From 66c733e55b26f85a746ef35be7f0162918a9d20d Mon Sep 17 00:00:00 2001 From: Dhawal Patel Date: Mon, 2 Nov 2020 09:54:45 -0800 Subject: [PATCH 001/542] Make port configurable --- cmd/kube-vip-start.go | 3 ++- cmd/kube-vip.go | 1 + pkg/cluster/clusterLeader.go | 6 ++---- pkg/kubevip/config_generator.go | 13 +++++++++++++ pkg/kubevip/config_types.go | 3 +++ 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 41e5d0a8..f75389b5 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -28,6 +28,7 @@ func init() { kubeVipStart.Flags().StringVar(&startConfig.Interface, "interface", "eth0", "Name of the interface to bind to") kubeVipStart.Flags().StringVar(&startConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address") kubeVipStart.Flags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") + kubeVipStart.Flags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") kubeVipStart.Flags().BoolVar(&startConfig.SingleNode, "singleNode", false, "Start this instance as a single node") kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") kubeVipStart.Flags().BoolVar(&startConfig.GratuitousARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") @@ -96,7 +97,7 @@ var kubeVipStart = &cobra.Command{ } if startConfig.EnableLeaderElection { - cm, err := cluster.NewManager(startKubeConfigPath, inCluster) + cm, err := cluster.NewManager(startKubeConfigPath, inCluster, startConfig.Port) if err != nil { log.Fatalf("%v", err) } diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 02f46644..2fe5bb3f 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -55,6 +55,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") + kubeVipCmd.PersistentFlags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.GratuitousARP, "arp", true, "Enable Arp for Vip changes") diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 9da41f7f..35f11ca6 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -36,7 +36,7 @@ type Manager struct { } // NewManager will create a new managing object -func NewManager(path string, inCluster bool) (*Manager, error) { +func NewManager(path string, inCluster bool, port int) (*Manager, error) { var clientset *kubernetes.Clientset if inCluster { // This will attempt to load the configuration when running within a POD @@ -65,9 +65,7 @@ func NewManager(path string, inCluster bool) (*Manager, error) { return nil, err } - // TODO - we need to make the host/port configurable - - config.Host = fmt.Sprintf("%s:6443", id) + config.Host = fmt.Sprintf("%s:%v", id, port) clientset, err = kubernetes.NewForConfig(config) if err != nil { diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 7a075286..5d511145 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -48,6 +48,9 @@ const ( // kube-vip will try to resolve it and use the IP as a VIP address = "address" + //port - defines the port for the VIP + port = "port" + //vipSingleNode - defines the vip start as a single node cluster vipSingleNode = "vip_singlenode" @@ -165,6 +168,16 @@ func ParseEnvironment(c *Config) error { c.Address = os.Getenv(address) } + // Find vip port + env = os.Getenv(port) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.Port = int(i) + } + // Find vip address cidr range env = os.Getenv(vipCidr) if env != "" { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 94324205..980052eb 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -30,6 +30,9 @@ type Config struct { // Address is the IP or DNS Name to use as a VirtualIP Address string `yaml:"address"` + // Listen port for the VirtualIP + Port int `yaml:"port"` + // GratuitousARP will broadcast an ARP update when the VIP changes host GratuitousARP bool `yaml:"gratuitousARP"` From 4c3714223a432825735c134001cc4d3935b2fdad Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 2 Nov 2020 20:19:16 +0000 Subject: [PATCH 002/542] Adds documents into repo --- docs/architecture/index.md | 140 ++++++ .../kubernetes-vip-architecture.png | Bin 0 -> 68679 bytes docs/control-plane/0.1.4/index.md | 147 ++++++ docs/control-plane/0.1.5/index.md | 195 ++++++++ docs/control-plane/index.md | 418 ++++++++++++++++++ docs/index/index.md | 23 + docs/index/kube-vip.png | Bin 0 -> 62135 bytes docs/kubernetes/index.md | 222 ++++++++++ docs/manifests/controller.yaml | 106 +++++ docs/manifests/controller_test.yaml | 107 +++++ docs/manifests/kube-vip.yaml | 83 ++++ 11 files changed, 1441 insertions(+) create mode 100644 docs/architecture/index.md create mode 100644 docs/architecture/kubernetes-vip-architecture.png create mode 100644 docs/control-plane/0.1.4/index.md create mode 100644 docs/control-plane/0.1.5/index.md create mode 100644 docs/control-plane/index.md create mode 100644 docs/index/index.md create mode 100644 docs/index/kube-vip.png create mode 100644 docs/kubernetes/index.md create mode 100644 docs/manifests/controller.yaml create mode 100644 docs/manifests/controller_test.yaml create mode 100644 docs/manifests/kube-vip.yaml diff --git a/docs/architecture/index.md b/docs/architecture/index.md new file mode 100644 index 00000000..94a4527c --- /dev/null +++ b/docs/architecture/index.md @@ -0,0 +1,140 @@ +# **kube-vip** architecture + +This section covers two parts of the architecture: + +1. The technical capabilities of `kube-vip` +2. The components to build a load-balancing service within [Kubernetes](https://kubernetes.io) + +The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expended to provide the same functionality for applications within a Kubernetes cluster. + +Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). + +## Technologies + +There are a number of technologies or functional design choices that provide high-availability or networking functions as part of a VIP/Load-balancing solution. + +### Cluster + +The `kube-vip` service builds a multi-node or multi-pod cluster to provide High-Availability. When a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster. + +When running **out of cluster** it will use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology + +When running **in cluster** it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) + +### Virtual IP + +The leader within the cluster will assume the **vip** and will have it bound to the selected interface that is declared within the configuration. When the leader changes it will evacuate the **vip** first or in failure scenarios the **vip** will be directly assumed by the next elected leader. + +When the **vip** moves from one host to another any host that has been using the **vip** will retain the previous `vip <-> MAC address` mapping until the ARP (Address resolution protocol) expires the old entry (typically 30 seconds) and retrieves a new `vip <-> MAC` mapping. This can be improved using Gratuitous ARP broadcasts (when enabled), this is detailed below. + +### ARP + +(Optional) The `kube-vip` can be configured to broadcast a [gratuitous arp](https://wiki.wireshark.org/Gratuitous_ARP) that will typically immediately notify all local hosts that the `vip <-> MAC` has changed. + +**Below** we can see that the failover is typically done within a few seconds as the ARP broadcast is recieved. + +``` +64 bytes from 192.168.0.75: icmp_seq=146 ttl=64 time=0.258 ms +64 bytes from 192.168.0.75: icmp_seq=147 ttl=64 time=0.240 ms +92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) +Vr HL TOS Len ID Flg off TTL Pro cks Src Dst + 4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 + +Request timeout for icmp_seq 148 +92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) +Vr HL TOS Len ID Flg off TTL Pro cks Src Dst + 4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 + +Request timeout for icmp_seq 149 +92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) +Vr HL TOS Len ID Flg off TTL Pro cks Src Dst + 4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 + +Request timeout for icmp_seq 150 +64 bytes from 192.168.0.75: icmp_seq=151 ttl=64 time=0.245 ms +``` + +### Load Balancing + +Within a Kubernetes cluster, the load-balancing is managed by the `plndr-cloud-provider` which watches all service that are created, and for those of `type: LoadBalancer` will create the configuration for `kube-vip` to consume. + +#### Load Balancing (Outside a cluster) + +Within the configuration of `kube-vip` multiple load-balancers can be created, below is the example load-balancer for a Kubernetes Control-plane: + +``` +loadBalancers: +- name: Kubernetes Control Plane + type: tcp + port: 6443 + bindToVip: true + backends: + - port: 6444 + address: 192.168.0.70 + - port: 6444 + address: 192.168.0.71 + - port: 6444 + address: 192.168.0.72 +``` + +The above load balancer will create an instance that listens on port `6443` and will forward traffic to the array of backend addresses. If the load-balancer type is `tcp` then the backends will be IP addresses, however if the backend is set to `http` then the backends should be URLs: + +``` + type: http + port: 6443 + bindToVip: true + backends: + - port: 6444 + address: https://192.168.0.70 +``` + +Additionally the load-balancing within `kibe-vip` has two modes of operation: + +`bindToVip: false` - will result in every node in the cluster binding all load-balancer port(s) to all interfaces on the host itself + +`bindToVip: true` - The load-balancer will only **bind** to the VIP address. + + +## Components within a Kubernetes Cluster + +The `kube-vip` kubernetes load-balancer requires a number of components in order to function: + +- The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) +- The Starboard Daemonset -> [https://github.com/plunder-app/starboard](https://github.com/plunder-app/starboard) +- The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) + +### Architecture overview + +![kubernetes-vip-architecture.png](kubernetes-vip-architecture.png) + +### Plunder Cloud Provider + +The cloud provider works like all Kubernetes cloud providers and is built using the Kubernetes cloud-provider SDK. It's role is to provide the same cloud "like" services one would expect from services such as AWS / Azure / GCP etc.. in that when a user requests functionality then the cloud provider can speak natively to the underlying vendor and provision the required service + +e.g. _In AWS when requesting a Kubernetes LoadBalancer, the cloud provider will provision an **ELB**_ + +The `Plunder cloud Provider` is *currently* only designed to intercept the creation of LoadBalancers and translate that into a `kube-vip` load balancer. + +It is configured by a `configMap` within the `kube-system` namespace that contains the ranges of addresses that the other `kube-vip` load-balancers can use, it will also manage the allocation of addresses and then build the configMap configurations in these namespaces for consumption by `kube-vip`. The IP addresses for each namespace should be in the structure `cidr-` followed by the cidr range for the address pool. + +**Example `ConfigMap`** + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: plndr + namespace: kube-system +data: + cidr-default: 192.168.0.200/29 + cidr-plunder: 192.168.0.210/29 + cidr-testing: 192.168.0.220/29 +``` + +### Starboard Daemonset + +The `starboard` pod is a simple service that implements a [client-go](https://github.com/kubernetes/client-go) [watch](https://github.com/plunder-app/starboard/blob/master/main.go#L72) on a Kubernetes `configMap` that contains the network range/cidr that load-balancer addresses will use. It then ensures that this cidr is present in the ipTables of all machines in the cluster, this will ensure that network traffic is directed to `kube-vip` to be load-balancer to the underlying application pods. + +### Kube-vip + + The `kube-vip` pod should exist in every namespace that requires load-balancing services, it also implements a "client-go watch" over a `configMap` in its current namespace. These configurations and created and managed by the cloud-provider, when `kube-vip` sees a change happen (i.e. a new service is defined) then it will implement the virtual IP and start the load-balancer. Furthermore `kube-vip` implements a second "watch" over the endpoints of the service and as that service changes (pods die, scaling etc..) so will the the endpoints that `kube-vip` will load-balancer over. diff --git a/docs/architecture/kubernetes-vip-architecture.png b/docs/architecture/kubernetes-vip-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..9d5a6f4c1919ccfab459ea3488cee41524d3dde4 GIT binary patch literal 68679 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 z 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

Behl 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%0A+>$O$F*H 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 Q8u;_%k-Sv?LtU@`2g6f+?EnA( literal 0 HcmV?d00001 diff --git a/docs/control-plane/0.1.4/index.md b/docs/control-plane/0.1.4/index.md new file mode 100644 index 00000000..e40ef6ec --- /dev/null +++ b/docs/control-plane/0.1.4/index.md @@ -0,0 +1,147 @@ +# Load Balancing a Kubernetes Cluster (Control-Plane) (pre 0.1.5) + +This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster + +`tl;dr version` +- Generate/modify first node `kube-vip` config/manifest +- `init` first node +- `join` remaining nodes +- Add remaining config/manifests + +## Infrastructure architecture + +The infrastructure for our example HA Kubernetes cluster is as follows: + +| Node | Address | +|----------------|------------| +| VIP | 10.0.0.75 | +| controlPlane01 | 10.0.0.70 | +| controlPlane02 | 10.0.0.71 | +| controlPlane03 | 10.0.0.72 | + +All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. + +### Generate the `kube-vip` configuration + +Make sure that the config directory exists: `sudo mkdir -p /etc/kube-vip/`, this directory can be any directory however the `hostPath` in the manifest will need modifying to point to the correct path. + +``` +sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample config | sudo tee /etc/kube-vip/config.yaml +``` + +### Modify the configuration + +**Cluster Configuration** +Modify the `remotePeers` to point to the correct addresses of the other two nodes, ensure that their `id` is unique otherwise this will confuse the raft algorithm. The `localPeer` should be the configuration of the current node (`controlPlane01`), which is where this instance of the cluster will run. + +As this node will be the first node, it will need to elect itself leader as until this occurs the VIP won’t be activated! + +`startAsLeader: true` + +**VIP Config** +We will need to set our VIP address to `192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `gratuitousARP: true` + +**Load Balancer** +We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. + +We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. + +**config.yaml** + +`user@controlPlane01:/etc/kube-vip$ cat config.yaml` + +... + +``` +remotePeers: +- id: server2 + address: 192.168.0.71 + port: 10000 +- id: server3 + address: 192.168.0.72 + port: 10000 +localPeer: + id: server1 + address: 192.168.0.70 + port: 10000 +vip: 192.168.0.75 +gratuitousARP: true +singleNode: false +startAsLeader: true +interface: ens192 +loadBalancers: +- name: Kubernetes Control Plane + type: tcp + port: 6443 + bindToVip: true + backends: + - port: 6444 + address: 192.168.0.70 + - port: 6444 + address: 192.168.0.71 + - port: 6444 + address: 192.168.0.72 +``` + +### First Node + +To generate the basic Kubernetes static pod `yaml` configuration: + +Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` + +``` +sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isn’t the above path. + +The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. + +`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` + +Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: + +``` +$ kubectl get pods -A +NAMESPACE NAME READY STATUS RESTARTS AGE +<...> +kube-system kube-vip-controlplane01 1/1 Running 0 10m +``` + +### Remaining Nodes + +We first will need to create the `kube-vip` configuration that resides in `/etc/kube-vip/config.yaml` or we can regenerate it from scratch using the above example. Ensure that the configuration is almost identical with the `localPeer` and `remotePeers` sections are updated for each node. Finally, ensure that the remaining nodes will behave as standard cluster nodes by setting `startAsLeader: false`. + +At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. + +``` + kubeadm join 192.168.0.75:6443 --token \ + --discovery-token-ca-cert-hash sha256: \ + --control-plane --certificate-key + +``` + +**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). + +``` +sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: + +``` +user@controlPlane01:~$ kubectl get pods -A | grep vip +kube-system kube-vip-controlplane01 1/1 Running 1 16m +kube-system kube-vip-controlplane02 1/1 Running 0 18m +kube-system kube-vip-controlplane03 1/1 Running 0 20m + +``` + +If we look at the logs, we can see that the VIP is running on the second node and we’re waiting for our third node to join the cluster: + +``` +$ kubectl logs kube-vip-controlplane02 -n kube-system +time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” +time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” + +``` \ No newline at end of file diff --git a/docs/control-plane/0.1.5/index.md b/docs/control-plane/0.1.5/index.md new file mode 100644 index 00000000..d22e3e4d --- /dev/null +++ b/docs/control-plane/0.1.5/index.md @@ -0,0 +1,195 @@ +# Load Balancing a Kubernetes Cluster (Control-Plane) + +This document covers the newer (post `0.1.5`) method for using `kube-vip` to provide HA for a Kubernetes Cluster. The documentation for older releases can be found [here](./0.1.4/) + +This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster + +`tl;dr version` +- Generate/modify first node `kube-vip` config/manifest +- `init` first node +- `join` remaining nodes +- Add remaining config/manifests + +Below are examples of the steps required: + +``` +# First Node +sudo docker run --network host --rm plndr/kube-vip:0.1.5 kubeadm init --interface ens192 --vip 192.168.0.81 --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml + +sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0.81 --upload-certs + +# Additional Node(s) + +sudo kubeadm join 192.168.0.81:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 + +sudo docker run -v /etc/kubernetes/admin.conf:/etc/kubernetes/admin.conf --network host --rm plndr/kube-vip:0.1.5 kubeadm join --interface ens192 --vip 192.168.0.81 --startAsLeader=false | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + + +## Infrastructure architecture + +The infrastructure for our example HA Kubernetes cluster is as follows: + +| Node | Address | +|----------------|------------| +| VIP | 10.0.0.75 | +| controlPlane01 | 10.0.0.70 | +| controlPlane02 | 10.0.0.71 | +| controlPlane03 | 10.0.0.72 | + +All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. + +### Generate the `kube-vip` configuration + +Kube-Vip no longer requires storing it's configuration in a seperate directory and will now store its configuration in the actual manifest that defines the static pods. + +``` +sudo docker run --network host \ + --rm plndr/kube-vip:0.1.5 \ + kubeadm init \ + --interface ens192 \ + --vip 192.168.0.75 \ + --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + +The above command will "initialise" the manifest within the `/etc/kubernetes/manifests` directory, that will be started when we actually initialise our Kubernetes cluster with `kubeadm init` + +### Modify the configuration + +**Cluster Configuration** +As this node will be the first node, it will need to elect itself leader as until this occurs the VIP won’t be activated! + +`--startAsLeader=true` + +**VIP Config** +We will need to set our VIP address to `192.168.0.75` with `--vip 192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `--arp` (defaults to `true`) + +**Load Balancer** +We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. + +We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. + +**vip.yaml** Static-pod Manifest + +`$ sudo cat /etc/kubernetes/manifests/vip.yaml` + + +``` +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - start + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: ens192 + - name: vip_address + value: 192.168.0.81 + - name: vip_startleader + value: "true" + - name: vip_addpeerstolb + value: "true" + - name: vip_localpeer + value: controlPlane01:192.168.0.70:10000 + - name: lb_backendport + value: "6443" + - name: lb_name + value: Kubeadm Load Balancer + - name: lb_type + value: tcp + - name: lb_bindtovip + value: "true" + image: plndr/kube-vip:0.1.5 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + hostNetwork: true +status: {} +``` + +### First Node + +To generate the basic Kubernetes static pod `yaml` configuration: + +Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` + +``` +sudo docker run --network host \ + --rm plndr/kube-vip:0.1.5 \ + kubeadm init \ + --interface ens192 \ + --vip 192.168.0.75 \ + --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + +Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1.5` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. + +The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. + +`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` + +Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: + +``` +$ kubectl get pods -A +NAMESPACE NAME READY STATUS RESTARTS AGE +<...> +kube-system kube-vip-controlplane01 1/1 Running 0 10m +``` + +### Remaining Nodes + + +At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. + +``` + kubeadm join 192.168.0.75:6443 --token \ + --discovery-token-ca-cert-hash sha256: \ + --control-plane --certificate-key + +``` + +**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). + +``` +sudo docker run \ + -v /etc/kubernetes/admin.conf:/etc/kubernetes/admin.conf \ + --network host \ + --rm plndr/kube-vip:0.1.5 \ + kubeadm join \ + --interface ens192 \ + --vip 192.168.0.81 \ + --startAsLeader=false | sudo tee /etc/kubernetes/manifests/vip.yaml + +``` + +Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: + +``` +user@controlPlane01:~$ kubectl get pods -A | grep vip +kube-system kube-vip-controlplane01 1/1 Running 1 16m +kube-system kube-vip-controlplane02 1/1 Running 0 18m +kube-system kube-vip-controlplane03 1/1 Running 0 20m + +``` + +If we look at the logs, we can see that the VIP is running on the second node and we’re waiting for our third node to join the cluster: + +``` +$ kubectl logs kube-vip-controlplane02 -n kube-system +time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” +time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” + +``` \ No newline at end of file diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md new file mode 100644 index 00000000..1ffa3ab9 --- /dev/null +++ b/docs/control-plane/index.md @@ -0,0 +1,418 @@ +# Load Balancing a Kubernetes Cluster (Control-Plane) + +**Note**: The most common deployment currently for HA Kubernetes clusters w/`kub-vip` involved `kubeadm`, however recently we've worked to bring a method of bringing `kube-vip` to other types of Kubernetes cluster. Typically this deployment method makes use of a daemonset that is usually brought up during the cluster instantiation.. So for those wanting to deploy [k3s](https://k3s.io), we now have installation steps available [here](https://kube-vip.io/control-plane/#k3s), + +This document covers the newer (post `0.1.6`) method for using `kube-vip` to provide HA for a Kubernetes Cluster. The documentation for older releases can be found [here](./0.1.5/) + +From version `0.1.6` we've moved `kube-vip` from raft to leaderElection within the Kubernetes cluster. After a lot of testing it became clear that the leaderElection gave quicker reconciliation when removing nodes etc.. during upgrades and failures. + +For **more** configuration around LeaderElection click [here](https://kube-vip.io/control-plane/#leaderelection-configuration). + +This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster + +`tl;dr version` +- Generate/modify first node `kube-vip` config/manifest +- `init` first node +- `join` remaining nodes +- Add remaining config/manifests + +Below are examples of the steps required: + +``` +# First Node +sudo docker run --network host --rm plndr/kube-vip:0.1.8 kubeadm init \ +--interface ens192 \ +--vip 192.168.0.75 \ +--arp \ +--leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml + +sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0.75 --upload-certs + +# Additional Node(s) + +sudo kubeadm join 192.168.0.75:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 + +sudo docker run --network host --rm plndr/kube-vip:0.1.8 kubeadm init \ +--interface ens192 \ +--vip 192.168.0.75 \ +--arp \ +--leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + + +## Infrastructure architecture + +The infrastructure for our example HA Kubernetes cluster is as follows: + +| Node | Address | +|----------------|------------| +| VIP | 10.0.0.75 | +| controlPlane01 | 10.0.0.70 | +| controlPlane02 | 10.0.0.71 | +| controlPlane03 | 10.0.0.72 | + +All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. + +### Generate the `kube-vip` configuration + +`kube-vip` no longer requires storing its configuration in a separate directory and will now store its configuration in the actual manifest that defines the static pods. + +``` +sudo docker run --network host \ + --rm plndr/kube-vip:0.1.8 \ + kubeadm init \ + --interface ens192 \ + --vip 192.168.0.75 \ + --arp \ + --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + +The above command will "initialise" the manifest within the `/etc/kubernetes/manifests` directory, that will be started when we actually initialise our Kubernetes cluster with `kubeadm init` + +### Modify the configuration + +**Cluster Configuration** +To enable Kubernetes leader Election passing the `--leaderElection` flag will enable `kube-vip` to use the Kubernetes leaderElection functionality to work out which member is the leader. + +**VIP Config** +We will need to set our VIP address to `192.168.0.75` with `--vip 192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `--arp` (defaults to `true`) + +**Load Balancer** +We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. + +We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. + +**vip.yaml** Static-pod Manifest + +`$ sudo cat /etc/kubernetes/manifests/vip.yaml` + + +``` +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - start + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: ens192 + - name: vip_address + value: 192.168.0.81 + - name: vip_startleader + value: "true" + - name: vip_addpeerstolb + value: "true" + - name: vip_localpeer + value: controlPlane01:192.168.0.70:10000 + - name: lb_backendport + value: "6443" + - name: lb_name + value: Kubeadm Load Balancer + - name: lb_type + value: tcp + - name: lb_bindtovip + value: "true" + image: plndr/kube-vip:0.1.8 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + hostNetwork: true +status: {} +``` + +### First Node + +To generate the basic Kubernetes static pod `yaml` configuration: + +Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` + +``` +sudo docker run --network host \ + --rm plndr/kube-vip:0.1.8 \ + kubeadm init \ + --interface ens192 \ + --vip 192.168.0.75 \ + --arp \ + --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + +Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1.8` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. + +The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. + +`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` + +Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: + +``` +$ kubectl get pods -A +NAMESPACE NAME READY STATUS RESTARTS AGE +<...> +kube-system kube-vip-controlplane01 1/1 Running 0 10m +``` + +### Remaining Nodes + + +At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. + +``` + kubeadm join 192.168.0.75:6443 --token \ + --discovery-token-ca-cert-hash sha256: \ + --control-plane --certificate-key + +``` + +**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). + +``` +sudo docker run --network host \ + --rm plndr/kube-vip:0.1.8 \ + kubeadm init \ + --interface ens192 \ + --vip 192.168.0.75 \ + --arp \ + --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml + +``` + +Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: + +``` +user@controlPlane01:~$ kubectl get pods -A | grep vip +kube-system kube-vip-controlplane01 1/1 Running 1 16m +kube-system kube-vip-controlplane02 1/1 Running 0 18m +kube-system kube-vip-controlplane03 1/1 Running 0 20m + +``` + +## BGP Support (added in 0.1.8) + +In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. + +The following new flags are used: + +- `--bgp` This will enable BGP support within kube-vip +- `--localAS` The local AS number +- `--bgpRouterID` The local router address +- `--peerAS` The AS number for a BGP peer +- `--peerAddress` The address of a BGP peer + +### BGP Packet support + +If the `--bgp` flag is passed alone with the Packet flags `packet, packetKey and packetProject`, then the Packet API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Packet much simpler. + +## Packet Support (added in 0.1.7) + +Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Packet Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Packet account and create a EIP (either public (eek) or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Packet project we can now apply this address to the servers that live in the same project. + +In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. + +The following new flags are used: + +- `--packet` which enables the use of the Packet API +- `--packetKey` which is our API key +- `--packetProject`which is the name of our Packet project where our servers and EIP are located. + +*Also* the `--arp` flag should NOT be used as it wont work within the Packet network. + +### Variables + +``` +export EIP=1.1.1.1 +export PACKET_AUTH_TOKEN=XYZ +``` + +### First node + +``` +# Generate the manifest + +sudo docker run --network host --rm plndr/kube-vip:0.1.7 kubeadm init \ +--arp=false \ +--interface lo \ +--vip $EIP \ +--leaderElection \ +--packet \ +--packetKey $PACKET_AUTH_TOKEN \ +--packetProject vipTest | sudo tee /etc/kubernetes/manifests/vip.yaml\ + +# Init Kubernetes + +sudo kubeadm init --kubernetes-version 1.18.5 --control-plane-endpoint $EIP --upload-certs +``` + +### Other nodes + +``` +# Join +kubeadm join $EIP:6443 --token BLAH --control-plane --certificate-key BLAH --discovery-token-ca-cert-hash sha:blah + +# Generate Manifest + +sudo docker run --network host --rm plndr/kube-vip:0.1.7 kubeadm init \ +--arp=false \ +--interface lo \ +--vip $EIP \ +--leaderElection \ +--packet \ +--packetKey $PACKET_AUTH_TOKEN \ +--packetProject vipTest | sudo tee /etc/kubernetes/manifests/vip.yaml\ +``` + +The Elastic IP failover takes some time (30+ seconds) to move from a failed host to a new leader, so in this release it is mainly for testing. + + +## Upgrades + +From above we have a 3 node cluster and the controlPlane01 is leader: + +``` +$ kubectl logs -n kube-system kube-vip-controlplane01 -f +time="2020-07-04T15:12:52Z" level=info msg="Beginning cluster membership, namespace [kube-system], lock name [plunder-lock], id [controlPlane01]" +I0704 15:12:52.290420 1 leaderelection.go:242] attempting to acquire leader lease kube-system/plunder-lock... +I0704 15:12:56.373113 1 leaderelection.go:252] successfully acquired lease kube-system/plunder-lock +time="2020-07-04T15:12:56Z" level=info msg="This node is assuming leadership of the cluster" +time="2020-07-04T15:12:56Z" level=error msg="This node is leader and is adopting the virtual IP" +time="2020-07-04T15:12:56Z" level=info msg="Starting TCP Load Balancer for service [192.168.0.81:0]" +time="2020-07-04T15:12:56Z" level=info msg="Load Balancer [Kubeadm Load Balancer] started" +time="2020-07-04T15:12:56Z" level=info msg="Broadcasting ARP update for 192.168.0.81 (00:50:56:a5:69:a1) via ens192" +time="2020-07-04T15:12:56Z" level=info msg="Starting TCP Load Balancer for service [192.168.0.81:0]" +time="2020-07-04T15:12:56Z" level=info msg="Load Balancer [Kubeadm Load Balancer] started" +time="2020-07-04T15:12:56Z" level=info msg="Broadcasting ARP update for 192.168.0.81 (00:50:56:a5:69:a1) via ens192" +time="2020-07-04T15:12:56Z" level=info msg="new leader elected: controlPlane01" +``` + +We will kill this node and watch `kube-vip` logs from another node: + +#### Pinging VIP + +``` +64 bytes from 192.168.0.81: icmp_seq=667 ttl=64 time=0.387 ms +Request timeout for icmp_seq 668 +Request timeout for icmp_seq 669 +Request timeout for icmp_seq 670 +Request timeout for icmp_seq 671 +Request timeout for icmp_seq 672 +64 bytes from 192.168.0.81: icmp_seq=673 ttl=64 time=0.453 ms +``` + +#### Logs +``` +$ kubectl logs -n kube-system kube-vip-controlplane03 -f +time="2020-07-04T15:17:53Z" level=info msg="Beginning cluster membership, namespace [kube-system], lock name [plunder-lock], id [controlPlane03]" +I0704 15:17:53.484698 1 leaderelection.go:242] attempting to acquire leader lease kube-system/plunder-lock... +time="2020-07-04T15:17:53Z" level=info msg="new leader elected: controlPlane01" +E0704 15:20:18.864141 1 leaderelection.go:331] error retrieving resource lock kube-system/plunder-lock: etcdserver: request timed out +time="2020-07-04T15:20:20Z" level=info msg="new leader elected: controlPlane02" +``` + +#### Adding `controlPlane04` + +A kubeadm join will fail as the `controlPlane01` still exists as an endpoint, so we have two options (manual steps and configmap edit to remove all mention of this node, or we can bring this node up and `kubeadm reset` the node (which we will do)). + +``` +$ kubectl get nodes +NAME STATUS ROLES AGE VERSION +controlplane01 NotReady master 14m v1.17.0 +controlplane02 Ready master 13m v1.17.2 +controlplane03 Ready master 13m v1.17.0 +controlplane04 NotReady master 9s v1.17.0 +``` + After this we can add this node into `kube-vip` with the same manifest created by `docker run`. + +## LeaderElection configuration + +The Kubernetes LeaderElection that is used to manage the election of a new leader now supports having it's settings managed through flags. + + - `--leaseDuration` Length of time a Kubernetes leader lease can be held for + - `--leaseRenewDuration` Length of time a Kubernetes leader can attempt to renew its lease + - `--leaseRetry` Number of times the host will retry to hold a lease + +For larger clusters the `--leaseDuration` and `--leaseRenewDuration` may need extending due to slower `etcd` performance. (Tested with 2000 nodes) + +## k3s + +This section details the steps required to deploye `k3s` in a Highly available manner, using kube-vip deployed within k3s as a daemonset on the control plane nodes. As of `k3s` v1 the persistent datastore is back to etcd, however this guide will also include the steps for using `mysql`. + +### Example MySQL deployment (optional) + +To quickly validate this we can use docker on a host to quickly spin up a mysql database to store the persistent Kubernetes data. + +#### Create local directory for BD storage +`mkdir mysql` + +#### Start Docker MySQL container +`sudo docker run --cap-add SYS_NICE -p 3306:3306 --name k3s-mysql -v /home/dan/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=k3s-password -d mysql:8` + +### Create `kube-vip` manifest + +The `kube-vip` manifest contains all the configuration for starting up `kube-vip` within the `k3s` cluster, it runs as a daemonset with affinity/taints for the control-plane nodes. As `k3s` starts it will parse all manifests in the manifests folder and start the highly available VIP across all control plane nodes in the cluster. + +#### Create the `k3` manifests directory + +Create the manifests directory, this directory is used by `k3s` for all of it's other deployments once it's up and running. +`sudo mkdir -p /var/lib/rancher/k3s/server/manifests/` + +#### Generate the manifest + +Modify the `vipAddress` and `vipInterface` to match the floating IP address you'd like to use and the interface it should bind to. + +`curl -sL kube-vip.io/k3s | vipAddress=192.168.0.10 vipInterface=ens192 sh | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml` + +### Start `k3s` + +Set the VIP **first** + +`export VIP=192.168.0.10` + + +From online `-->` + +``` +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ +-t agent-secret --tls-san $VIP" sh - +``` + +From local `-->` + +``` +sudo ./k3s server --tls-san $VIP +``` + +#### With MySQL + +From online `-->` + +``` +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ +--datastore-endpoint mysql://root:k3s-password@tcp(192.168.0.43:3306)/kubernetes \ +-t agent-secret --tls-san $VIP" sh - +``` + +From local `-->` + +``` +sudo ./k3s server --tls-san $VIP \ +--datastore-endpoint="mysql://root:k3s-password@tcp(192.168.0.43:3306)/kubernetes" +``` + +### Get a `kubeconfig` that uses the vip + +```` +mkdir -p $HOME/.kube +sudo cat /etc/rancher/k3s/k3s.yaml | sed 's/127.0.0.1/'$VIP'/g' > $HOME/.kube/config +sudo chown $(id -u):$(id -g) $HOME/.kube/config +``` \ No newline at end of file diff --git a/docs/index/index.md b/docs/index/index.md new file mode 100644 index 00000000..045e0099 --- /dev/null +++ b/docs/index/index.md @@ -0,0 +1,23 @@ +# Kube-vip + +A Load-Balancer for both **inside** and **outside** a Kubernetes cluster + +![kube-vip.png](kube-vip.png) + +## Architecture + +The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) + +## Control-plane load balancer + +The details are [here](/control-plane/) + +## Kubernetes service `"type: LoadBalancer"` + +The details are [here](/kubernetes/) + +## GitHub Repositories + +- The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) +- The Starboard Daemonset -> [https://github.com/plunder-app/starboard](https://github.com/plunder-app/starboard) +- The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) \ No newline at end of file diff --git a/docs/index/kube-vip.png b/docs/index/kube-vip.png new file mode 100644 index 0000000000000000000000000000000000000000..d6384f251aecdf0c8b35cb53f9a4c6d0af181e6d GIT binary patch literal 62135 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, then ensure that `kube-vip` is deployed into that namespace with the above `apply` command with the `-n namespace` flag. + +## Deploying `kube-vip` in a Kubernetes cluster (in detail) + +### Deploy the `plndr-cloud-provider` + +From the GitHub repository [https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod](https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: + +``` +serviceaccount/plunder-cloud-controller created +clusterrole.rbac.authorization.k8s.io/system:plunder-cloud-controller-role created +clusterrolebinding.rbac.authorization.k8s.io/system:plunder-cloud-controller-binding created +pod/plndr-cloud-provider created +``` + +We can validate the cloud-provider by examining the pods: + +`kubectl logs -n kube-system plndr-cloud-provider -f` + +#### The `plndr-cloud-provider` `configmap` + +To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within the `configmap` should be that the key is in the format `cidr-` and teh value should be the cidr range. + +Example Configmap: + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: plndr + namespace: kube-system +data: + cidr-default: 192.168.0.200/29 + cidr-plunder: 192.168.0.210/29 +``` + +### Deploy `starboard` + +This requires no customisation as it simply monitors the `configMap` managed by the plndr-cloud-provider. + +From the GitHub repository [https://github.com/plunder-app/starboard/tree/master/examples/daemonset](https://github.com/plunder-app/starboard/tree/master/examples/daemonset) find the version of the starboard to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: +``` +serviceaccount/starboard created +role.rbac.authorization.k8s.io/starboard-role created +rolebinding.rbac.authorization.k8s.io/starboard-role-bind created +daemonset.apps/starboard-ds created +``` + +### Deploy `kube-vip` + +From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the kube-vip to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: +``` +serviceaccount/vip created +role.rbac.authorization.k8s.io/vip-role created +rolebinding.rbac.authorization.k8s.io/vip-role-bind created +deployment.apps/kube-vip-cluster created +``` + +*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. + +#### Editing `kube-vip` configuration + +Either download and edit the manifest locally or appy as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) + +``` + - name: vip_interface + value: ens192 + - name: vip_configmap + value: plndr + - name: vip_arp + value: "true" + - name: vip_loglevel + value: "5" +``` + +- `vip_interface` - defines the interface that the VIP will bind to +- `vip_configmap` - defines the configmap that `kube-vip` will watch for service configuration +- `vip_arp` - determines if ARP broadcasts are enabled +- `vip_loglevel` - determines the verbosity of logging + +## Testing + +This testing is performed on a brand new three node (`1.17.0`, 1 **Master**, 2 **Worker**) cluster, running Calico as the CNI plugin. + +#### Deploy NGINX + +``` +kubectl apply -f https://k8s.io/examples/application/deployment.yaml +``` + +#### Create Load-Balancer + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-loadbalancer +``` + +#### View Load-Balancer + +``` +$ k describe service nginx-loadbalancer +Name: nginx-loadbalancer +Namespace: default +Labels: +Annotations: +Selector: app=nginx +Type: LoadBalancer +IP: 10.96.184.221 +LoadBalancer Ingress: 192.168.0.81 +Port: 80/TCP +TargetPort: 80/TCP +NodePort: 31138/TCP +Endpoints: 172.16.198.194:80,172.16.232.2:80 +Session Affinity: None +External Traffic Policy: Cluster +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal EnsuringLoadBalancer 30s service-controller Ensuring load balancer + Normal EnsuredLoadBalancer 29s service-controller Ensured load balancer +``` + +Any host with on the same network or has the correct routes configured should now be able to use the load-balancer address displayed in the configuration: `LoadBalancer Ingress: 192.168.0.81` + +## Using other namespaces + +In this example we'll deploy and load-balance within the namespace `plunder` + +### Create the namespace + +`kubectl create namespace plunder` + +### Add a network range/cidr for this namespace + +`kubectl edit -n kube-system configmap/plndr` + +We will add the range 192.168.0.210/29 for the namespace plunder underneath the existing range for the namespace default: + +``` +apiVersion: v1 +data: + cidr-default: 192.168.0.200/29 + cidr-plunder: 192.168.0.210/29 +<...> +``` + +### Deploy `kube-vip` in the namespace **plunder** + +In the same way we deployed `kube-vip` into the default namespace we can deploy the same manifest into a different namespace using `-n namespace` e.g. + +**Note** change the version of manifest when actually deploying! + +``` +kubectl apply -f https://github.com/plunder-app/kube-vip/raw/master/example/deploy/0.1.3.yaml -n plunder +``` + +### Deploy nginx + +``` +kubectl create deployment --image nginx plunder-nginx --namespace plunder +``` + +### Create a load balancer + +``` +kubectl expose deployment plunder-nginx --port=80 --type=LoadBalancer --namespace plunder +``` + +## Troubleshooting + +Typically the logs from the `kube-vip` controller will reveal the most clues as to where a problem may lie. + +The `ClusterRoleBinding` is missing will result in the following: + +``` +E0229 17:36:38.014351 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) +E0229 17:36:38.014352 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) +``` + +If Load-balancing isn't working as expected, then examine the `iptables` on the node running `kube-vip`: + +``` +sudo iptables -L -n -t nat | more +Chain PREROUTING (policy ACCEPT) +target prot opt source destination +cali-PREROUTING all -- 0.0.0.0/0 0.0.0.0/0 /* cali:6gwbT8clXdHdC1b1 */ +ACCEPT all -- 0.0.0.0/0 192.168.0.80/29 +KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */ +DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL +``` + +Ensure that the `cidr` is present in the PREROUTING table, if this is missing ensure that the starboard daemonset is running. diff --git a/docs/manifests/controller.yaml b/docs/manifests/controller.yaml new file mode 100644 index 00000000..425e17db --- /dev/null +++ b/docs/manifests/controller.yaml @@ -0,0 +1,106 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: starboard + namespace: kube-system +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: starboard-role + namespace: kube-system +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["watch","get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: starboard-role-bind + namespace: kube-system +subjects: + - kind: ServiceAccount + name: starboard + apiGroup: "" +roleRef: + kind: Role + name: starboard-role + apiGroup: "" +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: starboard-ds + namespace: kube-system + labels: +spec: + selector: + matchLabels: + name: starboard-ds + template: + metadata: + labels: + name: starboard-ds + spec: + hostNetwork: true + serviceAccountName: starboard + containers: + - name: starboard-ds + image: plndr/starboard:0.1.1 + imagePullPolicy: Always + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: plunder-cloud-controller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:plunder-cloud-controller-role +rules: + - apiGroups: [""] + resources: ["configmaps", "endpoints","events","services/status"] + verbs: ["*"] + - apiGroups: [""] + resources: ["nodes", "services"] + verbs: ["list","get","watch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:plunder-cloud-controller-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:plunder-cloud-controller-role +subjects: +- kind: ServiceAccount + name: plunder-cloud-controller + namespace: kube-system +--- +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: plndr-cloud-provider + namespace: kube-system +spec: + containers: + - command: + - /plndr-cloud-provider + image: plndr/plndr-cloud-provider:0.1.3 + name: plndr-cloud-provider + imagePullPolicy: Always + resources: {} + serviceAccountName: plunder-cloud-controller diff --git a/docs/manifests/controller_test.yaml b/docs/manifests/controller_test.yaml new file mode 100644 index 00000000..c2349430 --- /dev/null +++ b/docs/manifests/controller_test.yaml @@ -0,0 +1,107 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: starboard + namespace: kube-system +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: starboard-role + namespace: kube-system +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["watch","get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: starboard-role-bind + namespace: kube-system +subjects: + - kind: ServiceAccount + name: starboard + apiGroup: "" +roleRef: + kind: Role + name: starboard-role + apiGroup: "" +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: starboard-ds + namespace: kube-system + labels: +spec: + selector: + matchLabels: + name: starboard-ds + template: + metadata: + labels: + name: starboard-ds + spec: + hostNetwork: true + serviceAccountName: starboard + containers: + - name: starboard-ds + image: plndr/starboard:0.1.1 + imagePullPolicy: Always + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: plunder-cloud-controller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:plunder-cloud-controller-role +rules: + - apiGroups: [""] + resources: ["configmaps", "endpoints","events","services/status"] + verbs: ["*"] + - apiGroups: [""] + resources: ["nodes", "services"] + verbs: ["list","get","watch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:plunder-cloud-controller-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:plunder-cloud-controller-role +subjects: +- kind: ServiceAccount + name: plunder-cloud-controller + namespace: kube-system +--- +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: plndr-cloud-provider + namespace: kube-system +spec: + containers: + - command: + - /plndr-cloud-provider + - --leader-elect-resource-name plndr-cloud-controller + image: plndr/plndr-cloud-provider:0.1.3 + name: plndr-cloud-provider + imagePullPolicy: Always + resources: {} + serviceAccountName: plunder-cloud-controller diff --git a/docs/manifests/kube-vip.yaml b/docs/manifests/kube-vip.yaml new file mode 100644 index 00000000..a693e6a1 --- /dev/null +++ b/docs/manifests/kube-vip.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: vip +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: vip-role +rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update", "list", "put"] + - apiGroups: [""] + resources: ["configmaps", "endpoints"] + verbs: ["watch", "get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: vip-role-bind +subjects: + - kind: ServiceAccount + name: vip + apiGroup: "" +roleRef: + kind: Role + name: vip-role + apiGroup: "" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: kube-vip-cluster + name: kube-vip-cluster +spec: + replicas: 3 + selector: + matchLabels: + app: kube-vip-cluster + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: kube-vip-cluster + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - kube-vip-cluster + topologyKey: "kubernetes.io/hostname" + containers: + - image: plndr/kube-vip:0.1.3 + imagePullPolicy: Always + name: kube-vip + command: + - /kube-vip + - service + env: + - name: vip_interface + value: "ens192" + - name: vip_configmap + value: "plndr" + - name: vip_arp + value: "true" + - name: vip_loglevel + value: "5" + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + hostNetwork: true + serviceAccountName: vip +status: {} \ No newline at end of file From ef7ace04001a9789d07103b21b97ccfb1b10d94d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 4 Nov 2020 12:23:19 +0000 Subject: [PATCH 003/542] Fixes to int parsing I've no clue why the incorrect int parsing ended up in the code. --- pkg/kubevip/config_generator.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 5d511145..67f7fdfa 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -134,7 +134,7 @@ func ParseEnvironment(c *Config) error { // Attempt to find the Lease configuration from teh environment variables env = os.Getenv(vipLeaseDuration) if env != "" { - i, err := strconv.ParseInt(env, 8, 0) + i, err := strconv.ParseInt(env, 10, 32) if err != nil { return err } @@ -143,7 +143,7 @@ func ParseEnvironment(c *Config) error { env = os.Getenv(vipRenewDeadline) if env != "" { - i, err := strconv.ParseInt(env, 8, 0) + i, err := strconv.ParseInt(env, 10, 32) if err != nil { return err } @@ -152,7 +152,7 @@ func ParseEnvironment(c *Config) error { env = os.Getenv(vipRetryPeriod) if env != "" { - i, err := strconv.ParseInt(env, 8, 0) + i, err := strconv.ParseInt(env, 10, 32) if err != nil { return err } @@ -341,7 +341,7 @@ func parseEnvironmentLoadBalancer(c *Config) error { // Find LoadBalancer Port env := os.Getenv(lbPort) if env != "" { - i, err := strconv.ParseInt(env, 8, 0) + i, err := strconv.ParseInt(env, 10, 32) if err != nil { return err } @@ -373,7 +373,7 @@ func parseEnvironmentLoadBalancer(c *Config) error { // Find global backendport env = os.Getenv(lbBackendPort) if env != "" { - i, err := strconv.ParseInt(env, 8, 0) + i, err := strconv.ParseInt(env, 10, 32) if err != nil { return err } From 8c443397579478114ee59c3885c12636d2e11a44 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 5 Nov 2020 13:30:34 +0000 Subject: [PATCH 004/542] This adds upnp functionality to kube-vip With upnp functionality enabled any loadbalancer will be exposed through a upnp gateway! --- Makefile | 6 +++++- go.mod | 1 + go.sum | 2 ++ pkg/service/manager.go | 28 ++++++++++++++++++++++++---- pkg/service/services.go | 22 ++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 79cda47f..10569e18 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.2.0 +VERSION := 0.2.1 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) @@ -54,10 +54,12 @@ demo: # This build a local docker image (x86 only) for quick testing dockerx86: + @rm ./kube-vip @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New single x86 Architecture Docker image created docker: + @rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created @@ -65,10 +67,12 @@ docker: # This will build a local docker image (x86 only), use make dockerLocal for all architectures dockerx86Local: + @rm ./kube-vip @docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created dockerLocal: + @rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created diff --git a/go.mod b/go.mod index ec9e3421..b33cbd24 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/hashicorp/raft v1.1.2 github.com/imdario/mergo v0.3.11 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect + github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef github.com/magiconair/properties v1.8.3 // indirect github.com/mattn/go-colorable v0.1.7 // indirect github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect diff --git a/go.sum b/go.sum index a30c30cc..29ec6784 100644 --- a/go.sum +++ b/go.sum @@ -305,6 +305,8 @@ github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131 h1:2bjzgZk4GiWA github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= +github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef h1:hYYYR5sSbR211XTKlIERN7I7xYU1D47eft2ooDg0Dtg= +github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= diff --git a/pkg/service/manager.go b/pkg/service/manager.go index d9563672..783e3271 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -8,11 +8,14 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "syscall" "time" "github.com/davecgh/go-spew/spew" + "github.com/kamhlos/upnp" + dhclient "github.com/digineo/go-dhclient" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" @@ -20,15 +23,14 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/leaderelection/resourcelock" - watchtools "k8s.io/client-go/tools/watch" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/leaderelection" + "k8s.io/client-go/tools/leaderelection/resourcelock" + watchtools "k8s.io/client-go/tools/watch" ) const plunderLock = "plunder-lock" @@ -80,6 +82,9 @@ type Manager struct { configMap string // Keeps track of all running instances serviceInstances []serviceInstance + + // Additional functionality + upnp *upnp.Upnp } // NewManager will create a new managing object @@ -170,6 +175,21 @@ func (sm *Manager) Start() error { cancel() }() + // Before starting the leader Election enable any additional functionality + upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) + + if upnpEnabled { + sm.upnp = new(upnp.Upnp) + err := sm.upnp.ExternalIPAddr() + if err != nil { + log.Errorf("Error Enabling UPNP %s", err.Error()) + // Set the struct to nil so nothing should use it in future + sm.upnp = nil + } else { + log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + } + } + // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, diff --git a/pkg/service/services.go b/pkg/service/services.go index 5e8f193f..363cc248 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "strings" dhclient "github.com/digineo/go-dhclient" "github.com/plunder-app/kube-vip/pkg/cluster" @@ -176,6 +177,9 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) return } + + sm.upnpMap(s.Services[x]) + }, } @@ -222,6 +226,9 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) return err } + + sm.upnpMap(s.Services[x]) + newService.cluster = *c // Begin watching endpoints for this service @@ -235,3 +242,18 @@ func (sm *Manager) syncServices(s *plndrServices) error { return nil } + +func (sm *Manager) upnpMap(s service) { + // If upnp is enabled then update the gateway/router with the address + // TODO - work out if we need to mapping.Reclaim() + if sm.upnp != nil { + + log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) + if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + log.Infof("Service should be accessible externally on port [%d]", s.Port) + } else { + sm.upnp.Reclaim() + log.Errorf("Unable to map port to gateway [%s]", err.Error()) + } + } +} From 0eda56a44a2998a2fd84a8164ee86168196815cb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 6 Nov 2020 10:00:07 +0000 Subject: [PATCH 005/542] Testing of new service --- Makefile | 2 +- pkg/cluster/singleNode.go | 45 +++++++++++++++++++++++++++++++++++++++ pkg/service/services.go | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 79cda47f..193c043c 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.2.0 +VERSION := 0.2.1 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index e24328e4..f44eb98c 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -101,3 +101,48 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro log.Infoln("Started Load Balancer and Virtual IP") return nil } + +// StartLoadBalancerService will start a VIP/LoadBalancer instance +func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, disableVIP bool) error { + // Start a kube-vip loadbalancer service + log.Infoln("Starting kube-vip as a LoadBalancer Service") + + cluster.stop = make(chan bool, 1) + cluster.completed = make(chan bool, 1) + + err := cluster.Network.DeleteIP() + if err != nil { + log.Warnf("Attempted to clean existing VIP => %v", err) + } + + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + + if c.GratuitousARP == true { + // Gratuitous ARP, will broadcast to new MAC <-> IP + err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) + if err != nil { + log.Warnf("%v", err) + } + } + + go func() { + for { + select { + case <-cluster.stop: + log.Info("[LOADBALANCER] Stopping load balancers") + log.Info("[VIP] Releasing the Virtual IP") + err = cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) + } + close(cluster.completed) + return + } + } + }() + log.Infoln("Started Load Balancer and Virtual IP") + return nil +} diff --git a/pkg/service/services.go b/pkg/service/services.go index 5e8f193f..626065ef 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -217,7 +217,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) return err } - err = c.StartSingleNode(&newService.vipConfig, false) + err = c.StartLoadBalancerService(&newService.vipConfig, false) if err != nil { log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) return err From ca7a08bad189edc47ccee0e2e36ed07dcb389b44 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 6 Nov 2020 16:02:57 +0000 Subject: [PATCH 006/542] Fixes to DHCP --- pkg/cluster/singleNode.go | 2 +- pkg/service/services.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index f44eb98c..2937d325 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -102,7 +102,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro return nil } -// StartLoadBalancerService will start a VIP/LoadBalancer instance +// StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, disableVIP bool) error { // Start a kube-vip loadbalancer service log.Infoln("Starting kube-vip as a LoadBalancer Service") diff --git a/pkg/service/services.go b/pkg/service/services.go index 626065ef..9dc48fbf 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -143,7 +143,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) //return err } - err = c.StartSingleNode(&newService.vipConfig, false) + err = c.StartLoadBalancerService(&newService.vipConfig, false) if err != nil { log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) //return err From 29c570eeb48b8e604a6edeeaa00bed3477734ba8 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sun, 8 Nov 2020 16:27:30 +0000 Subject: [PATCH 007/542] This PR begins the work of enabled BGP loadbalancing within a Kubernets cluster --- cmd/kube-vip.go | 63 ++++----- go.mod | 3 +- go.sum | 10 +- pkg/cluster/singleNode.go | 16 ++- pkg/kubevip/config_types.go | 3 + pkg/service/manager.go | 260 ++++++++++++------------------------ pkg/service/manager_arp.go | 123 +++++++++++++++++ pkg/service/manager_bgp.go | 82 ++++++++++++ pkg/service/services.go | 12 +- 9 files changed, 354 insertions(+), 218 deletions(-) create mode 100644 pkg/service/manager_arp.go create mode 100644 pkg/service/manager_bgp.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 2fe5bb3f..33cf2bbd 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -3,7 +3,6 @@ package cmd import ( "fmt" "os" - "strconv" "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/service" @@ -94,9 +93,7 @@ func init() { // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "kube-vip", "The configuration map defined within the cluster") - kubeVipService.Flags().StringVarP(&service.Interface, "interface", "i", "eth0", "Name of the interface to bind to") kubeVipService.Flags().BoolVar(&service.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster") - kubeVipService.Flags().BoolVar(&service.EnableArp, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) @@ -144,37 +141,43 @@ var kubeVipService = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) - // User Environment variables as an option to make manifest clearer - envInterface := os.Getenv("vip_interface") - if envInterface != "" { - service.Interface = envInterface - } - - envConfigMap := os.Getenv("vip_configmap") - if envInterface != "" { - configMap = envConfigMap - } - - envLog := os.Getenv("vip_loglevel") - if envLog != "" { - logLevel, err := strconv.Atoi(envLog) - if err != nil { - panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int")) - } - log.SetLevel(log.Level(logLevel)) + // parse environment variables, these will overwrite anything loaded or flags + err := kubevip.ParseEnvironment(&startConfig) + if err != nil { + log.Fatalln(err) } - envArp := os.Getenv("vip_arp") - if envArp != "" { - arpBool, err := strconv.ParseBool(envArp) - if err != nil { - panic(fmt.Sprintf("Unable to parse environment variable [arp], should be bool (true/false)")) - } - service.EnableArp = arpBool - } + // // User Environment variables as an option to make manifest clearer + // envInterface := os.Getenv("vip_interface") + // if envInterface != "" { + // service.Interface = envInterface + // } + + // envConfigMap := os.Getenv("vip_configmap") + // if envInterface != "" { + // configMap = envConfigMap + // } + + // envLog := os.Getenv("vip_loglevel") + // if envLog != "" { + // logLevel, err := strconv.Atoi(envLog) + // if err != nil { + // panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int")) + // } + // log.SetLevel(log.Level(logLevel)) + // } + + // envArp := os.Getenv("vip_arp") + // if envArp != "" { + // arpBool, err := strconv.ParseBool(envArp) + // if err != nil { + // panic(fmt.Sprintf("Unable to parse environment variable [arp], should be bool (true/false)")) + // } + // service.EnableArp = arpBool + // } // Define the new service manager - mgr, err := service.NewManager(configMap) + mgr, err := service.NewManager(configMap, &startConfig) if err != nil { log.Fatalf("%v", err) } diff --git a/go.mod b/go.mod index b33cbd24..487de5ce 100644 --- a/go.mod +++ b/go.mod @@ -43,9 +43,8 @@ require ( github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect - golang.org/x/net v0.0.0-20200904194848-62affa334b73 + golang.org/x/net v0.0.0-20201021035429-f5854403a974 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect - golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0 // indirect google.golang.org/grpc v1.32.0 // indirect diff --git a/go.sum b/go.sum index 29ec6784..a26d281b 100644 --- a/go.sum +++ b/go.sum @@ -548,6 +548,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -585,8 +586,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -649,8 +650,8 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20 h1:4X356008q5SA3YXu8PiRap39KFmy4Lf6sGlceJKZQsU= -golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -711,6 +712,7 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 2937d325..5be53662 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -1,8 +1,11 @@ package cluster import ( + "fmt" + log "github.com/sirupsen/logrus" + "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/loadbalancer" "github.com/plunder-app/kube-vip/pkg/vip" @@ -103,7 +106,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro } // StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle -func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, disableVIP bool) error { +func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) error { // Start a kube-vip loadbalancer service log.Infoln("Starting kube-vip as a LoadBalancer Service") @@ -128,6 +131,17 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, disableVIP b } } + 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.IP(), c.VIPCIDR) + log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) + + err = bgp.AddHost(cidrVip) + if err != nil { + log.Error(err) + } + } + go func() { for { select { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 980052eb..f2467922 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -48,6 +48,9 @@ type Config struct { // EnableLoadBalancer, provides the flexibility to make the load-balancer optional EnableLoadBalancer bool `yaml:"enableLoadBalancer"` + // EnableARP, will use BGP to advertise the VIP address + EnableARP bool `yaml:"enableARP"` + // EnableBGP, will use BGP to advertise the VIP address EnableBGP bool `yaml:"enableBGP"` diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 783e3271..ff21d472 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -6,17 +6,14 @@ import ( "fmt" "io/ioutil" "os" - "os/signal" "path/filepath" - "strconv" "strings" - "syscall" - "time" "github.com/davecgh/go-spew/spew" "github.com/kamhlos/upnp" dhclient "github.com/digineo/go-dhclient" + "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" @@ -24,12 +21,11 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" - "k8s.io/client-go/tools/leaderelection" - "k8s.io/client-go/tools/leaderelection/resourcelock" watchtools "k8s.io/client-go/tools/watch" ) @@ -38,11 +34,7 @@ const plunderLock = "plunder-lock" // OutSideCluster allows the controller to be started using a local kubeConfig for testing var OutSideCluster bool -// EnableArp - determines the use of ARP broadcasts -var EnableArp bool - -// Interface - determines the interface that all Loadbalancers/macvlans will bind too -var Interface string +var signalChan chan os.Signal type plndrServices struct { Services []service `json:"services"` @@ -80,15 +72,19 @@ type service struct { type Manager struct { clientSet *kubernetes.Clientset configMap string + config *kubevip.Config + // Keeps track of all running instances serviceInstances []serviceInstance // Additional functionality upnp *upnp.Upnp + //BGP Manager, this is a singleton that manages all BGP advertisements + bgpServer *bgp.Server } // NewManager will create a new managing object -func NewManager(configMap string) (*Manager, error) { +func NewManager(configMap string, config *kubevip.Config) (*Manager, error) { var clientset *kubernetes.Clientset if OutSideCluster == false { // This will attempt to load the configuration when running within a POD @@ -117,193 +113,107 @@ func NewManager(configMap string) (*Manager, error) { return &Manager{ clientSet: clientset, configMap: configMap, + config: config, }, nil } -// Start will begin the ConfigMap watcher +// Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) Start() error { - ns, err := returnNameSpace() - if err != nil { - return err + // If BGP is enabled then we start a server instance that will broadcast VIPs + if sm.config.EnableBGP { + return sm.startBGP() } - id, err := os.Hostname() - if err != nil { - return err + // If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs + if sm.config.EnableARP { + return sm.startARP() + } + + log.Infoln("Prematurely exiting Load-balancer as neither Layer2 or Layer3 is enabled") + return nil +} + +func returnNameSpace() (string, error) { + if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if ns := strings.TrimSpace(string(data)); len(ns) > 0 { + return ns, nil + } + return "", err } + return "", fmt.Errorf("Unable to find Namespace") +} +// The watcher will watch config maps for new services being created +func (sm *Manager) watcher(ctx context.Context, ns string) { // Build a options structure to defined what we're looking for listOptions := metav1.ListOptions{ FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), } - log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ - LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, - Namespace: ns, - }, - Client: sm.clientSet.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{ - Identity: id, + + // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) }, - } + }) - // use a Go context so we can tell the leaderelection code when we - // want to step down - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + if err != nil { + log.Errorf("error creating watcher: %s", err.Error()) + ctx.Done() + } - // listen for interrupts or the Linux SIGTERM signal and cancel - // our context, which the leader election code will observe and - // step down - signalChan := make(chan os.Signal, 1) - // Add Notification for Userland interrupt - signal.Notify(signalChan, syscall.SIGINT) + ch := rw.ResultChan() + defer rw.Stop() + log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) - // Add Notification for SIGTERM (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGTERM) + var svcs plndrServices - // Add Notification for SIGKILL (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGKILL) go func() { - <-signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context, which will in turn cancel the leadership - cancel() - }() - - // Before starting the leader Election enable any additional functionality - upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) - - if upnpEnabled { - sm.upnp = new(upnp.Upnp) - err := sm.upnp.ExternalIPAddr() - if err != nil { - log.Errorf("Error Enabling UPNP %s", err.Error()) - // Set the struct to nil so nothing should use it in future - sm.upnp = nil - } else { - log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) - } - } - - // start the leader election code loop - leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ - Lock: lock, - // IMPORTANT: you MUST ensure that any code you have that - // is protected by the lease must terminate **before** - // you call cancel. Otherwise, you could have a background - // loop still running and another process could - // get elected before your background loop finished, violating - // the stated goal of the lease. - ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, - Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - // we're notified when we start - - // Watch function - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) - }, - }) - - if err != nil { - log.Errorf("error creating watcher: %s", err.Error()) - ctx.Done() + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) + cm, ok := event.Object.(*v1.ConfigMap) + if !ok { + log.Errorf("Unable to parse ConfigMap from watcher") + break } + data := cm.Data["plndr-services"] + json.Unmarshal([]byte(data), &svcs) + log.Debugf("Found %d services defined in ConfigMap", len(svcs.Services)) - ch := rw.ResultChan() - defer rw.Stop() - log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) - - var svcs plndrServices - //signalChan := make(chan os.Signal, 1) - //signal.Notify(signalChan, os.Interrupt) - go func() { - for event := range ch { - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) - cm, ok := event.Object.(*v1.ConfigMap) - if !ok { - log.Errorf("Unable to parse ConfigMap from watcher") - break - } - data := cm.Data["plndr-services"] - json.Unmarshal([]byte(data), &svcs) - log.Debugf("Found %d services defined in ConfigMap", len(svcs.Services)) - - err = sm.syncServices(&svcs) - if err != nil { - log.Errorf("%v", err) - } - case watch.Deleted: - log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Infoln("err") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - - default: - } - } - }() - - <-signalChan - }, - OnStoppedLeading: func() { - // we can do cleanup here - log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + err = sm.syncServices(&svcs) + if err != nil { + log.Errorf("%v", err) } - }, - OnNewLeader: func(identity string) { - // we're notified when new leader elected - if identity == id { - // I just got the lock - return + case watch.Deleted: + log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Infoln("err") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + // Retry unknown errors + //return false, 0 } - log.Infof("new leader elected: %s", identity) - }, - }, - }) - //<-signalChan - log.Infof("Shutting down Kube-Vip") + status := statusErr.ErrStatus + log.Errorf("%v", status) - return nil -} - -func returnNameSpace() (string, error) { - if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { - if ns := strings.TrimSpace(string(data)); len(ns) > 0 { - return ns, nil + default: + } } - return "", err - } - return "", fmt.Errorf("Unable to find Namespace") + }() + + <-signalChan } diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go new file mode 100644 index 00000000..e38bdd07 --- /dev/null +++ b/pkg/service/manager_arp.go @@ -0,0 +1,123 @@ +package service + +import ( + "context" + "os" + "os/signal" + "syscall" + "time" + + "github.com/plunder-app/kube-vip/pkg/bgp" + 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" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startARP() error { + ns, err := returnNameSpace() + if err != nil { + return err + } + + id, err := os.Hostname() + if err != nil { + return err + } + + // If BGP is enabled then we start the server that will broadcast VIPs + if sm.config.EnableBGP { + // Lets start BGP + log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + if err != nil { + log.Error(err) + } + } + + // Defer a function to check if the bgpServer has been created and if so attempt to close it + defer func() { + if sm.bgpServer != nil { + sm.bgpServer.Close() + } + }() + + log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: ns, + }, + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, + }, + } + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + signalChan := make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGTERM) + + // Add Notification for SIGKILL (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGKILL) + go func() { + <-signalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + sm.watcher(ctx, ns) + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + + //<-signalChan + log.Infof("Shutting down Kube-Vip") + + return nil +} diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go new file mode 100644 index 00000000..c5f2525f --- /dev/null +++ b/pkg/service/manager_bgp.go @@ -0,0 +1,82 @@ +package service + +import ( + "context" + "os" + "os/signal" + "syscall" + + "github.com/packethost/packngo" + "github.com/plunder-app/kube-vip/pkg/bgp" + "github.com/plunder-app/kube-vip/pkg/packet" + log "github.com/sirupsen/logrus" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startBGP() error { + ns, err := returnNameSpace() + if err != nil { + return err + } + + // If Packet is enabled then we can begin our preperation work + var packetClient *packngo.Client + if sm.config.EnablePacket { + packetClient, err = packngo.NewClient() + if err != nil { + log.Error(err) + } + + // We're using Packet with BGP, popuplate the Peer information from the API + if sm.config.EnableBGP { + log.Infoln("Looking up the BGP configuration from packet") + err = packet.BGPLookup(packetClient, sm.config) + if err != nil { + log.Error(err) + } + } + } + + log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + if err != nil { + return err + } + + // Defer a function to check if the bgpServer has been created and if so attempt to close it + defer func() { + if sm.bgpServer != nil { + sm.bgpServer.Close() + } + }() + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + signalChan = make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGTERM) + + // Add Notification for SIGKILL (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGKILL) + go func() { + <-signalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + sm.watcher(ctx, ns) + + log.Infof("Shutting down Kube-Vip") + + return nil +} diff --git a/pkg/service/services.go b/pkg/service/services.go index bf186fe9..1733207b 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -76,9 +76,9 @@ func (sm *Manager) syncServices(s *plndrServices) error { // Generate new Virtual IP configuration newVip := kubevip.Config{ VIP: s.Services[x].Vip, - Interface: Interface, + Interface: sm.config.Interface, SingleNode: true, - GratuitousARP: EnableArp, + GratuitousARP: sm.config.GratuitousARP, } // This instance wasn't found, we need to add it to the manager @@ -89,7 +89,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP if s.Services[x].Vip == "0.0.0.0" { - parent, err := netlink.LinkByName(Interface) + parent, err := netlink.LinkByName(sm.config.Interface) if err != nil { return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) } @@ -144,7 +144,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) //return err } - err = c.StartLoadBalancerService(&newService.vipConfig, false) + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) if err != nil { log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) //return err @@ -200,7 +200,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) - // Generate Load Balancer configu + // Generate Load Balancer config newLB := kubevip.LoadBalancer{ Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), Port: s.Services[x].Port, @@ -221,7 +221,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) return err } - err = c.StartLoadBalancerService(&newService.vipConfig, false) + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) if err != nil { log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) return err From 19757656b8672bf525e7480b3baf54236bff8c3c Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 9 Nov 2020 09:36:43 +0000 Subject: [PATCH 008/542] Tidy of code This reduces repetition of environment variablers and re-uses the existing configuration builder. --- cmd/kube-vip-config.go | 2 +- cmd/kube-vip-start.go | 2 +- cmd/kube-vip.go | 38 +++++++-------------------------- pkg/cluster/clusterLeader.go | 2 +- pkg/cluster/clusterRaft.go | 6 +++--- pkg/cluster/singleNode.go | 4 ++-- pkg/kubevip/config_generator.go | 4 ++-- pkg/kubevip/config_types.go | 4 ++-- pkg/service/services.go | 8 +++---- 9 files changed, 24 insertions(+), 46 deletions(-) diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index d8a9f0ce..8d0d031a 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -22,7 +22,7 @@ func init() { kubeVipSampleConfig.Flags().StringVar(&cliConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address") kubeVipSampleConfig.Flags().BoolVar(&cliConfig.SingleNode, "singleNode", false, "Start this instance as a single node") kubeVipSampleConfig.Flags().BoolVar(&cliConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") - kubeVipSampleConfig.Flags().BoolVar(&cliConfig.GratuitousARP, "arp", true, "Use ARP broadcasts to improve VIP re-allocations") + kubeVipSampleConfig.Flags().BoolVar(&cliConfig.EnableARP, "arp", true, "Use ARP broadcasts to improve VIP re-allocations") kubeVipSampleConfig.Flags().StringVar(&cliLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") kubeVipSampleConfig.Flags().StringSliceVar(&cliRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port") // Load Balancer flags diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index f75389b5..78b8688b 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -31,7 +31,7 @@ func init() { kubeVipStart.Flags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") kubeVipStart.Flags().BoolVar(&startConfig.SingleNode, "singleNode", false, "Start this instance as a single node") kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") - kubeVipStart.Flags().BoolVar(&startConfig.GratuitousARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") + kubeVipStart.Flags().BoolVar(&startConfig.EnableARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") kubeVipStart.Flags().StringVar(&startLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") kubeVipStart.Flags().StringSliceVar(&startRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port") // Load Balancer flags diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 33cf2bbd..7f1eb00a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -56,7 +56,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "", "The CIDR range for the virtual IP address") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.GratuitousARP, "arp", true, "Enable Arp for Vip changes") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", true, "Enable Arp for Vip changes") // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") @@ -92,7 +92,7 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&logLevel, "log", 4, "Set the level of logging") // Service flags - kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "kube-vip", "The configuration map defined within the cluster") + kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") kubeVipService.Flags().BoolVar(&service.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster") kubeVipCmd.AddCommand(kubeKubeadm) @@ -147,34 +147,12 @@ var kubeVipService = &cobra.Command{ log.Fatalln(err) } - // // User Environment variables as an option to make manifest clearer - // envInterface := os.Getenv("vip_interface") - // if envInterface != "" { - // service.Interface = envInterface - // } - - // envConfigMap := os.Getenv("vip_configmap") - // if envInterface != "" { - // configMap = envConfigMap - // } - - // envLog := os.Getenv("vip_loglevel") - // if envLog != "" { - // logLevel, err := strconv.Atoi(envLog) - // if err != nil { - // panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int")) - // } - // log.SetLevel(log.Level(logLevel)) - // } - - // envArp := os.Getenv("vip_arp") - // if envArp != "" { - // arpBool, err := strconv.ParseBool(envArp) - // if err != nil { - // panic(fmt.Sprintf("Unable to parse environment variable [arp], should be bool (true/false)")) - // } - // service.EnableArp = arpBool - // } + // User Environment variables as an option to make manifest clearer + + envConfigMap := os.Getenv("vip_configmap") + if envConfigMap != "" { + configMap = envConfigMap + } // Define the new service manager mgr, err := service.NewManager(configMap, &startConfig) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 35f11ca6..d1fff906 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -260,7 +260,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error } } - if c.GratuitousARP == true { + if c.EnableARP == true { ctxArp, cancelArp = context.WithCancel(context.Background()) go func(ctx context.Context) { diff --git a/pkg/cluster/clusterRaft.go b/pkg/cluster/clusterRaft.go index 0f0f1554..9734e2bc 100644 --- a/pkg/cluster/clusterRaft.go +++ b/pkg/cluster/clusterRaft.go @@ -130,7 +130,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { // ensure that if this node is the leader, it is set as the leader if localAddress == string(raftServer.Leader()) { // Re-broadcast arp to ensure network stays up to date - if c.GratuitousARP == true { + if c.EnableARP == true { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -187,7 +187,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { } } - if c.GratuitousARP == true { + if c.EnableARP == true { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -238,7 +238,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { } } } - if c.GratuitousARP == true { + if c.EnableARP == true { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 5be53662..0f06291b 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -62,7 +62,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro } } - if c.GratuitousARP == true { + if c.EnableARP == true { // Gratuitous ARP, will broadcast to new MAC <-> IP err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -123,7 +123,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser log.Warnf("%v", err) } - if c.GratuitousARP == true { + if c.EnableARP == true { // Gratuitous ARP, will broadcast to new MAC <-> IP err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 67f7fdfa..dd5899d4 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -214,7 +214,7 @@ func ParseEnvironment(c *Config) error { if err != nil { return err } - c.GratuitousARP = b + c.EnableARP = b } //Removal of seperate peer @@ -414,7 +414,7 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { newEnvironment := []corev1.EnvVar{ { Name: vipArp, - Value: strconv.FormatBool(c.GratuitousARP), + Value: strconv.FormatBool(c.EnableARP), }, { Name: vipInterface, diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index f2467922..cdc5d929 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -33,8 +33,8 @@ type Config struct { // Listen port for the VirtualIP Port int `yaml:"port"` - // GratuitousARP will broadcast an ARP update when the VIP changes host - GratuitousARP bool `yaml:"gratuitousARP"` + // // GratuitousARP will broadcast an ARP update when the VIP changes host + // GratuitousARP bool `yaml:"gratuitousARP"` // SingleNode will start the cluster as a single Node (Raft disabled) SingleNode bool `yaml:"singleNode"` diff --git a/pkg/service/services.go b/pkg/service/services.go index 1733207b..5613aaef 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -75,10 +75,10 @@ func (sm *Manager) syncServices(s *plndrServices) error { // Generate new Virtual IP configuration newVip := kubevip.Config{ - VIP: s.Services[x].Vip, - Interface: sm.config.Interface, - SingleNode: true, - GratuitousARP: sm.config.GratuitousARP, + VIP: s.Services[x].Vip, + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, } // This instance wasn't found, we need to add it to the manager From 6c42cdf379f3e74526b5b9bebe3b808e6be548f1 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 9 Nov 2020 09:55:45 +0000 Subject: [PATCH 009/542] Rebase removed initialisation of upnp This ensures that UPNP is started correctly, it was accidentally removed during the rebase. --- pkg/service/manager_arp.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index e38bdd07..a18e82b3 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -4,9 +4,11 @@ import ( "context" "os" "os/signal" + "strconv" "syscall" "time" + "github.com/kamhlos/upnp" "github.com/plunder-app/kube-vip/pkg/bgp" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,6 +28,22 @@ func (sm *Manager) startARP() error { return err } + // Before starting the leader Election enable any additional functionality + upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) + + log.Errorf("Unable to parse ConfigMap from watcher") + if upnpEnabled { + sm.upnp = new(upnp.Upnp) + err := sm.upnp.ExternalIPAddr() + if err != nil { + log.Errorf("Error Enabling UPNP %s", err.Error()) + // Set the struct to nil so nothing should use it in future + sm.upnp = nil + } else { + log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + } + } + // If BGP is enabled then we start the server that will broadcast VIPs if sm.config.EnableBGP { // Lets start BGP From 71296c9c086c7cb0c8050ffa532b3299fd76768d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 9 Nov 2020 15:03:21 +0000 Subject: [PATCH 010/542] Fixes for existing DHCP interfaces A macvlan interface is created using part of the service UUID, the service caching in the cloud-provider can cause problems with the same interface names.. This allows interface re-use. --- Makefile | 4 +- docs/manifests/controller.yaml | 98 ++++++++----------------- docs/manifests/controller_test.yaml | 107 ---------------------------- pkg/service/manager_arp.go | 1 - pkg/service/services.go | 38 ++++++---- 5 files changed, 55 insertions(+), 193 deletions(-) delete mode 100644 docs/manifests/controller_test.yaml diff --git a/Makefile b/Makefile index 10569e18..4f76a192 100644 --- a/Makefile +++ b/Makefile @@ -54,12 +54,12 @@ demo: # This build a local docker image (x86 only) for quick testing dockerx86: - @rm ./kube-vip + @-rm ./kube-vip @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New single x86 Architecture Docker image created docker: - @rm ./kube-vip + @-rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created diff --git a/docs/manifests/controller.yaml b/docs/manifests/controller.yaml index 425e17db..eb12755a 100644 --- a/docs/manifests/controller.yaml +++ b/docs/manifests/controller.yaml @@ -1,63 +1,5 @@ apiVersion: v1 kind: ServiceAccount -metadata: - name: starboard - namespace: kube-system ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: starboard-role - namespace: kube-system -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["watch","get"] ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: starboard-role-bind - namespace: kube-system -subjects: - - kind: ServiceAccount - name: starboard - apiGroup: "" -roleRef: - kind: Role - name: starboard-role - apiGroup: "" ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: starboard-ds - namespace: kube-system - labels: -spec: - selector: - matchLabels: - name: starboard-ds - template: - metadata: - labels: - name: starboard-ds - spec: - hostNetwork: true - serviceAccountName: starboard - containers: - - name: starboard-ds - image: plndr/starboard:0.1.1 - imagePullPolicy: Always - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_ADMIN ---- -apiVersion: v1 -kind: ServiceAccount metadata: name: plunder-cloud-controller namespace: kube-system @@ -89,18 +31,36 @@ subjects: name: plunder-cloud-controller namespace: kube-system --- -apiVersion: v1 -kind: Pod +apiVersion: apps/v1 +kind: StatefulSet metadata: - creationTimestamp: null name: plndr-cloud-provider namespace: kube-system spec: - containers: - - command: - - /plndr-cloud-provider - image: plndr/plndr-cloud-provider:0.1.3 - name: plndr-cloud-provider - imagePullPolicy: Always - resources: {} - serviceAccountName: plunder-cloud-controller + serviceName: plndr-cloud-provider + podManagementPolicy: OrderedReady + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: kube-vip + component: plndr-cloud-provider + template: + metadata: + labels: + app: kube-vip + component: plndr-cloud-provider + spec: + containers: + - command: + - /plndr-cloud-provider + image: plndr/plndr-cloud-provider:0.1.4 + name: plndr-cloud-provider + imagePullPolicy: Always + resources: {} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + serviceAccountName: plunder-cloud-controller \ No newline at end of file diff --git a/docs/manifests/controller_test.yaml b/docs/manifests/controller_test.yaml deleted file mode 100644 index c2349430..00000000 --- a/docs/manifests/controller_test.yaml +++ /dev/null @@ -1,107 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: starboard - namespace: kube-system ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: starboard-role - namespace: kube-system -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["watch","get"] ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: starboard-role-bind - namespace: kube-system -subjects: - - kind: ServiceAccount - name: starboard - apiGroup: "" -roleRef: - kind: Role - name: starboard-role - apiGroup: "" ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: starboard-ds - namespace: kube-system - labels: -spec: - selector: - matchLabels: - name: starboard-ds - template: - metadata: - labels: - name: starboard-ds - spec: - hostNetwork: true - serviceAccountName: starboard - containers: - - name: starboard-ds - image: plndr/starboard:0.1.1 - imagePullPolicy: Always - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_ADMIN ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: plunder-cloud-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:plunder-cloud-controller-role -rules: - - apiGroups: [""] - resources: ["configmaps", "endpoints","events","services/status"] - verbs: ["*"] - - apiGroups: [""] - resources: ["nodes", "services"] - verbs: ["list","get","watch"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:plunder-cloud-controller-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:plunder-cloud-controller-role -subjects: -- kind: ServiceAccount - name: plunder-cloud-controller - namespace: kube-system ---- -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: plndr-cloud-provider - namespace: kube-system -spec: - containers: - - command: - - /plndr-cloud-provider - - --leader-elect-resource-name plndr-cloud-controller - image: plndr/plndr-cloud-provider:0.1.3 - name: plndr-cloud-provider - imagePullPolicy: Always - resources: {} - serviceAccountName: plunder-cloud-controller diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index a18e82b3..4fc37218 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -31,7 +31,6 @@ func (sm *Manager) startARP() error { // Before starting the leader Election enable any additional functionality upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) - log.Errorf("Unable to parse ConfigMap from watcher") if upnpEnabled { sm.upnp = new(upnp.Upnp) err := sm.upnp.ExternalIPAddr() diff --git a/pkg/service/services.go b/pkg/service/services.go index 5613aaef..afb47074 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -99,20 +99,29 @@ func (sm *Manager) syncServices(s *plndrServices) error { // Generate name from UID interfaceName := fmt.Sprintf("vip-%s", s.Services[x].UID[0:8]) - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} - err = netlink.LinkAdd(mac) - if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) - } - - err = netlink.LinkSetUp(mac) - if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) - } - + // Check if the interface doesn't exist first iface, err := net.InterfaceByName(interfaceName) if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) + + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + + err = netlink.LinkAdd(mac) + if err != nil { + return fmt.Errorf("Could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) + } + iface, err = net.InterfaceByName(interfaceName) + if err != nil { + return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + } client := dhclient.Client{ @@ -121,7 +130,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { // Set VIP to Address from lease newVip.VIP = lease.FixedAddress.String() - log.Infof("New VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) // Generate Load Balancer configu newLB := kubevip.LoadBalancer{ @@ -172,7 +181,8 @@ func (sm *Manager) syncServices(s *plndrServices) error { return } dhcpService.Spec.LoadBalancerIP = newVip.VIP - _, err = sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) + updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) + log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.ExternalIPs) if err != nil { log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) return From 31a5ca4d60612a51b8829ce4449a90bae587e5c5 Mon Sep 17 00:00:00 2001 From: Kaito Ii Date: Tue, 10 Nov 2020 11:56:36 +0900 Subject: [PATCH 011/542] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 92cf886b..a026decc 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Overview -Kubernetes Virtual IP and Load-Balancer for both control pane and Kubernetes services +Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services The idea behind `kube-vip` is a small self-contained Highly-Available option for all environments, especially: From 051ed3d9eb9c9328520b13528882d0fb34afcfc9 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 10 Nov 2020 11:32:49 +0000 Subject: [PATCH 012/542] Phase one BGP works We can now create a BGP balanced load-balancer in Kubernetes. --- go.mod | 2 +- pkg/service/manager_arp.go | 33 ++++++++++++++++----------------- pkg/service/services.go | 31 +++++++++++++++---------------- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 487de5ce..49635421 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/osrg/gobgp v2.0.0+incompatible - github.com/packethost/packngo v0.3.0 + github.com/packethost/packngo v0.5.0 github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.6.0 diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index 4fc37218..87db51cc 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -9,7 +9,6 @@ import ( "time" "github.com/kamhlos/upnp" - "github.com/plunder-app/kube-vip/pkg/bgp" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection" @@ -43,22 +42,22 @@ func (sm *Manager) startARP() error { } } - // If BGP is enabled then we start the server that will broadcast VIPs - if sm.config.EnableBGP { - // Lets start BGP - log.Info("Starting the BGP server to adverise VIP routes to VGP peers") - sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) - if err != nil { - log.Error(err) - } - } - - // Defer a function to check if the bgpServer has been created and if so attempt to close it - defer func() { - if sm.bgpServer != nil { - sm.bgpServer.Close() - } - }() + // // If BGP is enabled then we start the server that will broadcast VIPs + // if sm.config.EnableBGP { + // // Lets start BGP + // log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + // sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + // if err != nil { + // log.Error(err) + // } + // } + + // // Defer a function to check if the bgpServer has been created and if so attempt to close it + // defer func() { + // if sm.bgpServer != nil { + // sm.bgpServer.Close() + // } + // }() log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, id) // we use the Lease lock type since edits to Leases are less common diff --git a/pkg/service/services.go b/pkg/service/services.go index afb47074..1fdfe86b 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -79,6 +79,8 @@ func (sm *Manager) syncServices(s *plndrServices) error { Interface: sm.config.Interface, SingleNode: true, EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, } // This instance wasn't found, we need to add it to the manager @@ -132,16 +134,16 @@ func (sm *Manager) syncServices(s *plndrServices) error { newVip.VIP = lease.FixedAddress.String() log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) - // Generate Load Balancer configu - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - Port: s.Services[x].Port, - Type: s.Services[x].Type, - BindToVip: true, - } + // // Generate Load Balancer configu + // newLB := kubevip.LoadBalancer{ + // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + // Port: s.Services[x].Port, + // Type: s.Services[x].Type, + // BindToVip: true, + // } - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + // // Add Load Balancer Configuration + // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) // Create Add configuration to the new service newService.vipConfig = newVip @@ -161,15 +163,12 @@ func (sm *Manager) syncServices(s *plndrServices) error { newService.cluster = *c // Begin watching endpoints for this service - go sm.newWatcher(&newService) + //go sm.newWatcher(&newService) // Add new service to manager configuration sm.serviceInstances = append(sm.serviceInstances, newService) // Update the service - // listOptions := metav1.ListOptions{ - // FieldSelector: fmt.Sprintf("metadata.uid=%s", newService.service.UID), - // } ns, err := returnNameSpace() if err != nil { log.Errorf("Error finding Namespace") @@ -182,13 +181,13 @@ func (sm *Manager) syncServices(s *plndrServices) error { } dhcpService.Spec.LoadBalancerIP = newVip.VIP updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) - log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.ExternalIPs) + log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) if err != nil { log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) return } - sm.upnpMap(s.Services[x]) + sm.upnpMap(newService.service) }, } @@ -242,7 +241,7 @@ func (sm *Manager) syncServices(s *plndrServices) error { newService.cluster = *c // Begin watching endpoints for this service - go sm.newWatcher(&newService) + //go sm.newWatcher(&newService) // Add new service to manager configuration sm.serviceInstances = append(sm.serviceInstances, newService) From 8f31390c8025d59c4ae5efb0aa989014ac596ae0 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 10 Nov 2020 15:16:25 +0000 Subject: [PATCH 013/542] Fixes the watcher for the lifecycle of the advertised address. This final commit ensures that we stop advertising the VIP after the service is deleted --- pkg/service/services.go | 8 ++++---- pkg/service/watcher.go | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/service/services.go b/pkg/service/services.go index 1fdfe86b..95365e9c 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -162,8 +162,8 @@ func (sm *Manager) syncServices(s *plndrServices) error { } newService.cluster = *c - // Begin watching endpoints for this service - //go sm.newWatcher(&newService) + // Begin watching this service + go sm.newWatcher(&newService) // Add new service to manager configuration sm.serviceInstances = append(sm.serviceInstances, newService) @@ -240,8 +240,8 @@ func (sm *Manager) syncServices(s *plndrServices) error { newService.cluster = *c - // Begin watching endpoints for this service - //go sm.newWatcher(&newService) + // Begin watching this service + go sm.newWatcher(&newService) // Add new service to manager configuration sm.serviceInstances = append(sm.serviceInstances, newService) diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index a15cd29c..a3e7f67a 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -46,14 +46,14 @@ func (sm *Manager) newWatcher(s *serviceInstance) error { // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added, watch.Modified: - log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - ep, ok := event.Object.(*v1.Endpoints) - if !ok { - return fmt.Errorf("Unable to parse Endpoints from watcher") - } - s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + // ep, ok := event.Object.(*v1.Endpoints) + // if !ok { + // return fmt.Errorf("Unable to parse Endpoints from watcher") + // } + // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) - log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) + // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) case watch.Deleted: log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) From 8afd5d50d4b0fe966303245ca708462604297ef0 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 11 Nov 2020 10:48:14 +0000 Subject: [PATCH 014/542] This fixes logging through env --- pkg/kubevip/config_generator.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index dd5899d4..d7555ca7 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/ghodss/yaml" + log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -114,8 +115,18 @@ const ( // ParseEnvironment - will popultate the configuration from environment variables func ParseEnvironment(c *Config) error { + // Ensure that logging is set through the environment variables + env := os.Getenv(vipLogLevel) + if env != "" { + logLevel, err := strconv.Atoi(env) + if err != nil { + panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int")) + } + log.SetLevel(log.Level(logLevel)) + } + // Find interface - env := os.Getenv(vipInterface) + env = os.Getenv(vipInterface) if env != "" { c.Interface = env } From 38c42271f7f0f71b284e143abb0eb0348ef73774 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 11 Nov 2020 13:44:09 +0000 Subject: [PATCH 015/542] Doc re-write for 0.2.1 --- docs/architecture/index.md | 13 ++- docs/control-plane/index.md | 57 +++++------ docs/index/index.md | 3 +- docs/kubernetes/arp/index.md | 181 +++++++++++++++++++++++++++++++++++ docs/kubernetes/bgp/index.md | 87 +++++++++++++++++ docs/kubernetes/index.md | 181 ++++------------------------------- 6 files changed, 315 insertions(+), 207 deletions(-) create mode 100644 docs/kubernetes/arp/index.md create mode 100644 docs/kubernetes/bgp/index.md diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 94a4527c..9bda3715 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -17,9 +17,9 @@ There are a number of technologies or functional design choices that provide hig The `kube-vip` service builds a multi-node or multi-pod cluster to provide High-Availability. When a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster. -When running **out of cluster** it will use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology +When using ARP or layer2 it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) -When running **in cluster** it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) +It is also possible to use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology, but this approach has largely been superseded by leader election. ### Virtual IP @@ -58,6 +58,10 @@ Request timeout for icmp_seq 150 Within a Kubernetes cluster, the load-balancing is managed by the `plndr-cloud-provider` which watches all service that are created, and for those of `type: LoadBalancer` will create the configuration for `kube-vip` to consume. +#### Load Balancing (Inside a cluster) + +When using `type:LoadBalancer` within a Kubernetes cluster `kube-vip` will assign the VIP to the leader (when using ARP) all to all running Pods (when using BGP). When traffic is directed to a node with the VIP then the rules configured by `kube-proxy` will redirect the traffic to one of the pods running in the service. + #### Load Balancing (Outside a cluster) Within the configuration of `kube-vip` multiple load-balancers can be created, below is the example load-balancer for a Kubernetes Control-plane: @@ -100,7 +104,6 @@ Additionally the load-balancing within `kibe-vip` has two modes of operation: The `kube-vip` kubernetes load-balancer requires a number of components in order to function: - The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) -- The Starboard Daemonset -> [https://github.com/plunder-app/starboard](https://github.com/plunder-app/starboard) - The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) ### Architecture overview @@ -131,10 +134,6 @@ data: cidr-testing: 192.168.0.220/29 ``` -### Starboard Daemonset - -The `starboard` pod is a simple service that implements a [client-go](https://github.com/kubernetes/client-go) [watch](https://github.com/plunder-app/starboard/blob/master/main.go#L72) on a Kubernetes `configMap` that contains the network range/cidr that load-balancer addresses will use. It then ensures that this cidr is present in the ipTables of all machines in the cluster, this will ensure that network traffic is directed to `kube-vip` to be load-balancer to the underlying application pods. - ### Kube-vip The `kube-vip` pod should exist in every namespace that requires load-balancing services, it also implements a "client-go watch" over a `configMap` in its current namespace. These configurations and created and managed by the cloud-provider, when `kube-vip` sees a change happen (i.e. a new service is defined) then it will implement the virtual IP and start the load-balancer. Furthermore `kube-vip` implements a second "watch" over the endpoints of the service and as that service changes (pods die, scaling etc..) so will the the endpoints that `kube-vip` will load-balancer over. diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md index 1ffa3ab9..b4019a1f 100644 --- a/docs/control-plane/index.md +++ b/docs/control-plane/index.md @@ -20,7 +20,7 @@ Below are examples of the steps required: ``` # First Node -sudo docker run --network host --rm plndr/kube-vip:0.1.8 kubeadm init \ +sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -32,7 +32,7 @@ sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0 sudo kubeadm join 192.168.0.75:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 -sudo docker run --network host --rm plndr/kube-vip:0.1.8 kubeadm init \ +sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -59,8 +59,8 @@ All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.1.8 \ - kubeadm init \ + --rm plndr/kube-vip:0.2.1 \ + manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -77,11 +77,6 @@ To enable Kubernetes leader Election passing the `--leaderElection` flag will en **VIP Config** We will need to set our VIP address to `192.168.0.75` with `--vip 192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `--arp` (defaults to `true`) -**Load Balancer** -We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. - -We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. - **vip.yaml** Static-pod Manifest `$ sudo cat /etc/kubernetes/manifests/vip.yaml` @@ -102,24 +97,18 @@ spec: - name: vip_arp value: "true" - name: vip_interface - value: ens192 - - name: vip_address - value: 192.168.0.81 - - name: vip_startleader + value: ens160 + - name: vip_leaderelection value: "true" - - name: vip_addpeerstolb - value: "true" - - name: vip_localpeer - value: controlPlane01:192.168.0.70:10000 - - name: lb_backendport - value: "6443" - - name: lb_name - value: Kubeadm Load Balancer - - name: lb_type - value: tcp - - name: lb_bindtovip - value: "true" - image: plndr/kube-vip:0.1.8 + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.75 + image: plndr/kube-vip:0.2.1 imagePullPolicy: Always name: kube-vip resources: {} @@ -140,8 +129,8 @@ Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/man ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.1.8 \ - kubeadm init \ + --rm plndr/kube-vip:0.2.1 \ + manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -152,7 +141,7 @@ Ensure that `image: plndr/kube-vip:` is modified to point to a specific versi The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. -`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` +`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --upload-certs --kubernetes-version “v1.17.0”` Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: @@ -179,8 +168,8 @@ At this point **DON’T** generate the manifests, this is due to some bizarre `k ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.1.8 \ - kubeadm init \ + --rm plndr/kube-vip:0.2.1 \ + manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -200,7 +189,7 @@ kube-system kube-vip-controlplane03 1/1 Running ## BGP Support (added in 0.1.8) -In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. +In version `0.1.8`+ `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. The following new flags are used: @@ -240,7 +229,7 @@ export PACKET_AUTH_TOKEN=XYZ ``` # Generate the manifest -sudo docker run --network host --rm plndr/kube-vip:0.1.7 kubeadm init \ +sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ --arp=false \ --interface lo \ --vip $EIP \ @@ -262,7 +251,7 @@ kubeadm join $EIP:6443 --token BLAH --control-plane --certificate-key BLAH --dis # Generate Manifest -sudo docker run --network host --rm plndr/kube-vip:0.1.7 kubeadm init \ +sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ --arp=false \ --interface lo \ --vip $EIP \ diff --git a/docs/index/index.md b/docs/index/index.md index 045e0099..07cb28d2 100644 --- a/docs/index/index.md +++ b/docs/index/index.md @@ -1,6 +1,6 @@ # Kube-vip -A Load-Balancer for both **inside** and **outside** a Kubernetes cluster +The **kube-vip** project provides High-Availability and load-balancing for both **inside** and **outside** a Kubernetes cluster ![kube-vip.png](kube-vip.png) @@ -19,5 +19,4 @@ The details are [here](/kubernetes/) ## GitHub Repositories - The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) -- The Starboard Daemonset -> [https://github.com/plunder-app/starboard](https://github.com/plunder-app/starboard) - The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) \ No newline at end of file diff --git a/docs/kubernetes/arp/index.md b/docs/kubernetes/arp/index.md new file mode 100644 index 00000000..29b54c63 --- /dev/null +++ b/docs/kubernetes/arp/index.md @@ -0,0 +1,181 @@ +# Kube-vip (Layer 2 / ARP) + +**BEFORE** we begin we should ensure that ipvs has `strict` ARP enabled: + +``` +$ kubectl describe configmap -n kube-system kube-proxy | grep ARP + strictARP: false +``` + +If this is false we can enable it with the command: + +``` +$ kubectl get configmap kube-proxy -n kube-system -o yaml | \ + sed -e "s/strictARP: false/strictARP: true/" | \ + kubectl apply -f - -n kube-system +``` + +and confirm with: + +``` +$ kubectl describe configmap -n kube-system kube-proxy | grep ARP + strictARP: true +``` + +## Deploy `kube-vip` + +To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml`, specific versions should be found in the repository as detailed below: + +From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: +``` +serviceaccount/vip created +role.rbac.authorization.k8s.io/vip-role created +rolebinding.rbac.authorization.k8s.io/vip-role-bind created +deployment.apps/kube-vip-cluster created +``` + +*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. + +### Editing `kube-vip` configuration + +Either download and edit the manifest locally or apply as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) + +``` + - name: vip_interface + value: ens192 + - name: vip_configmap + value: plndr + - name: vip_arp + value: "true" + - name: vip_loglevel + value: "5" +``` + +- `vip_interface` - defines the interface that the VIP will bind to +- `vip_configmap` - defines the `configmap` that `kube-vip` will watch for service configuration +- `vip_arp` - determines if ARP broadcasts are enabled +- `vip_loglevel` - determines the verbosity of logging + +## Using other namespaces + +In this example we'll deploy and load-balance within the namespace `plunder` + +### Create the namespace + +`kubectl create namespace plunder` + +### Add a network range/cidr for this namespace + +`kubectl edit -n kube-system configmap/plndr` + +We will add the range 192.168.0.210/29 for the namespace plunder underneath the existing range for the namespace default: + +``` +apiVersion: v1 +data: + cidr-default: 192.168.0.200/29 + cidr-global: 192.168.0.210/29 + cidr-plunder: 192.168.0.220/29 +<...> +``` + +### Deploy `kube-vip` in the namespace **plunder** + +In the same way we deployed `kube-vip` into the default namespace we can deploy the same manifest into a different namespace using `-n namespace` e.g. + +**Note** change the version of manifest when actually deploying! + +``` +kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml -n plunder +``` + +## Usage + +This example will deploy into the namespace `plunder` as mention in the [Using other namespaces](Using other namespaces) example. Remove the `-n plunder` to deploy within the `default` namespace. + +### Deploy nginx + +``` +kubectl create deployment --image nginx plunder-nginx --namespace plunder +``` + +### Create a load balancer + +``` +kubectl expose deployment plunder-nginx --port=80 --type=LoadBalancer --namespace plunder +``` + +## Using DHCP for Load Balancers (experimental) + +With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a Kubernetes service on the network. + +In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! + +``` +$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc +service/nginx-dhcp exposed +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s + +{ ... a second or so later ... } + +$ k get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s +``` + +## Using UPNP to expose a service to the outside world + +With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the internet. + +Most simple networks look something like the following: + +`<----- ----> Internet` + +Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. + +### Enable UPNP + +Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. + +**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) + +``` +- name: enableUPNP + value: "true" +``` + +### Exposing a service + +To expose a port successfully we'll need to change the command slightly: + +`--target-port=80` the port of the application in the pods (HTT/NGINX) +`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) + +`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` + +The above example should expose a port on your external (internet facing address), that can be tested externally with: + +``` +$ curl externalIP:32380 + + +... +``` + +## Troubleshooting + +Typically the logs from the `kube-vip` controller will reveal the most clues as to where a problem may lie. + +The `ClusterRoleBinding` is missing will result in the following: + +``` +E0229 17:36:38.014351 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) +E0229 17:36:38.014352 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) +``` + +Additionally ensure that the vip_interface matches the correct interface from `ip addr` \ No newline at end of file diff --git a/docs/kubernetes/bgp/index.md b/docs/kubernetes/bgp/index.md new file mode 100644 index 00000000..8929bc65 --- /dev/null +++ b/docs/kubernetes/bgp/index.md @@ -0,0 +1,87 @@ +# Kube-vip (Layer 3 / BGP) + +## Deploy `kube-vip` + +To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml`, specific versions should be found in the repository as detailed below: + +From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: +``` +serviceaccount/vip created +role.rbac.authorization.k8s.io/vip-role created +rolebinding.rbac.authorization.k8s.io/vip-role-bind created +deployment.apps/kube-vip-cluster created +``` + +*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. + +### Editing `kube-vip` configuration + +Either download and edit the manifest locally or apply as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) + +Ensure the `vip_arp` isn't enabled as ARP and BGP can't be used at the same time (today), also that the `vip_interface` is set to localhost (`lo`). + +``` + - name: vip_interface + value: "lo" + - name: vip_configmap + value: "plndr" + - name: bgp_enable + value: "true" + - name: vip_loglevel + value: "5" +``` + +### BGP Specific configuration + +Additionally for BGP we'll need some configuration details, your local friendly network admin should be able to help here: + +``` + - name: bgp_routerid + value: "192.168.0.45" + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + value: "10.0.0.1" + - name: bgp_peeras + value: "65522" +``` + +### BGP on Packet + +If you're lucky enough to be running services on Packet then The above BGP information can be found from the API, instead of specifying the above we need to use the following: + +``` + - name: vip_packet + value: "true" + - name: vip_packetproject + value: "My Project" + - name: PACKET_AUTH_TOKEN + value: "XXYZZYVVY" +``` + +With the above configuration in place, all `kube-vip` pods will start in active mode and when a service is exposed then all nodes will advertise the VIP to the routers. + +## Expose a service + +Given that `kube-vip` doesn't know your network (at this point) ask your local friendly network OPs for an address you can advertise. That is the address you can expose to the outside world as shown below! + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` + +## Expose with packet + +Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! + +``` +# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 ++-------+---------------+--------+----------------------+ +| ID | ADDRESS | PUBLIC | CREATED | ++-------+---------------+--------+----------------------+ +| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | ++-------+---------------+--------+----------------------+ + +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` \ No newline at end of file diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md index b3971bb7..d9d1b4d1 100644 --- a/docs/kubernetes/index.md +++ b/docs/kubernetes/index.md @@ -6,29 +6,33 @@ The below instructions *should just work* on Kubernetes regardless of architectu If you just want things to "work", then you can quickly install the "latest" components: -**Install the `plndr-cloud-provider`, `starboard` and `kube-vip`** +**NOTE** the `kube-vip.yaml` may need customising to set ARP/BGP OR to configure which interface to bind VIPs too. + +**Install the `plndr-cloud-provider`, and `kube-vip`** ``` kubectl apply -f https://kube-vip.io/manifests/controller.yaml kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml ``` -**Create the `cidr` for the `default` namespace** +**Create the `cidr` for the `global` namespace** ``` -kubectl create configmap --namespace kube-system plndr --from-literal cidr-default=192.168.0.200/29 +kubectl create configmap --namespace kube-system plndr --from-literal cidr-global=192.168.0.200/29 ``` -Creating services of `type: LoadBalancer` in the default namespace will now take addresses from the cidr defined in the `configmap`. +Creating services of `type: LoadBalancer` in the default namespace will now take addresses from the **global** cidr defined in the `configmap`. **Additional namespaces** Edit the `configmap` and add in the cidr ranges for those namespaces, the key in the cidr should be `cidr-`, then ensure that `kube-vip` is deployed into that namespace with the above `apply` command with the `-n namespace` flag. -## Deploying `kube-vip` in a Kubernetes cluster (in detail) +## The Detailed guide ### Deploy the `plndr-cloud-provider` +To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/controller.yaml`, specific versions should be found in the repository as detailed below: + From the GitHub repository [https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod](https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. The following output should appear when the manifest is applied: @@ -42,11 +46,13 @@ pod/plndr-cloud-provider created We can validate the cloud-provider by examining the pods: -`kubectl logs -n kube-system plndr-cloud-provider -f` +`kubectl logs -n kube-system plndr-cloud-provider-0 -f` #### The `plndr-cloud-provider` `configmap` -To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within the `configmap` should be that the key is in the format `cidr-` and teh value should be the cidr range. +The `configmap` details a CIDR range *per* namespace, however as of (`kube-vip 0.2.1` and `plnder-cloud-provider 0.1.4`), there is now the option of having a **global** CIDR range (`cidr-global)`. + +To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within the `configmap` should be that the key is in the format `cidr-` and the value should be the cidr range. Example Configmap: @@ -58,165 +64,12 @@ metadata: namespace: kube-system data: cidr-default: 192.168.0.200/29 - cidr-plunder: 192.168.0.210/29 -``` - -### Deploy `starboard` - -This requires no customisation as it simply monitors the `configMap` managed by the plndr-cloud-provider. - -From the GitHub repository [https://github.com/plunder-app/starboard/tree/master/examples/daemonset](https://github.com/plunder-app/starboard/tree/master/examples/daemonset) find the version of the starboard to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. - -The following output should appear when the manifest is applied: -``` -serviceaccount/starboard created -role.rbac.authorization.k8s.io/starboard-role created -rolebinding.rbac.authorization.k8s.io/starboard-role-bind created -daemonset.apps/starboard-ds created -``` - -### Deploy `kube-vip` - -From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the kube-vip to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. - -The following output should appear when the manifest is applied: -``` -serviceaccount/vip created -role.rbac.authorization.k8s.io/vip-role created -rolebinding.rbac.authorization.k8s.io/vip-role-bind created -deployment.apps/kube-vip-cluster created -``` - -*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. - -#### Editing `kube-vip` configuration - -Either download and edit the manifest locally or appy as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) - -``` - - name: vip_interface - value: ens192 - - name: vip_configmap - value: plndr - - name: vip_arp - value: "true" - - name: vip_loglevel - value: "5" -``` - -- `vip_interface` - defines the interface that the VIP will bind to -- `vip_configmap` - defines the configmap that `kube-vip` will watch for service configuration -- `vip_arp` - determines if ARP broadcasts are enabled -- `vip_loglevel` - determines the verbosity of logging - -## Testing - -This testing is performed on a brand new three node (`1.17.0`, 1 **Master**, 2 **Worker**) cluster, running Calico as the CNI plugin. - -#### Deploy NGINX - -``` -kubectl apply -f https://k8s.io/examples/application/deployment.yaml -``` - -#### Create Load-Balancer - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-loadbalancer -``` - -#### View Load-Balancer - -``` -$ k describe service nginx-loadbalancer -Name: nginx-loadbalancer -Namespace: default -Labels: -Annotations: -Selector: app=nginx -Type: LoadBalancer -IP: 10.96.184.221 -LoadBalancer Ingress: 192.168.0.81 -Port: 80/TCP -TargetPort: 80/TCP -NodePort: 31138/TCP -Endpoints: 172.16.198.194:80,172.16.232.2:80 -Session Affinity: None -External Traffic Policy: Cluster -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal EnsuringLoadBalancer 30s service-controller Ensuring load balancer - Normal EnsuredLoadBalancer 29s service-controller Ensured load balancer -``` - -Any host with on the same network or has the correct routes configured should now be able to use the load-balancer address displayed in the configuration: `LoadBalancer Ingress: 192.168.0.81` - -## Using other namespaces - -In this example we'll deploy and load-balance within the namespace `plunder` - -### Create the namespace - -`kubectl create namespace plunder` - -### Add a network range/cidr for this namespace - -`kubectl edit -n kube-system configmap/plndr` - -We will add the range 192.168.0.210/29 for the namespace plunder underneath the existing range for the namespace default: - -``` -apiVersion: v1 -data: - cidr-default: 192.168.0.200/29 - cidr-plunder: 192.168.0.210/29 -<...> -``` - -### Deploy `kube-vip` in the namespace **plunder** - -In the same way we deployed `kube-vip` into the default namespace we can deploy the same manifest into a different namespace using `-n namespace` e.g. - -**Note** change the version of manifest when actually deploying! - -``` -kubectl apply -f https://github.com/plunder-app/kube-vip/raw/master/example/deploy/0.1.3.yaml -n plunder -``` - -### Deploy nginx - -``` -kubectl create deployment --image nginx plunder-nginx --namespace plunder -``` - -### Create a load balancer - -``` -kubectl expose deployment plunder-nginx --port=80 --type=LoadBalancer --namespace plunder + cidr-global: 192.168.0.210/29 ``` -## Troubleshooting - -Typically the logs from the `kube-vip` controller will reveal the most clues as to where a problem may lie. +### Deploying `kube-vip` -The `ClusterRoleBinding` is missing will result in the following: +To use `kube-vip` in Layer2/ARP the follow this [guide](/arp/) -``` -E0229 17:36:38.014351 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) -E0229 17:36:38.014352 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) -``` - -If Load-balancing isn't working as expected, then examine the `iptables` on the node running `kube-vip`: - -``` -sudo iptables -L -n -t nat | more -Chain PREROUTING (policy ACCEPT) -target prot opt source destination -cali-PREROUTING all -- 0.0.0.0/0 0.0.0.0/0 /* cali:6gwbT8clXdHdC1b1 */ -ACCEPT all -- 0.0.0.0/0 192.168.0.80/29 -KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */ -DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL -``` +To use `kube-vip` in Layer3/BGP the follow this [guide](/bgp/) -Ensure that the `cidr` is present in the PREROUTING table, if this is missing ensure that the starboard daemonset is running. From d93df4edb28e2ed6bee3ce040cdd84a557dce4d9 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 11 Nov 2020 13:53:18 +0000 Subject: [PATCH 016/542] Fix to URLs --- docs/kubernetes/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md index d9d1b4d1..a345e522 100644 --- a/docs/kubernetes/index.md +++ b/docs/kubernetes/index.md @@ -69,7 +69,7 @@ data: ### Deploying `kube-vip` -To use `kube-vip` in Layer2/ARP the follow this [guide](/arp/) +To use `kube-vip` in Layer2/ARP the follow this [guide](/kubernetes/arp/) -To use `kube-vip` in Layer3/BGP the follow this [guide](/bgp/) +To use `kube-vip` in Layer3/BGP the follow this [guide](/kubernetes/bgp/) From c5a4212229f67104c793d1e9247dc444afd4d6cb Mon Sep 17 00:00:00 2001 From: jzhoucliqr Date: Wed, 11 Nov 2020 13:13:09 -0800 Subject: [PATCH 017/542] add dynamic dns support with dhcp --- cmd/kube-vip-start.go | 11 ---- go.mod | 2 +- go.sum | 4 +- pkg/cluster/cluster.go | 3 +- pkg/cluster/clusterDDNS.go | 26 ++++++++ pkg/cluster/clusterLeader.go | 23 ++++++- pkg/kubevip/config_generator.go | 13 ++++ pkg/kubevip/config_types.go | 3 + pkg/vip/address.go | 49 +++++++++++++-- pkg/vip/ddns.go | 102 ++++++++++++++++++++++++++++++++ pkg/vip/dns.go | 13 ++-- pkg/vip/util.go | 15 ++++- 12 files changed, 234 insertions(+), 30 deletions(-) create mode 100644 pkg/cluster/clusterDDNS.go create mode 100644 pkg/vip/ddns.go diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 78b8688b..063ed3c0 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -1,13 +1,11 @@ package cmd import ( - "context" "os" "os/signal" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -78,15 +76,6 @@ var kubeVipStart = &cobra.Command{ log.Fatalf("%v", err) } - // start the dns updater if the address flag is used and the address isn't an IP - if startConfig.Address != "" && !vip.IsIP(startConfig.Address) { - log.Infof("starting the DNS updater for the address %s", startConfig.Address) - - ipUpdater := vip.NewIPUpdater(startConfig.Address, newCluster.Network) - - ipUpdater.Run(context.Background()) - } - if startConfig.SingleNode { // If the Virtual IP isn't disabled then create the netlink configuration // Start a single node cluster diff --git a/go.mod b/go.mod index 49635421..be31d62f 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/golang/protobuf v1.4.2 github.com/google/go-cmp v0.5.2 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.18 // indirect + github.com/google/gopacket v1.1.18 github.com/google/uuid v1.1.2 // indirect github.com/googleapis/gnostic v0.5.1 // indirect github.com/hashicorp/go-hclog v0.14.1 // indirect diff --git a/go.sum b/go.sum index a26d281b..1d0cda1d 100644 --- a/go.sum +++ b/go.sum @@ -379,8 +379,8 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyTzf1c5VubkPi+Q83O9oBCNgA= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= -github.com/packethost/packngo v0.3.0 h1:mE5UHyhr5sKN1Qa0GtExRG9ECUX/muazI0f53gSrt5E= -github.com/packethost/packngo v0.3.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= +github.com/packethost/packngo v0.5.0 h1:WGpfeRMstPqgyXGUXl6b9xFsbUudXU3p0+JlYri290U= +github.com/packethost/packngo v0.5.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index af9c95b5..46d3e68f 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -37,7 +37,6 @@ func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) { return newCluster, nil } - func startNetworking(c *kubevip.Config) (vip.Network, error) { address := c.VIP @@ -45,7 +44,7 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { address = c.Address } - network, err := vip.NewConfig(address, c.Interface) + network, err := vip.NewConfig(address, c.Interface, c.DDNS) if err != nil { return nil, err } diff --git a/pkg/cluster/clusterDDNS.go b/pkg/cluster/clusterDDNS.go new file mode 100644 index 00000000..7d045e7f --- /dev/null +++ b/pkg/cluster/clusterDDNS.go @@ -0,0 +1,26 @@ +package cluster + +import ( + "context" + "github.com/plunder-app/kube-vip/pkg/vip" +) + +// StartDDNS should start go routine for dhclient to hold the lease for the IP +// StartDDNS should wait until IP is allocated from DHCP, set it to cluster.Network +// so the OnStartedLeading can continue to configure the VIP initially +// during runtime if IP changes, startDDNS don't have to do reconfigure because +// dnsUpdater already have the functionality to keep trying resolve the IP +// and update the VIP configuration if it changes +func (cluster *Cluster) StartDDNS(ctx context.Context) error { + ddnsMgr := vip.NewDDNSManager(ctx, cluster.Network) + ip, err := ddnsMgr.Start() + if err != nil { + return err + } + + if err = cluster.Network.SetIP(ip); err != nil { + return err + } + + return nil +} diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index d1fff906..0ec44e53 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -111,6 +111,11 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error ctxArp, cancelArp := context.WithCancel(context.Background()) defer cancelArp() + // use a Go context so we can tell the dns loop code when we + // want to step down + ctxDns, cancelDns := context.WithCancel(context.Background()) + defer cancelDns() + // listen for interrupts or the Linux SIGTERM signal and cancel // our context, which the leader election code will observe and // step down @@ -205,9 +210,23 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error RetryPeriod: time.Duration(c.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - // we're notified when we start log.Info("This node is starting with leadership of the cluster") + // setup ddns first + // for first time, need to wait until IP is allocated from DHCP + if cluster.Network.IsDDNS() { + if err := cluster.StartDDNS(ctxDns); err != nil { + log.Error(err) + } + } + + // start the dns updater if address is dns + if cluster.Network.IsDNS() { + log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) + ipUpdater := vip.NewIPUpdater(cluster.Network) + ipUpdater.Run(ctxDns) + } + err = cluster.Network.AddIP() if err != nil { log.Warnf("%v", err) @@ -284,6 +303,8 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error // we can do cleanup here log.Info("This node is becoming a follower within the cluster") + // Stop the dns context + cancelDns() // Stop the Arp context if it is running cancelArp() diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index d7555ca7..8f77b645 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -52,6 +52,9 @@ const ( //port - defines the port for the VIP port = "port" + //vipDdns - defines if use dynamic dns to allocate IP for "address" + vipDdns = "vip_ddns" + //vipSingleNode - defines the vip start as a single node cluster vipSingleNode = "vip_singlenode" @@ -189,6 +192,16 @@ func ParseEnvironment(c *Config) error { c.Port = int(i) } + // Find vipDdns + env = os.Getenv(vipDdns) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.DDNS = b + } + // Find vip address cidr range env = os.Getenv(vipCidr) if env != "" { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index cdc5d929..d4d1ee6c 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -36,6 +36,9 @@ type Config struct { // // GratuitousARP will broadcast an ARP update when the VIP changes host // GratuitousARP bool `yaml:"gratuitousARP"` + // use DDNS to allocate IP when Address is set to a DNS Name + DDNS bool `yaml:"ddns"` + // SingleNode will start the cluster as a single Node (Raft disabled) SingleNode bool `yaml:"singleNode"` diff --git a/pkg/vip/address.go b/pkg/vip/address.go index f4a716e1..cbabbb7f 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -19,6 +19,10 @@ type Network interface { IP() string SetIP(ip string) error Interface() string + IsDNS() bool + IsDDNS() bool + DDNSHostName() string + DNSName() string } // network - This allows network configuration @@ -27,11 +31,13 @@ type network struct { address *netlink.Addr link netlink.Link - isDNS bool + + dnsName string + isDDNS bool } // NewConfig will attempt to provide an interface to the kernel network configuration -func NewConfig(address string, iface string) (Network, error) { +func NewConfig(address string, iface string, isDDNS bool) (Network, error) { result := &network{} link, err := netlink.LinkByName(iface) @@ -48,10 +54,18 @@ func NewConfig(address string, iface string) (Network, error) { return result, nil } + // address is DNS + result.isDDNS = isDDNS + result.dnsName = address + // try to resolve the address ip, err := lookupHost(address) - result.isDNS = err == nil if err != nil { + // return early for ddns if no IP is allocated for the domain + // when leader starts, should do get IP from DHCP for the domain + if isDDNS { + return result, nil + } return nil, err } @@ -96,6 +110,10 @@ func (configurator *network) DeleteIP() error { func (configurator *network) IsSet() (result bool, err error) { var addresses []netlink.Addr + if configurator.address == nil { + return false, nil + } + addresses, err = netlink.AddrList(configurator.link, 0) if err != nil { err = errors.Wrap(err, "could not list addresses") @@ -121,7 +139,7 @@ func (configurator *network) SetIP(ip string) error { if err != nil { return err } - if configurator.address != nil && configurator.isDNS { + if configurator.address != nil && configurator.IsDNS() { addr.ValidLft = defaultValidLft } configurator.address = addr @@ -136,6 +154,29 @@ func (configurator *network) IP() string { return configurator.address.IP.String() } +// DNSName return the configured dnsName when use DNS +func (configurator *network) DNSName() string { + return configurator.dnsName +} + +// IsDNS - when dnsName is configured +func (configurator *network) IsDNS() bool { + return configurator.dnsName != "" +} + +// IsDDNS - return true if use dynamic dns +func (configurator *network) IsDDNS() bool { + return configurator.isDDNS +} + +// DDNSHostName - return the hostname for dynamic dns +// when dDNSHostName is not empty, use DHCP to get IP for hostname: dDNSHostName +// it's expected that dynamic DNS should be configured so +// the fqdn for apiserver endpoint is dDNSHostName.{LocalDomain} +func (configurator *network) DDNSHostName() string { + return getHostName(configurator.dnsName) +} + // Interface - return the Interface name func (configurator *network) Interface() string { return configurator.link.Attrs().Name diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go new file mode 100644 index 00000000..2d0801b3 --- /dev/null +++ b/pkg/vip/ddns.go @@ -0,0 +1,102 @@ +package vip + +import ( + "context" + "net" + "time" + + dhclient "github.com/digineo/go-dhclient" + "github.com/google/gopacket/layers" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +// DDNSManager will start a dhclient to retrieve and keep the lease for the IP +// for the dDNSHostName +// will return the IP allocated +type DDNSManager interface { + Start() (string, error) +} + +type ddnsManager struct { + ctx context.Context + network Network +} + +func NewDDNSManager(ctx context.Context, network Network) DDNSManager { + return &ddnsManager{ + ctx: ctx, + network: network, + } +} + +// Start will start the dhcpclient routine to keep the lease +// and return the IP it got from DHCP +func (ddns *ddnsManager) Start() (string, error) { + interfaceName := ddns.network.Interface() + iface, err := net.InterfaceByName(interfaceName) + if err != nil { + return "", err + } + + // channel to wait for IP + ipCh := make(chan string) + + client := dhclient.Client{ + // send host name, not current os.Hostname, but configured name from user + Hostname: ddns.network.DDNSHostName(), + Iface: iface, + OnBound: func(lease *dhclient.Lease) { + ipCh <- lease.FixedAddress.String() + }, + } + + // add default request param + for _, param := range dhclient.DefaultParamsRequestList { + client.AddParamRequest(param) + } + // send hostname to get IP for this specific name + client.AddOption(layers.DHCPOptHostname, []byte(client.Hostname)) + // use clientID so different leaders will use same ID to get same IP + client.AddOption(layers.DHCPOptClientID, []byte(client.Hostname)) + + log.Info("start dhcp client for ddns") + client.Start() + + log.Info("waiting for ip from dhcp") + ip, timeout := "", time.After(1*time.Minute) + + select { + case <-ddns.ctx.Done(): + client.Stop() + return "", errors.New("context cancelled") + case <-timeout: + client.Stop() + return "", errors.New("failed to get IP from dhcp for ddns in 1 minutes") + case ip = <-ipCh: + log.Info("got ip from dhcp: ", ip) + } + + // lease.FixedAddress.String() could return + if ip == "" { + return "", errors.New("failed to get IP from dhcp for ddns, got ip as ") + } + + // start a go routine to stop dhclient when lose leader election + // also to keep read the ip from channel + // so onbound function is unblocked to send the ip + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + log.Info("stop dhclient for ddns") + client.Stop() + return + case ip := <-ipCh: + log.Info("got ip from dhcp: ", ip) + } + } + }(ddns.ctx) + + return ip, nil +} diff --git a/pkg/vip/dns.go b/pkg/vip/dns.go index 17f1f419..c773c216 100644 --- a/pkg/vip/dns.go +++ b/pkg/vip/dns.go @@ -13,15 +13,13 @@ type IPUpdater interface { } type ipUpdater struct { - dnsName string - vip Network + vip Network } // NewIPUpdater creates a DNSUpdater -func NewIPUpdater(dnsName string, vip Network) IPUpdater { +func NewIPUpdater(vip Network) IPUpdater { return &ipUpdater{ - dnsName: dnsName, - vip: vip, + vip: vip, } } @@ -31,11 +29,12 @@ func (d *ipUpdater) Run(ctx context.Context) { for { select { case <-ctx.Done(): + log.Infof("stop ipUpdater") return default: - ip, err := lookupHost(d.dnsName) + ip, err := lookupHost(d.vip.DNSName()) if err != nil { - log.Warnf("cannot lookup %s: %v", d.dnsName, err) + log.Warnf("cannot lookup %s: %v", d.vip.DNSName(), err) // fallback to renewing the existing IP ip = d.vip.IP() } diff --git a/pkg/vip/util.go b/pkg/vip/util.go index bf6401f5..fd8c010e 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -1,8 +1,9 @@ package vip import ( - "net" "github.com/pkg/errors" + "net" + "strings" ) // LookupHost resolves dnsName and return an IP or an error @@ -21,4 +22,14 @@ func lookupHost(dnsName string) (string, error) { func IsIP(address string) bool { ip := net.ParseIP(address) return ip != nil -} \ No newline at end of file +} + +// getHostName return the hostname from the fqdn +func getHostName(dnsName string) string { + if dnsName == "" { + return "" + } + + fields := strings.Split(dnsName, ".") + return fields[0] +} From 6c056b441a3ac68b6b3ebb35b347bdcce78a1110 Mon Sep 17 00:00:00 2001 From: jzhoucliqr Date: Thu, 12 Nov 2020 15:02:12 -0800 Subject: [PATCH 018/542] add docs for dns support, also adding the missing ddns commandline option --- cmd/kube-vip-start.go | 1 + docs/control-plane/index.md | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 063ed3c0..cd670d3e 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -27,6 +27,7 @@ func init() { kubeVipStart.Flags().StringVar(&startConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address") kubeVipStart.Flags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipStart.Flags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") + kubeVipStart.Flags().BoolVar(&startConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") kubeVipStart.Flags().BoolVar(&startConfig.SingleNode, "singleNode", false, "Start this instance as a single node") kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") kubeVipStart.Flags().BoolVar(&startConfig.EnableARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md index 1ffa3ab9..ff498a11 100644 --- a/docs/control-plane/index.md +++ b/docs/control-plane/index.md @@ -198,6 +198,20 @@ kube-system kube-vip-controlplane03 1/1 Running ``` +## DNS Support + +### Static DNS Support (added in 0.2.0) + +A new flag `--address` is introduced to support using a DNS record as the control plane endpoint. `kube-vip` will do a dns lookup to retrieve the IP for the DNS record, and use that IP as the VIP. An `dnsUpdater` periodically checks and updates the system if IP changes for the DNS record. + +### Dynamic DNS Support (added in 0.2.1) + +`kube-vip` was also updated to support DHCP + [Dynamic DNS](https://en.wikipedia.org/wiki/Dynamic_DNS), for the use case where it's not able to reserve a static IP for the control plane endpoint. + +A new flag `--ddns` is introduced. Once enabled, `kube-vip` expects the input `--address` will be a FQDN without binding to an IP. Then `kube-vip` will start a dhcp client to allocate an IP for the hostname of FQDN, and maintain the lease for it. + +Once DHCP returns an IP for the FQDN, the same `dnsUpdater` runs to periodically checks and updates if IP got changed. + ## BGP Support (added in 0.1.8) In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. @@ -415,4 +429,4 @@ sudo ./k3s server --tls-san $VIP \ mkdir -p $HOME/.kube sudo cat /etc/rancher/k3s/k3s.yaml | sed 's/127.0.0.1/'$VIP'/g' > $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config -``` \ No newline at end of file +``` From 147f665054d1f25c4c17b1366caee2d2564d0819 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 20 Nov 2020 12:05:49 +0000 Subject: [PATCH 019/542] BGP Fixes --- Makefile | 2 +- pkg/kubevip/config_generator.go | 27 ++++++++++++++++++++++----- pkg/service/services.go | 5 +++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 4f76a192..5da56e04 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.2.1 +VERSION := 0.2.2 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 8f77b645..20c0fea9 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/ghodss/yaml" + "github.com/plunder-app/kube-vip/pkg/detector" log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -83,6 +84,8 @@ const ( bgpEnable = "bgp_enable" //bgpRouterID defines the routerID for the BGP server bgpRouterID = "bgp_routerid" + //bgpRouterInterface defines the interface that we can find the address for + bgpRouterInterface = "bgp_routerinterface" //bgpRouterAS defines the AS for the BGP server bgpRouterAS = "bgp_as" //bgpPeerAddress defines the address for a BGP peer @@ -295,11 +298,22 @@ func ParseEnvironment(c *Config) error { c.EnableBGP = b } + // BGP Router interface determines an interface that we can use to find an address for + env = os.Getenv(bgpRouterInterface) + if env != "" { + _, address, err := detector.FindIPAddress(env) + if err != nil { + return err + } + c.BGPConfig.RouterID = address + } + // RouterID env = os.Getenv(bgpRouterID) if env != "" { c.BGPConfig.RouterID = env } + // AS env = os.Getenv(bgpRouterAS) if env != "" { @@ -310,11 +324,6 @@ func ParseEnvironment(c *Config) error { c.BGPConfig.AS = uint32(u64) } - // BGP Peer options - env = os.Getenv(bgpPeerAddress) - if env != "" { - c.BGPPeerConfig.Address = env - } // Peer AS env = os.Getenv(bgpPeerAS) if env != "" { @@ -325,6 +334,14 @@ func ParseEnvironment(c *Config) error { c.BGPPeerConfig.AS = uint32(u64) } + // BGP Peer options + env = os.Getenv(bgpPeerAddress) + if env != "" { + c.BGPPeerConfig.Address = env + // If we've added in a peer configuration, then we should add it to the BGP configuration + c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig) + } + // Enable the Packet API calls env = os.Getenv(vipPacket) if env != "" { diff --git a/pkg/service/services.go b/pkg/service/services.go index 95365e9c..7337133e 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -46,6 +46,11 @@ func (sm *Manager) deleteService(uid string) error { } netlink.LinkDel(macvlan) } + if sm.serviceInstances[x].vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) + err := sm.bgpServer.DelHost(cidrVip) + return err + } } } // If we've been through all services and not found the correct one then error From 8981de5f4fb2f710352d30317ce7ca6e5c471078 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 20 Nov 2020 15:26:19 +0000 Subject: [PATCH 020/542] defaults the cidr for service types lb --- cmd/kube-vip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 7f1eb00a..b5906df0 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -55,7 +55,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "", "The CIDR range for the virtual IP address") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", true, "Enable Arp for Vip changes") // Clustering type (leaderElection) From 0241437a4fa6f8aa64b267c5b98aed85db34e302 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 20 Nov 2020 19:47:01 +0000 Subject: [PATCH 021/542] Fixes to scope --- cmd/kube-vip.go | 10 +++++----- pkg/service/manager.go | 2 ++ pkg/vip/address.go | 5 +++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index b5906df0..4640e86e 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -53,10 +53,10 @@ func init() { //initConfig.Peers = append(initConfig.Peers, *localpeer) kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") - kubeVipCmd.PersistentFlags().StringVar(&startConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") - kubeVipCmd.PersistentFlags().IntVar(&startConfig.Port, "port", 6443, "listen port for the VIP") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") + kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "listen port for the VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", true, "Enable Arp for Vip changes") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") @@ -142,7 +142,7 @@ var kubeVipService = &cobra.Command{ log.SetLevel(log.Level(logLevel)) // parse environment variables, these will overwrite anything loaded or flags - err := kubevip.ParseEnvironment(&startConfig) + err := kubevip.ParseEnvironment(&initConfig) if err != nil { log.Fatalln(err) } @@ -155,7 +155,7 @@ var kubeVipService = &cobra.Command{ } // Define the new service manager - mgr, err := service.NewManager(configMap, &startConfig) + mgr, err := service.NewManager(configMap, &initConfig) if err != nil { log.Fatalf("%v", err) } diff --git a/pkg/service/manager.go b/pkg/service/manager.go index ff21d472..29800f91 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -122,11 +122,13 @@ func (sm *Manager) Start() error { // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { + log.Infoln("Starting loadBalancer Service with the BGP engine") return sm.startBGP() } // If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs if sm.config.EnableARP { + log.Infoln("Starting loadBalancer Service with the ARP engine") return sm.startARP() } diff --git a/pkg/vip/address.go b/pkg/vip/address.go index cbabbb7f..78dcce1d 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" ) const ( @@ -51,6 +52,10 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { if err != nil { return result, errors.Wrapf(err, "could not parse address '%s'", address) } + // Ensure we don't have a global address on loopback + if iface == "lo" { + result.address.Scope = unix.RT_SCOPE_HOST + } return result, nil } From 91645cbd3695ba4ca2d775ec82a6818afe316f8b Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 23 Nov 2020 14:21:34 +0000 Subject: [PATCH 022/542] Update README.md --- README.md | 62 ++++++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a026decc..40cdc851 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # kube-vip +High Availability and Load-Balancing -**NOTE** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io) - +![](https://kube-vip.io/kube-vip.png) ## Overview Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services @@ -11,15 +11,25 @@ The idea behind `kube-vip` is a small self-contained Highly-Available option for - Bare-Metal - Edge (arm / Raspberry PI) +- Virtualisation - Pretty much anywhere else :) -![](/overview.png) +**NOTE** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io) -The `kube-vip` application builds a multi-node or multi-pod cluster to provide High-Availability. When a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster. +## Features -When running **out of cluster** it will use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) clustering technology +Kube-Vip was originally created to provide a HA solutions for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). -When running **in cluster** it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) +- Control Plane with ARP (Layer 2) or BGP (Layer 3) +- Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) +- Control Plane HA with kubeadm (static Pods) +- Control Plane HA with K3s/and others (daemonsets) +- Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2) +- Service LoadBalancer using multiple nodes with BGP +- Service LoadBalancer address pools per namespace or global +- Service LoadBalancer address via (existing network DHCP) +- Service LoadBalancer address exposure to gateway via UPNP +- ... manifest generation, vendor API integrations and many nore... ## Why? @@ -42,42 +52,6 @@ The purpose of `kube-vip` is to simplify the building of HA Kubernetes clusters, All of these would require a separate level of configuration and in some infrastructures multiple teams in order to implement. Also when considering the software components, they may require packaging into containers or if they’re pre-packaged then security and transparency may be an issue. Finally, in edge environments we may have limited room for hardware (no HW load-balancer) or packages solutions in the correct architectures might not exist (e.g. ARM). Luckily with `kube-vip` being written in GO, it’s small(ish) and easy to build for multiple architectures, with the added security benefit of being the only thing needed in the container. +## Troubleshooting and Feedback -## Standalone Usage - -The usage of `kube-vip` can either be directly by taking the binary / building yourself (`make build`), or alternatively through a pre-built docker container which can be found in the plunder Docker Hub repository [https://hub.docker.com/r/plndr/kube-vip](https://hub.docker.com/r/plndr/kube-vip). For further - -### Configuration - -To generate the basic `yaml` configuration: - -``` -kube-vip sample config > config.yaml -``` - -Modify the `localPeer` section to match this particular instance (local IP address/port etc..) and ensure that the `remotePeers` section is correct for the current instance and all other instances in the cluster. Also ensure that the `interface` is the correct interface that the `vip` will bind to. - - -## Starting a simple cluster - -To start `kube-vip` ensure the configuration for the `localPeers` and `remotePeers` is correct for each instance and the cluster as a whole and start: - -``` -kube-vip start -c /config.yaml -INFO[0000] Reading configuration from [config.yaml] -INFO[0000] 2020-02-01T15:41:04.287Z [INFO] raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:server1 Address:192.168.0.70:10000} {Suffrage:Voter ID:server2 Address:192.168.0.71:10000} {Suffrage:Voter ID:server3 Address:192.168.0.72:10000}]" -INFO[0000] 2020-02-01T15:41:04.287Z [INFO] raft: entering follower state: follower="Node at 192.168.0.70:10000 [Follower]" leader= -INFO[0000] Started -INFO[0000] The Node [] is leading -INFO[0001] The Node [] is leading -INFO[0001] 2020-02-01T15:41:05.522Z [WARN] raft: heartbeat timeout reached, starting election: last-leader= -INFO[0001] 2020-02-01T15:41:05.522Z [INFO] raft: entering candidate state: node="Node at 192.168.0.70:10000 [Candidate]" term=2 -INFO[0001] 2020-02-01T15:41:05.522Z [DEBUG] raft: votes: needed=2 -INFO[0001] 2020-02-01T15:41:05.522Z [DEBUG] raft: vote granted: from=server1 term=2 tally=1 -INFO[0001] 2020-02-01T15:41:05.523Z [DEBUG] raft: newer term discovered, fallback to follower -INFO[0001] 2020-02-01T15:41:05.523Z [INFO] raft: entering follower state: follower="Node at 192.168.0.70:10000 [Follower]" leader= -INFO[0001] 2020-02-01T15:41:05.838Z [WARN] raft: failed to get previous log: previous-index=2 last-index=1 error="log not found" -INFO[0002] The Node [192.168.0.72:10000] is leading -``` - -After a few seconds with additional nodes started a leader election will take place and the leader will assume the **vip**. +Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/) From e02083d97295504e13d44d5f178dd32ce9dcc346 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 24 Nov 2020 18:08:33 +0000 Subject: [PATCH 023/542] First instance of a hybrid CP/SVCS design --- cmd/kube-vip.go | 17 +- go.mod | 1 + pkg/cluster/clusterLeader.go | 13 +- pkg/kubevip/config_generator.go | 29 +++- pkg/kubevip/config_types.go | 21 +-- pkg/manager/manager.go | 187 ++++++++++++++++++++++ pkg/manager/manager_arp.go | 155 ++++++++++++++++++ pkg/manager/manager_bgp.go | 103 ++++++++++++ pkg/manager/services.go | 273 ++++++++++++++++++++++++++++++++ pkg/manager/watcher.go | 224 ++++++++++++++++++++++++++ 10 files changed, 1003 insertions(+), 20 deletions(-) create mode 100644 pkg/manager/manager.go create mode 100644 pkg/manager/manager_arp.go create mode 100644 pkg/manager/manager_bgp.go create mode 100644 pkg/manager/services.go create mode 100644 pkg/manager/watcher.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 4640e86e..1ad9fc96 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -5,7 +5,7 @@ import ( "os" "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/service" + "github.com/plunder-app/kube-vip/pkg/manager" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -13,9 +13,15 @@ import ( // Path to the configuration file var configPath string +// Path to the configuration file +var namespace string + // Disable the Virtual IP (bind to the existing network stack) var disableVIP bool +// Disable the Virtual IP (bind to the existing network stack) +var controlPlane bool + // Run as a load balancer service (within a pod / kubernetes) var serviceArp bool @@ -88,12 +94,16 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") + // Control plane specific flags + kubeVipService.Flags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") + // Manage logging kubeVipCmd.PersistentFlags().Uint32Var(&logLevel, "log", 4, "Set the level of logging") // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") - kubeVipService.Flags().BoolVar(&service.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster") + kubeVipService.Flags().BoolVar(&manager.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster") + kubeVipService.Flags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) @@ -155,10 +165,11 @@ var kubeVipService = &cobra.Command{ } // Define the new service manager - mgr, err := service.NewManager(configMap, &initConfig) + mgr, err := manager.New(configMap, &initConfig) if err != nil { log.Fatalf("%v", err) } + // Start the service manager, this will watch the config Map and construct kube-vip services for it err = mgr.Start() if err != nil { diff --git a/go.mod b/go.mod index be31d62f..e99bd1d1 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect golang.org/x/net v0.0.0-20201021035429-f5854403a974 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0 // indirect google.golang.org/grpc v1.32.0 // indirect diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 0ec44e53..f9c85f9c 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -27,12 +27,11 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" ) -const plunderLock = "plunder-lock" -const namespace = "kube-system" +const plunderLock = "plndr-cp-lock" // Manager degines the manager of the load-balancing services type Manager struct { - clientSet *kubernetes.Clientset + KubernetesClient *kubernetes.Clientset } // NewManager will create a new managing object @@ -74,7 +73,7 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { } return &Manager{ - clientSet: clientset, + KubernetesClient: clientset, }, nil } @@ -86,16 +85,16 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error return err } - log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", namespace, plunderLock, id) + log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", c.Namespace, plunderLock, 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{ LeaseMeta: metav1.ObjectMeta{ Name: plunderLock, - Namespace: namespace, + Namespace: c.Namespace, }, - Client: sm.clientSet.CoordinationV1(), + Client: sm.KubernetesClient.CoordinationV1(), LockConfig: resourcelock.ResourceLockConfig{ Identity: id, }, diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 20c0fea9..29005f44 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -93,6 +93,12 @@ const ( //bgpPeerAS defines the AS for a BGP peer bgpPeerAS = "bgp_peeras" + //cpNamespace defines the namespace the control plane pods will run in + cpNamespace = "cp_namespace" + + //cpEnable starts kube-vip in the hybrid mode + cpEnable = "cp_enable" + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" @@ -205,10 +211,31 @@ func ParseEnvironment(c *Config) error { c.DDNS = b } + // Find vip address cidr range + env = os.Getenv(cpNamespace) + if env != "" { + c.Namespace = env + } + + // Find the namespace that the control pane should use (for leaderElection lock) + env = os.Getenv(cpNamespace) + if env != "" { + c.Namespace = env + } + + // Find vipDdns + env = os.Getenv(cpEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableControlPane = b + } + // Find vip address cidr range env = os.Getenv(vipCidr) if env != "" { - // TODO - parse address net.Host() c.VIPCIDR = env } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index d4d1ee6c..dd45bf2c 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -6,9 +6,18 @@ import ( "github.com/plunder-app/kube-vip/pkg/bgp" ) -// Config defines all of the settings for the Virtual IP / Load-balancer +// Config defines all of the settings for the Kube-Vip Pod type Config struct { + // EnableARP, will use BGP to advertise the VIP address + EnableARP bool `yaml:"enableARP"` + + // EnableBGP, will use BGP to advertise the VIP address + EnableBGP bool `yaml:"enableBGP"` + + // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) + EnableControlPane bool `yaml:"enableControlPane"` + // LeaderElection defines the settings around Kubernetes LeaderElection LeaderElection @@ -33,8 +42,8 @@ type Config struct { // Listen port for the VirtualIP Port int `yaml:"port"` - // // GratuitousARP will broadcast an ARP update when the VIP changes host - // GratuitousARP bool `yaml:"gratuitousARP"` + // Namespace will define which namespace the control plane pods will run in + Namespace string `yaml:"namespace"` // use DDNS to allocate IP when Address is set to a DNS Name DDNS bool `yaml:"ddns"` @@ -51,12 +60,6 @@ type Config struct { // EnableLoadBalancer, provides the flexibility to make the load-balancer optional EnableLoadBalancer bool `yaml:"enableLoadBalancer"` - // EnableARP, will use BGP to advertise the VIP address - EnableARP bool `yaml:"enableARP"` - - // EnableBGP, will use BGP to advertise the VIP address - EnableBGP bool `yaml:"enableBGP"` - // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go new file mode 100644 index 00000000..264e8779 --- /dev/null +++ b/pkg/manager/manager.go @@ -0,0 +1,187 @@ +package manager + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + dhclient "github.com/digineo/go-dhclient" + "github.com/kamhlos/upnp" + "github.com/plunder-app/kube-vip/pkg/bgp" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +const plunderLock = "plndr-svcs-lock" + +var signalChan chan os.Signal + +// OutSideCluster allows the controller to be started using a local kubeConfig for testing +var OutSideCluster bool + +type kubernetesServices struct { + Services []service `json:"services"` +} + +// Manager degines the manager of the load-balancing services +type Manager struct { + clientSet *kubernetes.Clientset + configMap string + config *kubevip.Config + + // Manager services + service bool + + // Keeps track of all running instances + serviceInstances []Instance + + // Additional functionality + upnp *upnp.Upnp + //BGP Manager, this is a singleton that manages all BGP advertisements + bgpServer *bgp.Server +} + +type dhcpService struct { + // dhcpClient (used DHCP for the vip) + dhcpClient *dhclient.Client + dhcpInterface string +} + +// Instance defines an instance of everything needed to manage a vip +type Instance struct { + // Virtual IP / Load Balancer configuration + vipConfig kubevip.Config + // Kubernetes service mapping + service service + // cluster instance + cluster cluster.Cluster + + // Custom settings + dhcp *dhcpService +} + +// TODO - call from a package (duplicated struct in the cloud-provider code) +type service struct { + Vip string `json:"vip"` + Port int `json:"port"` + UID string `json:"uid"` + Type string `json:"type"` + + ServiceName string `json:"serviceName"` +} + +// SetControlPane determines if the control plane should be enabled +// func (sm *Manager) SetControlPane(enable bool) { +// sm.controlPane = enable +// } + +// New will create a new managing object +func New(configMap string, config *kubevip.Config) (*Manager, error) { + var clientset *kubernetes.Clientset + if OutSideCluster == false || !config.EnableControlPane { + // This will attempt to load the configuration when running within a POD + cfg, err := rest.InClusterConfig() + if err != nil { + return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) + } + clientset, err = kubernetes.NewForConfig(cfg) + + if err != nil { + log.Debugln("Using incluster Kubernetes configuration") + return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) + } + // use the current context in kubeconfig + } else { + // Check for file existing + // First for default path on control plane + // /etc/kubernetes/admin.conf + var configPath string + var cfg *rest.Config + var err error + + configPath = "/etc/kubernetes/admin.conf" + if fileExists(configPath) { + cfg, err = clientcmd.BuildConfigFromFlags("", configPath) + if err != nil { + return nil, err + } + } else { + // Second check in home directory for kube config + configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") + cfg, err = clientcmd.BuildConfigFromFlags("", configPath) + if err != nil { + return nil, err + } + } + + log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) + clientset, err = kubernetes.NewForConfig(cfg) + + // If this is a control pane host it will likely have started as a static pod or wont have the + // VIP up before trying to connect to the API server, we set the API endpoing to this machine to + // ensure connectivity. + if config.EnableControlPane { + // We modify the config so that we can always speak to the correct host + id, err := os.Hostname() + if err != nil { + return nil, err + } + cfg.Host = fmt.Sprintf("%s:%v", id, config.Port) + clientset, err = kubernetes.NewForConfig(cfg) + } + if err != nil { + return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) + } + } + + return &Manager{ + clientSet: clientset, + configMap: configMap, + config: config, + }, nil +} + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) Start() error { + + // If BGP is enabled then we start a server instance that will broadcast VIPs + if sm.config.EnableBGP { + log.Infoln("Starting Kube-vip loadBalancer Service with the BGP engine") + log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane) + return sm.startBGP() + } + + // If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs + if sm.config.EnableARP { + log.Infoln("Starting loadBalancer Service with the ARP engine") + log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane) + return sm.startARP() + } + + log.Infoln("Prematurely exiting Load-balancer as neither Layer2 or Layer3 is enabled") + return nil +} + +func returnNameSpace() (string, error) { + if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if ns := strings.TrimSpace(string(data)); len(ns) > 0 { + return ns, nil + } + return "", err + } + return "", fmt.Errorf("Unable to find Namespace") +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go new file mode 100644 index 00000000..fd43f7f1 --- /dev/null +++ b/pkg/manager/manager_arp.go @@ -0,0 +1,155 @@ +package manager + +import ( + "context" + "os" + "os/signal" + "strconv" + "syscall" + "time" + + "github.com/kamhlos/upnp" + "github.com/plunder-app/kube-vip/pkg/cluster" + 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" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startARP() error { + var cpCluster *cluster.Cluster + var ns string + var err error + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + signalChan := make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGTERM) + + // Add Notification for SIGKILL (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGKILL) + + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-signalChan + log.Info("Received termination, signaling shutdown") + if sm.config.EnableControlPane { + cpCluster.Stop() + } + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + if sm.config.EnableControlPane { + cpCluster, err = cluster.InitCluster(sm.config, false) + if err != nil { + return err + } + + clusterManager := &cluster.Manager{ + KubernetesClient: sm.clientSet, + } + + go func() { + cpCluster.StartLeaderCluster(sm.config, clusterManager) + if err != nil { + log.Errorf("Control Pane Error [%v]", err) + // Trigger the shutdown of this manager instance + signalChan <- syscall.SIGINT + + } + }() + + ns = sm.config.Namespace + } else { + ns, err = returnNameSpace() + if err != nil { + return err + } + } + + id, err := os.Hostname() + if err != nil { + return err + } + + // Before starting the leader Election enable any additional functionality + upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) + + if upnpEnabled { + sm.upnp = new(upnp.Upnp) + err := sm.upnp.ExternalIPAddr() + if err != nil { + log.Errorf("Error Enabling UPNP %s", err.Error()) + // Set the struct to nil so nothing should use it in future + sm.upnp = nil + } else { + log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + } + } + + log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: ns, + }, + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, + }, + } + + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + sm.servicesWatcher(ctx) + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + + //<-signalChan + log.Infof("Shutting down Kube-Vip") + + return nil +} diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go new file mode 100644 index 00000000..adb52246 --- /dev/null +++ b/pkg/manager/manager_bgp.go @@ -0,0 +1,103 @@ +package manager + +import ( + "context" + "os" + "os/signal" + "syscall" + + "github.com/packethost/packngo" + "github.com/plunder-app/kube-vip/pkg/bgp" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/packet" + log "github.com/sirupsen/logrus" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startBGP() error { + var cpCluster *cluster.Cluster + var ns string + var err error + + if sm.config.EnableControlPane { + cpCluster, err = cluster.InitCluster(sm.config, false) + if err != nil { + return err + } + + clusterManager := &cluster.Manager{ + KubernetesClient: sm.clientSet, + } + err = cpCluster.StartLeaderCluster(sm.config, clusterManager) + if err != nil { + return err + } + ns = sm.config.Namespace + } else { + ns, err = returnNameSpace() + if err != nil { + return err + } + } + + // If Packet is enabled then we can begin our preperation work + var packetClient *packngo.Client + if sm.config.EnablePacket { + packetClient, err = packngo.NewClient() + if err != nil { + log.Error(err) + } + + // We're using Packet with BGP, popuplate the Peer information from the API + if sm.config.EnableBGP { + log.Infoln("Looking up the BGP configuration from packet") + err = packet.BGPLookup(packetClient, sm.config) + if err != nil { + log.Error(err) + } + } + } + + log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + if err != nil { + return err + } + + // Defer a function to check if the bgpServer has been created and if so attempt to close it + defer func() { + if sm.bgpServer != nil { + sm.bgpServer.Close() + } + }() + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + signalChan = make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGTERM) + + // Add Notification for SIGKILL (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGKILL) + go func() { + <-signalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + sm.configmapWatcher(ctx, ns) + + log.Infof("Shutting down Kube-Vip") + + return nil +} diff --git a/pkg/manager/services.go b/pkg/manager/services.go new file mode 100644 index 00000000..b8e835c0 --- /dev/null +++ b/pkg/manager/services.go @@ -0,0 +1,273 @@ +package manager + +import ( + "context" + "fmt" + "net" + "strings" + + dhclient "github.com/digineo/go-dhclient" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (sm *Manager) stopService(uid string) error { + found := false + for x := range sm.serviceInstances { + if sm.serviceInstances[x].service.UID == uid { + found = true + sm.serviceInstances[x].cluster.Stop() + } + } + if found == false { + return fmt.Errorf("Unable to find/stop service [%s]", uid) + } + return nil +} + +func (sm *Manager) deleteService(uid string) error { + var updatedInstances []Instance + found := false + for x := range sm.serviceInstances { + // Add the running services to the new array + if sm.serviceInstances[x].service.UID != uid { + updatedInstances = append(updatedInstances, sm.serviceInstances[x]) + } else { + // Flip the found when we match + found = true + if sm.serviceInstances[x].dhcp != nil { + sm.serviceInstances[x].dhcp.dhcpClient.Stop() + macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcp.dhcpInterface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + netlink.LinkDel(macvlan) + } + if sm.serviceInstances[x].vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) + err := sm.bgpServer.DelHost(cidrVip) + return err + } + } + } + // If we've been through all services and not found the correct one then error + if found == false { + return fmt.Errorf("Unable to find/stop service [%s]", uid) + } + + // Update the service array + sm.serviceInstances = updatedInstances + + log.Debugf("Removed [%s] from manager, [%d] services remain", uid, len(sm.serviceInstances)) + + return nil +} + +func (sm *Manager) syncServices(s *kubernetesServices) error { + log.Debugf("[STARTING] Service Sync") + // Iterate through the synchronising services + for x := range s.Services { + foundInstance := false + for y := range sm.serviceInstances { + if s.Services[x].UID == sm.serviceInstances[y].service.UID { + // We have found this instance in the manager and we can update it + foundInstance = true + } + } + + // Generate new Virtual IP configuration + newVip := kubevip.Config{ + VIP: s.Services[x].Vip, + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, + } + + // This instance wasn't found, we need to add it to the manager + if foundInstance == false { + // Create new service + var newService Instance + + // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP + if s.Services[x].Vip == "0.0.0.0" { + + parent, err := netlink.LinkByName(sm.config.Interface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + + // Create macvlan + + // Generate name from UID + interfaceName := fmt.Sprintf("vip-%s", s.Services[x].UID[0:8]) + + // 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) + + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + + err = netlink.LinkAdd(mac) + if err != nil { + return fmt.Errorf("Could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) + } + iface, err = net.InterfaceByName(interfaceName) + if err != nil { + return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + + } + + client := dhclient.Client{ + Iface: iface, + OnBound: func(lease *dhclient.Lease) { + + // Set VIP to Address from lease + newVip.VIP = lease.FixedAddress.String() + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) + + // // Generate Load Balancer configu + // newLB := kubevip.LoadBalancer{ + // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + // Port: s.Services[x].Port, + // Type: s.Services[x].Type, + // BindToVip: true, + // } + + // // Add Load Balancer Configuration + // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + + // Create Add configuration to the new service + newService.vipConfig = newVip + newService.service = s.Services[x] + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) + //return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) + //return err + } + newService.cluster = *c + + // Begin watching this service + go sm.serviceWatcher(&newService, sm.config.Namespace) + + // Add new service to manager configuration + sm.serviceInstances = append(sm.serviceInstances, newService) + + // Update the service + ns, err := returnNameSpace() + if err != nil { + log.Errorf("Error finding Namespace") + return + } + dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.service.ServiceName, metav1.GetOptions{}) + if err != nil { + log.Errorf("Error finding Service [%s] : %v", newService.service.ServiceName, err) + return + } + dhcpService.Spec.LoadBalancerIP = newVip.VIP + updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) + log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) + if err != nil { + log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) + return + } + + sm.upnpMap(newService.service) + + }, + } + + newService.dhcp = &dhcpService{ + dhcpClient: &client, + dhcpInterface: interfaceName, + } + + // Start the DHCP Client + newService.dhcp.dhcpClient.Start() + + // Change the interface name to our new DHCP macvlan interface + newVip.Interface = interfaceName + log.Infof("DHCP Interface and Client is up and active [%s]", interfaceName) + return nil + + } + + log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) + + // Generate Load Balancer config + newLB := kubevip.LoadBalancer{ + Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + Port: s.Services[x].Port, + Type: s.Services[x].Type, + BindToVip: true, + } + + // Add Load Balancer Configuration + newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + + // Create Add configuration to the new service + newService.vipConfig = newVip + newService.service = s.Services[x] + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) + return err + } + + sm.upnpMap(s.Services[x]) + + newService.cluster = *c + + // Begin watching this service + go sm.serviceWatcher(&newService, sm.config.Namespace) + + // Add new service to manager configuration + sm.serviceInstances = append(sm.serviceInstances, newService) + } + } + log.Debugf("[COMPLETE] Service Sync") + + return nil +} + +func (sm *Manager) upnpMap(s service) { + // If upnp is enabled then update the gateway/router with the address + // TODO - work out if we need to mapping.Reclaim() + if sm.upnp != nil { + + log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) + if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + log.Infof("Service should be accessible externally on port [%d]", s.Port) + } else { + sm.upnp.Reclaim() + log.Errorf("Unable to map port to gateway [%s]", err.Error()) + } + } +} diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go new file mode 100644 index 00000000..1230c003 --- /dev/null +++ b/pkg/manager/watcher.go @@ -0,0 +1,224 @@ +package manager + +import ( + "context" + "encoding/json" + "fmt" + + log "github.com/sirupsen/logrus" + + "github.com/davecgh/go-spew/spew" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + watchtools "k8s.io/client-go/tools/watch" + + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" +) + +// The watcher will watch config maps for new services being created +func (sm *Manager) configmapWatcher(ctx context.Context, ns string) { + // Build a options structure to defined what we're looking for + listOptions := metav1.ListOptions{ + FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), + } + + // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) + }, + }) + + if err != nil { + log.Errorf("error creating watcher: %s", err.Error()) + ctx.Done() + } + + ch := rw.ResultChan() + defer rw.Stop() + log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) + + var services kubernetesServices + + go func() { + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) + cm, ok := event.Object.(*v1.ConfigMap) + if !ok { + log.Errorf("Unable to parse ConfigMap from watcher") + break + } + data := cm.Data["plndr-services"] + json.Unmarshal([]byte(data), &services) + log.Debugf("Found %d services defined in ConfigMap", len(services.Services)) + + err = sm.syncServices(&services) + if err != nil { + log.Errorf("%v", err) + } + case watch.Deleted: + log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Infoln("err") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + // Retry unknown errors + //return false, 0 + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + + default: + } + } + }() + + <-signalChan +} + +// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +func (sm *Manager) serviceWatcher(s *Instance, ns string) error { + // Build a options structure to defined what we're looking for + listOptions := metav1.ListOptions{ + FieldSelector: fmt.Sprintf("metadata.name=%s", s.service.ServiceName), + } + + // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), listOptions) + }, + }) + if err != nil { + return fmt.Errorf("error creating watcher: %s", err.Error()) + } + + ch := rw.ResultChan() + defer rw.Stop() + log.Infof("Beginning watching Kubernetes Endpoints for service [%s]", s.service.ServiceName) + + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + // ep, ok := event.Object.(*v1.Endpoints) + // if !ok { + // return fmt.Errorf("Unable to parse Endpoints from watcher") + // } + // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) + + // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) + case watch.Deleted: + log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) + log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) + // Stopping the service from running + sm.stopService(s.service.UID) + // Remove this service from the list of services we manage + sm.deleteService(s.service.UID) + return nil + case watch.Bookmark: + // Un-used + case watch.Error: + log.Infoln("err") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + // Retry unknown errors + //return false, 0 + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + return nil +} + +// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +func (sm *Manager) servicesWatcher(ctx context.Context) error { + // Build a options structure to defined what we're looking for + // listOptions := metav1.ListOptions{ + // FieldSelector: fields.S, + // } + + // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + return fmt.Errorf("error creating services watcher: %s", err.Error()) + } + + ch := rw.ResultChan() + defer rw.Stop() + log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") + + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + log.Infof("Found Service [%s], it has [%d] external addresses", svc.Name, len(svc.Status.LoadBalancer.Ingress)) + // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) + + // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) + case watch.Deleted: + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("Unable to parse Endpoints from watcher") + } + log.Debugf("Endpoints for service [%s] have been Deleted", svc.Name) + log.Infof("Service [%s] has been deleted, stopping VIP", svc.Name) + + return nil + case watch.Bookmark: + // Un-used + case watch.Error: + log.Infoln("err") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + // Retry unknown errors + //return false, 0 + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + return nil +} From 8b480c3688eea48de5757fcec45ebcbf49415d42 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 25 Nov 2020 18:55:56 +0000 Subject: [PATCH 024/542] Now will succesfully manage loadbalancers --- cmd/kube-vip-start.go | 20 ++- pkg/cluster/clusterLeader.go | 97 ++++++++++- pkg/manager/manager.go | 31 ++-- pkg/manager/manager_arp.go | 2 +- pkg/manager/manager_bgp.go | 42 +++-- pkg/manager/services.go | 317 ++++++++++++++++++----------------- pkg/manager/watcher.go | 299 +++++++++++++++++---------------- 7 files changed, 462 insertions(+), 346 deletions(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index cd670d3e..615c0828 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -4,6 +4,7 @@ import ( "os" "os/signal" + "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" @@ -76,7 +77,7 @@ var kubeVipStart = &cobra.Command{ if err != nil { log.Fatalf("%v", err) } - + var bgpServer *bgp.Server if startConfig.SingleNode { // If the Virtual IP isn't disabled then create the netlink configuration // Start a single node cluster @@ -92,8 +93,23 @@ var kubeVipStart = &cobra.Command{ log.Fatalf("%v", err) } + if startConfig.EnableBGP { + log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + bgpServer, err = bgp.NewBGPServer(&startConfig.BGPConfig) + if err != nil { + log.Fatalf("%v", err) + } + + // Defer a function to check if the bgpServer has been created and if so attempt to close it + defer func() { + if bgpServer != nil { + bgpServer.Close() + } + }() + } + // Leader Cluster will block - err = newCluster.StartLeaderCluster(&startConfig, cm) + err = newCluster.StartLeaderCluster(&startConfig, cm, bgpServer) if err != nil { log.Fatalf("%v", err) } diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index f9c85f9c..b2c72df8 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -78,7 +78,7 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { } // StartLeaderCluster - Begins a running instance of the Raft cluster -func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error { +func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error { id, err := os.Hostname() if err != nil { @@ -143,8 +143,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error nonVipLB := loadbalancer.LBManager{} VipLB := loadbalancer.LBManager{} - // BGP server - var bgpServer *bgp.Server // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { if bgpServer != nil { @@ -345,3 +343,96 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager) error return nil } + +// TODO - refactor an active machine func(), this will replace the singleNode code and have a single code block + +// func (cluster *Cluster) active(c *kubevip.Config) error { +// // we're notified when we start +// log.Info("This node is starting with leadership of the cluster") +// // setup ddns first +// // for first time, need to wait until IP is allocated from DHCP +// if cluster.Network.IsDDNS() { +// if err := cluster.StartDDNS(ctxDns); err != nil { +// log.Error(err) +// } +// } + +// // start the dns updater if address is dns +// if cluster.Network.IsDNS() { +// log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) +// ipUpdater := vip.NewIPUpdater(cluster.Network) +// ipUpdater.Run(ctxDns) +// } + +// err := cluster.Network.AddIP() +// if err != nil { +// log.Warnf("%v", err) +// } + +// if c.EnablePacket { +// // We're not using Packet with BGP +// if !c.EnableBGP { +// // Attempt to attach the EIP in the standard manner +// log.Debugf("Attaching the Packet EIP through the API to this host") +// err = packet.AttachEIP(packetClient, c, id) +// if err != nil { +// log.Error(err) +// } +// } +// } + +// 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.IP(), c.VIPCIDR) +// log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) + +// err = bgpServer.AddHost(cidrVip) +// if err != nil { +// log.Error(err) +// } +// } + +// if c.EnableLoadBalancer { +// // Once we have the VIP running, start the load balancer(s) that bind to the VIP +// for x := range c.LoadBalancers { + +// if c.LoadBalancers[x].BindToVip == true { +// err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) +// if err != nil { +// log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) + +// // Stop all load balancers associated with the VIP +// err = VipLB.StopAll() +// if err != nil { +// log.Warnf("%v", err) +// } + +// err = cluster.Network.DeleteIP() +// if err != nil { +// log.Warnf("%v", err) +// } +// } +// } +// } +// } + +// if c.EnableARP == true { +// ctxArp, cancelArp = context.WithCancel(context.Background()) + +// go func(ctx context.Context) { +// for { +// select { +// case <-ctx.Done(): // if cancel() execute +// return +// default: +// // Gratuitous ARP, will broadcast to new MAC <-> IP +// err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) +// if err != nil { +// log.Warnf("%v", err) +// } +// } +// time.Sleep(3 * time.Second) +// } +// }(ctxArp) +// } +// } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 264e8779..d5c14c7c 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -25,10 +25,6 @@ var signalChan chan os.Signal // OutSideCluster allows the controller to be started using a local kubeConfig for testing var OutSideCluster bool -type kubernetesServices struct { - Services []service `json:"services"` -} - // Manager degines the manager of the load-balancing services type Manager struct { clientSet *kubernetes.Clientset @@ -57,25 +53,32 @@ type dhcpService struct { type Instance struct { // Virtual IP / Load Balancer configuration vipConfig kubevip.Config - // Kubernetes service mapping - service service + // cluster instance cluster cluster.Cluster // Custom settings dhcp *dhcpService -} -// TODO - call from a package (duplicated struct in the cloud-provider code) -type service struct { - Vip string `json:"vip"` - Port int `json:"port"` - UID string `json:"uid"` - Type string `json:"type"` + // Kubernetes service mapping + Vip string + Port int32 + UID string + Type string - ServiceName string `json:"serviceName"` + ServiceName string } +// // TODO - call from a package (duplicated struct in the cloud-provider code) +// type service struct { +// Vip string `json:"vip"` +// Port int32 `json:"port"` +// UID string `json:"uid"` +// Type string `json:"type"` + +// ServiceName string `json:"serviceName"` +// } + // SetControlPane determines if the control plane should be enabled // func (sm *Manager) SetControlPane(enable bool) { // sm.controlPane = enable diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index fd43f7f1..c24a77eb 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -62,7 +62,7 @@ func (sm *Manager) startARP() error { } go func() { - cpCluster.StartLeaderCluster(sm.config, clusterManager) + cpCluster.StartLeaderCluster(sm.config, clusterManager, nil) if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index adb52246..feaee182 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -16,30 +16,9 @@ import ( // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) startBGP() error { var cpCluster *cluster.Cluster - var ns string + //var ns string var err error - if sm.config.EnableControlPane { - cpCluster, err = cluster.InitCluster(sm.config, false) - if err != nil { - return err - } - - clusterManager := &cluster.Manager{ - KubernetesClient: sm.clientSet, - } - err = cpCluster.StartLeaderCluster(sm.config, clusterManager) - if err != nil { - return err - } - ns = sm.config.Namespace - } else { - ns, err = returnNameSpace() - if err != nil { - return err - } - } - // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client if sm.config.EnablePacket { @@ -71,6 +50,23 @@ func (sm *Manager) startBGP() error { } }() + if sm.config.EnableControlPane { + cpCluster, err = cluster.InitCluster(sm.config, false) + if err != nil { + return err + } + err = cpCluster.StartLoadBalancerService(sm.config, sm.bgpServer) + if err != nil { + return err + } + // ns = sm.config.Namespace + // } else { + // ns, err = returnNameSpace() + // if err != nil { + // return err + // } + } + // use a Go context so we can tell the leaderelection code when we // want to step down ctx, cancel := context.WithCancel(context.Background()) @@ -95,7 +91,7 @@ func (sm *Manager) startBGP() error { cancel() }() - sm.configmapWatcher(ctx, ns) + sm.servicesWatcher(ctx) log.Infof("Shutting down Kube-Vip") diff --git a/pkg/manager/services.go b/pkg/manager/services.go index b8e835c0..30e18437 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -11,13 +11,14 @@ import ( "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func (sm *Manager) stopService(uid string) error { found := false for x := range sm.serviceInstances { - if sm.serviceInstances[x].service.UID == uid { + if sm.serviceInstances[x].UID == uid { found = true sm.serviceInstances[x].cluster.Stop() } @@ -33,7 +34,7 @@ func (sm *Manager) deleteService(uid string) error { found := false for x := range sm.serviceInstances { // Add the running services to the new array - if sm.serviceInstances[x].service.UID != uid { + if sm.serviceInstances[x].UID != uid { updatedInstances = append(updatedInstances, sm.serviceInstances[x]) } else { // Flip the found when we match @@ -61,209 +62,217 @@ func (sm *Manager) deleteService(uid string) error { // Update the service array sm.serviceInstances = updatedInstances - log.Debugf("Removed [%s] from manager, [%d] services remain", uid, len(sm.serviceInstances)) + log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances)) return nil } -func (sm *Manager) syncServices(s *kubernetesServices) error { +func (sm *Manager) syncServices(service *v1.Service) error { log.Debugf("[STARTING] Service Sync") // Iterate through the synchronising services - for x := range s.Services { - foundInstance := false - for y := range sm.serviceInstances { - if s.Services[x].UID == sm.serviceInstances[y].service.UID { - // We have found this instance in the manager and we can update it - foundInstance = true - } - } + foundInstance := false + newServiceAddress := service.Status.LoadBalancer.Ingress[0].IP + newServiceUID := string(service.UID) - // Generate new Virtual IP configuration - newVip := kubevip.Config{ - VIP: s.Services[x].Vip, - Interface: sm.config.Interface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + // We have found this instance in the manager, we can determine if it needs updating + foundInstance = true } - // This instance wasn't found, we need to add it to the manager - if foundInstance == false { - // Create new service - var newService Instance + } + + // Generate new Virtual IP configuration + newVip := kubevip.Config{ + VIP: newServiceAddress, //TODO support more than one vip? + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, + } + + // This instance wasn't found, we need to add it to the manager + if foundInstance == false { + // Create new service + var newService Instance + newService.UID = newServiceUID + newService.Vip = newServiceAddress + newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types + newService.Port = service.Spec.Ports[0].Port + newService.ServiceName = service.Name - // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP - if s.Services[x].Vip == "0.0.0.0" { + // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP + if newServiceAddress == "0.0.0.0" { - parent, err := netlink.LinkByName(sm.config.Interface) + parent, err := netlink.LinkByName(sm.config.Interface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + + // Create macvlan + + // Generate name from UID + interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) + + // 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) + + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + + err = netlink.LinkAdd(mac) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + return fmt.Errorf("Could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) } + iface, err = net.InterfaceByName(interfaceName) + if err != nil { + return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + + } - // Create macvlan + client := dhclient.Client{ + Iface: iface, + OnBound: func(lease *dhclient.Lease) { - // Generate name from UID - interfaceName := fmt.Sprintf("vip-%s", s.Services[x].UID[0:8]) + // Set VIP to Address from lease + newVip.VIP = lease.FixedAddress.String() + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, service.Name, newServiceUID) - // 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) + // // Generate Load Balancer configu + // newLB := kubevip.LoadBalancer{ + // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + // Port: s.Services[x].Port, + // Type: s.Services[x].Type, + // BindToVip: true, + // } + + // // Add Load Balancer Configuration + // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + // Create Add configuration to the new service + newService.vipConfig = newVip - err = netlink.LinkAdd(mac) + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + //return err } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + //return err + } + newService.cluster = *c + + // Begin watching this service + // TODO - we may need this + // go sm.serviceWatcher(&newService, sm.config.Namespace) + + // Add new service to manager configuration + sm.serviceInstances = append(sm.serviceInstances, newService) - err = netlink.LinkSetUp(mac) + // Update the service + ns, err := returnNameSpace() if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) + log.Errorf("Error finding Namespace") + return } - iface, err = net.InterfaceByName(interfaceName) + dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.ServiceName, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + log.Errorf("Error finding Service [%s] : %v", newService.ServiceName, err) + return + } + dhcpService.Spec.LoadBalancerIP = newVip.VIP + updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) + log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) + if err != nil { + log.Errorf("Error updating Service [%s] : %v", newService.ServiceName, err) + return } - } else { - log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) - } + sm.upnpMap(newService) - client := dhclient.Client{ - Iface: iface, - OnBound: func(lease *dhclient.Lease) { - - // Set VIP to Address from lease - newVip.VIP = lease.FixedAddress.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) - - // // Generate Load Balancer configu - // newLB := kubevip.LoadBalancer{ - // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - // Port: s.Services[x].Port, - // Type: s.Services[x].Type, - // BindToVip: true, - // } - - // // Add Load Balancer Configuration - // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = newVip - newService.service = s.Services[x] - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) - //return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) - //return err - } - newService.cluster = *c - - // Begin watching this service - go sm.serviceWatcher(&newService, sm.config.Namespace) - - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) - - // Update the service - ns, err := returnNameSpace() - if err != nil { - log.Errorf("Error finding Namespace") - return - } - dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.service.ServiceName, metav1.GetOptions{}) - if err != nil { - log.Errorf("Error finding Service [%s] : %v", newService.service.ServiceName, err) - return - } - dhcpService.Spec.LoadBalancerIP = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) - log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) - if err != nil { - log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) - return - } - - sm.upnpMap(newService.service) - - }, - } + }, + } - newService.dhcp = &dhcpService{ - dhcpClient: &client, - dhcpInterface: interfaceName, - } + newService.dhcp = &dhcpService{ + dhcpClient: &client, + dhcpInterface: interfaceName, + } - // Start the DHCP Client - newService.dhcp.dhcpClient.Start() + // Start the DHCP Client + newService.dhcp.dhcpClient.Start() - // Change the interface name to our new DHCP macvlan interface - newVip.Interface = interfaceName - log.Infof("DHCP Interface and Client is up and active [%s]", interfaceName) - return nil + // Change the interface name to our new DHCP macvlan interface + newVip.Interface = interfaceName + log.Infof("DHCP Interface and Client is up and active [%s]", interfaceName) + return nil - } + } - log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) + log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceName, newService.UID) - // Generate Load Balancer config - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - Port: s.Services[x].Port, - Type: s.Services[x].Type, - BindToVip: true, - } + // Generate Load Balancer config + newLB := kubevip.LoadBalancer{ + Name: fmt.Sprintf("%s-load-balancer", newService.ServiceName), + Port: int(newService.Port), + Type: newService.Type, + BindToVip: true, + } - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + // Add Load Balancer Configuration + newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - // Create Add configuration to the new service - newService.vipConfig = newVip - newService.service = s.Services[x] + // Create Add configuration to the new service + newService.vipConfig = newVip - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + return err + } - sm.upnpMap(s.Services[x]) + sm.upnpMap(newService) - newService.cluster = *c + newService.cluster = *c - // Begin watching this service - go sm.serviceWatcher(&newService, sm.config.Namespace) + // Begin watching this service + // TODO - we may need this + // go sm.serviceWatcher(&newService, sm.config.Namespace) - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) - } + // Add new service to manager configuration + sm.serviceInstances = append(sm.serviceInstances, newService) } + log.Debugf("[COMPLETE] Service Sync") return nil } -func (sm *Manager) upnpMap(s service) { +func (sm *Manager) upnpMap(s Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() if sm.upnp != nil { log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) - if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { log.Infof("Service should be accessible externally on port [%d]", s.Port) } else { sm.upnp.Reclaim() diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 1230c003..3b5195b9 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -2,7 +2,6 @@ package manager import ( "context" - "encoding/json" "fmt" log "github.com/sirupsen/logrus" @@ -17,144 +16,144 @@ import ( "k8s.io/client-go/tools/cache" ) -// The watcher will watch config maps for new services being created -func (sm *Manager) configmapWatcher(ctx context.Context, ns string) { - // Build a options structure to defined what we're looking for - listOptions := metav1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), - } - - // Watch function - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) - }, - }) - - if err != nil { - log.Errorf("error creating watcher: %s", err.Error()) - ctx.Done() - } - - ch := rw.ResultChan() - defer rw.Stop() - log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) - - var services kubernetesServices - - go func() { - for event := range ch { - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) - cm, ok := event.Object.(*v1.ConfigMap) - if !ok { - log.Errorf("Unable to parse ConfigMap from watcher") - break - } - data := cm.Data["plndr-services"] - json.Unmarshal([]byte(data), &services) - log.Debugf("Found %d services defined in ConfigMap", len(services.Services)) - - err = sm.syncServices(&services) - if err != nil { - log.Errorf("%v", err) - } - case watch.Deleted: - log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Infoln("err") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - - default: - } - } - }() - - <-signalChan -} - -// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -func (sm *Manager) serviceWatcher(s *Instance, ns string) error { - // Build a options structure to defined what we're looking for - listOptions := metav1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", s.service.ServiceName), - } - - // Watch function - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), listOptions) - }, - }) - if err != nil { - return fmt.Errorf("error creating watcher: %s", err.Error()) - } - - ch := rw.ResultChan() - defer rw.Stop() - log.Infof("Beginning watching Kubernetes Endpoints for service [%s]", s.service.ServiceName) - - for event := range ch { - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - // ep, ok := event.Object.(*v1.Endpoints) - // if !ok { - // return fmt.Errorf("Unable to parse Endpoints from watcher") - // } - // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) - - // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) - case watch.Deleted: - log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) - log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) - // Stopping the service from running - sm.stopService(s.service.UID) - // Remove this service from the list of services we manage - sm.deleteService(s.service.UID) - return nil - case watch.Bookmark: - // Un-used - case watch.Error: - log.Infoln("err") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - default: - } - } - return nil -} +// // The watcher will watch config maps for new services being created +// func (sm *Manager) configmapWatcher(ctx context.Context, ns string) { +// // Build a options structure to defined what we're looking for +// listOptions := metav1.ListOptions{ +// FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), +// } + +// // Watch function +// // Use a restartable watcher, as this should help in the event of etcd or timeout issues +// rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ +// WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { +// return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) +// }, +// }) + +// if err != nil { +// log.Errorf("error creating watcher: %s", err.Error()) +// ctx.Done() +// } + +// ch := rw.ResultChan() +// defer rw.Stop() +// log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) + +// var services kubernetesServices + +// go func() { +// for event := range ch { + +// // We need to inspect the event and get ResourceVersion out of it +// switch event.Type { +// case watch.Added, watch.Modified: +// log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) +// cm, ok := event.Object.(*v1.ConfigMap) +// if !ok { +// log.Errorf("Unable to parse ConfigMap from watcher") +// break +// } +// data := cm.Data["plndr-services"] +// json.Unmarshal([]byte(data), &services) +// log.Debugf("Found %d services defined in ConfigMap", len(services.Services)) + +// err = sm.syncServices(&services) +// if err != nil { +// log.Errorf("%v", err) +// } +// case watch.Deleted: +// log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) + +// case watch.Bookmark: +// // Un-used +// case watch.Error: +// log.Infoln("err") + +// // This round trip allows us to handle unstructured status +// errObject := apierrors.FromObject(event.Object) +// statusErr, ok := errObject.(*apierrors.StatusError) +// if !ok { +// log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) +// // Retry unknown errors +// //return false, 0 +// } + +// status := statusErr.ErrStatus +// log.Errorf("%v", status) + +// default: +// } +// } +// }() + +// <-signalChan +// } + +// // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +// func (sm *Manager) serviceWatcher(s *Instance, ns string) error { +// // Build a options structure to defined what we're looking for +// listOptions := metav1.ListOptions{ +// FieldSelector: fmt.Sprintf("metadata.name=%s", s.service.ServiceName), +// } + +// // Watch function +// // Use a restartable watcher, as this should help in the event of etcd or timeout issues +// rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ +// WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { +// return sm.clientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), listOptions) +// }, +// }) +// if err != nil { +// return fmt.Errorf("error creating watcher: %s", err.Error()) +// } + +// ch := rw.ResultChan() +// defer rw.Stop() +// log.Infof("Beginning watching Kubernetes Endpoints for service [%s]", s.service.ServiceName) + +// for event := range ch { + +// // We need to inspect the event and get ResourceVersion out of it +// switch event.Type { +// case watch.Added, watch.Modified: +// // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) +// // ep, ok := event.Object.(*v1.Endpoints) +// // if !ok { +// // return fmt.Errorf("Unable to parse Endpoints from watcher") +// // } +// // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) + +// // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) +// case watch.Deleted: +// log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) +// log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) +// // Stopping the service from running +// sm.stopService(s.service.UID) +// // Remove this service from the list of services we manage +// sm.deleteService(s.service.UID) +// return nil +// case watch.Bookmark: +// // Un-used +// case watch.Error: +// log.Infoln("err") + +// // This round trip allows us to handle unstructured status +// errObject := apierrors.FromObject(event.Object) +// statusErr, ok := errObject.(*apierrors.StatusError) +// if !ok { +// log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) +// // Retry unknown errors +// //return false, 0 +// } + +// status := statusErr.ErrStatus +// log.Errorf("%v", status) +// default: +// } +// } +// return nil +// } // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context) error { @@ -189,30 +188,31 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } log.Infof("Found Service [%s], it has [%d] external addresses", svc.Name, len(svc.Status.LoadBalancer.Ingress)) - // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) + if len(svc.Status.LoadBalancer.Ingress) > 0 { + err = sm.syncServices(svc) + if err != nil { + log.Error(err) + } + } - // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { - return fmt.Errorf("Unable to parse Endpoints from watcher") + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - log.Debugf("Endpoints for service [%s] have been Deleted", svc.Name) - log.Infof("Service [%s] has been deleted, stopping VIP", svc.Name) + sm.deleteService(string(svc.UID)) - return nil case watch.Bookmark: // Un-used case watch.Error: - log.Infoln("err") + log.Error("Error attempting to watch Kubernetes services") // This round trip allows us to handle unstructured status errObject := apierrors.FromObject(event.Object) statusErr, ok := errObject.(*apierrors.StatusError) if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + } status := statusErr.ErrStatus @@ -220,5 +220,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { default: } } + log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } From 06bc786caa7c248b3328036d6dccdce884143151 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 26 Nov 2020 13:29:55 +0000 Subject: [PATCH 025/542] Updated manifests and fixes to flags --- cmd/kube-vip-start.go | 2 + cmd/kube-vip.go | 6 +- docs/manifests/kube-vip-arp.yaml | 85 ++++++++++++++++++ docs/manifests/kube-vip-bgp.yaml | 90 +++++++++++++++++++ pkg/kubevip/config_generator.go | 20 ++++- pkg/kubevip/config_types.go | 2 +- pkg/manager/manager.go | 84 +++++++----------- pkg/manager/services.go | 2 +- pkg/manager/watcher.go | 145 +------------------------------ 9 files changed, 229 insertions(+), 207 deletions(-) create mode 100644 docs/manifests/kube-vip-arp.yaml create mode 100644 docs/manifests/kube-vip-bgp.yaml diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 615c0828..20b51375 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -47,6 +47,8 @@ func init() { kubeVipStart.Flags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") kubeVipStart.Flags().BoolVar(&startConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") + // This sets the namespace that the lock should exist in + kubeVipStart.Flags().StringVarP(&startConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") } var kubeVipStart = &cobra.Command{ diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1ad9fc96..e81c5c71 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -95,15 +95,14 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") // Control plane specific flags - kubeVipService.Flags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") + kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") // Manage logging kubeVipCmd.PersistentFlags().Uint32Var(&logLevel, "log", 4, "Set the level of logging") // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") - kubeVipService.Flags().BoolVar(&manager.OutSideCluster, "OutSideCluster", false, "Start Controller outside of cluster") - kubeVipService.Flags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) @@ -158,7 +157,6 @@ var kubeVipService = &cobra.Command{ } // User Environment variables as an option to make manifest clearer - envConfigMap := os.Getenv("vip_configmap") if envConfigMap != "" { configMap = envConfigMap diff --git a/docs/manifests/kube-vip-arp.yaml b/docs/manifests/kube-vip-arp.yaml new file mode 100644 index 00000000..503b23f4 --- /dev/null +++ b/docs/manifests/kube-vip-arp.yaml @@ -0,0 +1,85 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-vip + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:kube-vip-role +rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update", "list", "put"] + - apiGroups: [""] + resources: ["services"] + verbs: ["list","get","watch", "update"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:kube-vip-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-vip-role +subjects: +- kind: ServiceAccount + name: kube-vip + namespace: kube-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: kube-vip-workers + name: kube-vip-workers + namespace: kube-system +spec: + replicas: 3 + selector: + matchLabels: + app: kube-vip-workers + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: kube-vip-workers + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - kube-vip-workers + topologyKey: "kubernetes.io/hostname" + containers: + - image: plndr/kube-vip:0.2.2 + imagePullPolicy: Always + name: kube-vip + command: + - /kube-vip + - service + env: + - name: vip_interface + value: "ens160" + - name: vip_arp + value: "true" + - name: vip_loglevel + value: "5" + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + hostNetwork: true + serviceAccountName: kube-vip +status: {} diff --git a/docs/manifests/kube-vip-bgp.yaml b/docs/manifests/kube-vip-bgp.yaml new file mode 100644 index 00000000..83b43e71 --- /dev/null +++ b/docs/manifests/kube-vip-bgp.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-vip + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:kube-vip-role +rules: + - apiGroups: [""] + resources: ["services"] + verbs: ["list","get","watch", "update"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:kube-vip-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-vip-role +subjects: +- kind: ServiceAccount + name: kube-vip + namespace: kube-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: kube-vip-workers + name: kube-vip-workers + namespace: kube-system +spec: + replicas: 3 + selector: + matchLabels: + app: kube-vip-workers + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: kube-vip-workers + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - kube-vip-workers + topologyKey: "kubernetes.io/hostname" + containers: + - image: plndr/kube-vip:0.2.2 + imagePullPolicy: Always + name: kube-vip + command: + - /kube-vip + - service + env: + - name: vip_interface + value: "lo" + - name: bgp_enable + value: "true" + - name: vip_loglevel + value: "5" + - name: bgp_routerinterface + value: "ens160" + - name: bgp_as + value: "64512" + - name: bgp_peeraddress + value: "192.168.0.1" + - name: bgp_peeras + value: "64512" + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + hostNetwork: true + serviceAccountName: kube-vip +status: {} \ No newline at end of file diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 29005f44..f136125d 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -477,7 +477,7 @@ func parseEnvironmentLoadBalancer(c *Config) error { // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { - + command := "start" // build environment variables newEnvironment := []corev1.EnvVar{ { @@ -503,6 +503,22 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { } + // If we're doing the hybrid mode + if c.EnableControlPane { + command = "service" + cp := []corev1.EnvVar{ + { + Name: cpEnable, + Value: strconv.FormatBool(c.EnableControlPane), + }, + { + Name: cpNamespace, + Value: c.Namespace, + }, + } + newEnvironment = append(newEnvironment, cp...) + } + // If Leader election is enabled then add the configuration to the manifest if c.EnableLeaderElection { // Generate Kubernetes Leader Election configuration @@ -692,7 +708,7 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { }, }, Args: []string{ - "start", + command, }, Env: newEnvironment, VolumeMounts: []corev1.VolumeMount{ diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index dd45bf2c..436d7572 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -9,7 +9,7 @@ import ( // Config defines all of the settings for the Kube-Vip Pod type Config struct { - // EnableARP, will use BGP to advertise the VIP address + // EnableARP, will use ARP to advertise the VIP address EnableARP bool `yaml:"enableARP"` // EnableBGP, will use BGP to advertise the VIP address diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index d5c14c7c..8f518cbe 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -22,9 +22,6 @@ const plunderLock = "plndr-svcs-lock" var signalChan chan os.Signal -// OutSideCluster allows the controller to be started using a local kubeConfig for testing -var OutSideCluster bool - // Manager degines the manager of the load-balancing services type Manager struct { clientSet *kubernetes.Clientset @@ -69,78 +66,55 @@ type Instance struct { ServiceName string } -// // TODO - call from a package (duplicated struct in the cloud-provider code) -// type service struct { -// Vip string `json:"vip"` -// Port int32 `json:"port"` -// UID string `json:"uid"` -// Type string `json:"type"` - -// ServiceName string `json:"serviceName"` -// } - -// SetControlPane determines if the control plane should be enabled -// func (sm *Manager) SetControlPane(enable bool) { -// sm.controlPane = enable -// } - // New will create a new managing object func New(configMap string, config *kubevip.Config) (*Manager, error) { var clientset *kubernetes.Clientset - if OutSideCluster == false || !config.EnableControlPane { - // This will attempt to load the configuration when running within a POD - cfg, err := rest.InClusterConfig() - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) - } - clientset, err = kubernetes.NewForConfig(cfg) + var configPath string + var cfg *rest.Config + var err error + + configPath = "/etc/kubernetes/admin.conf" + if fileExists(configPath) { + cfg, err = clientcmd.BuildConfigFromFlags("", configPath) if err != nil { - log.Debugln("Using incluster Kubernetes configuration") - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) + return nil, err } - // use the current context in kubeconfig + log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) } else { - // Check for file existing - // First for default path on control plane - // /etc/kubernetes/admin.conf - var configPath string - var cfg *rest.Config - var err error - - configPath = "/etc/kubernetes/admin.conf" + // Second check in home directory for kube config + configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") if fileExists(configPath) { + log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) cfg, err = clientcmd.BuildConfigFromFlags("", configPath) if err != nil { return nil, err } } else { - // Second check in home directory for kube config - configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") - cfg, err = clientcmd.BuildConfigFromFlags("", configPath) + cfg, err = rest.InClusterConfig() if err != nil { - return nil, err + return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) } + log.Debugf("Using the internal Kubernetes token") } + } - log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) - clientset, err = kubernetes.NewForConfig(cfg) + clientset, err = kubernetes.NewForConfig(cfg) - // If this is a control pane host it will likely have started as a static pod or wont have the - // VIP up before trying to connect to the API server, we set the API endpoing to this machine to - // ensure connectivity. - if config.EnableControlPane { - // We modify the config so that we can always speak to the correct host - id, err := os.Hostname() - if err != nil { - return nil, err - } - cfg.Host = fmt.Sprintf("%s:%v", id, config.Port) - clientset, err = kubernetes.NewForConfig(cfg) - } + // If this is a control pane host it will likely have started as a static pod or wont have the + // VIP up before trying to connect to the API server, we set the API endpoint to this machine to + // ensure connectivity. + if config.EnableControlPane { + // We modify the config so that we can always speak to the correct host + id, err := os.Hostname() if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) + return nil, err } + cfg.Host = fmt.Sprintf("%s:%v", id, config.Port) + clientset, err = kubernetes.NewForConfig(cfg) + } + if err != nil { + return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) } return &Manager{ diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 30e18437..5dfa8e9b 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -148,7 +148,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { newVip.VIP = lease.FixedAddress.String() log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, service.Name, newServiceUID) - // // Generate Load Balancer configu + // // Generate Load Balancer config // newLB := kubevip.LoadBalancer{ // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), // Port: s.Services[x].Port, diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 3b5195b9..4fdddfea 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -16,153 +16,10 @@ import ( "k8s.io/client-go/tools/cache" ) -// // The watcher will watch config maps for new services being created -// func (sm *Manager) configmapWatcher(ctx context.Context, ns string) { -// // Build a options structure to defined what we're looking for -// listOptions := metav1.ListOptions{ -// FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), -// } - -// // Watch function -// // Use a restartable watcher, as this should help in the event of etcd or timeout issues -// rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ -// WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { -// return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) -// }, -// }) - -// if err != nil { -// log.Errorf("error creating watcher: %s", err.Error()) -// ctx.Done() -// } - -// ch := rw.ResultChan() -// defer rw.Stop() -// log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) - -// var services kubernetesServices - -// go func() { -// for event := range ch { - -// // We need to inspect the event and get ResourceVersion out of it -// switch event.Type { -// case watch.Added, watch.Modified: -// log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) -// cm, ok := event.Object.(*v1.ConfigMap) -// if !ok { -// log.Errorf("Unable to parse ConfigMap from watcher") -// break -// } -// data := cm.Data["plndr-services"] -// json.Unmarshal([]byte(data), &services) -// log.Debugf("Found %d services defined in ConfigMap", len(services.Services)) - -// err = sm.syncServices(&services) -// if err != nil { -// log.Errorf("%v", err) -// } -// case watch.Deleted: -// log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) - -// case watch.Bookmark: -// // Un-used -// case watch.Error: -// log.Infoln("err") - -// // This round trip allows us to handle unstructured status -// errObject := apierrors.FromObject(event.Object) -// statusErr, ok := errObject.(*apierrors.StatusError) -// if !ok { -// log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) -// // Retry unknown errors -// //return false, 0 -// } - -// status := statusErr.ErrStatus -// log.Errorf("%v", status) - -// default: -// } -// } -// }() - -// <-signalChan -// } - -// // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -// func (sm *Manager) serviceWatcher(s *Instance, ns string) error { -// // Build a options structure to defined what we're looking for -// listOptions := metav1.ListOptions{ -// FieldSelector: fmt.Sprintf("metadata.name=%s", s.service.ServiceName), -// } - -// // Watch function -// // Use a restartable watcher, as this should help in the event of etcd or timeout issues -// rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ -// WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { -// return sm.clientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), listOptions) -// }, -// }) -// if err != nil { -// return fmt.Errorf("error creating watcher: %s", err.Error()) -// } - -// ch := rw.ResultChan() -// defer rw.Stop() -// log.Infof("Beginning watching Kubernetes Endpoints for service [%s]", s.service.ServiceName) - -// for event := range ch { - -// // We need to inspect the event and get ResourceVersion out of it -// switch event.Type { -// case watch.Added, watch.Modified: -// // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) -// // ep, ok := event.Object.(*v1.Endpoints) -// // if !ok { -// // return fmt.Errorf("Unable to parse Endpoints from watcher") -// // } -// // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) - -// // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) -// case watch.Deleted: -// log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) -// log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) -// // Stopping the service from running -// sm.stopService(s.service.UID) -// // Remove this service from the list of services we manage -// sm.deleteService(s.service.UID) -// return nil -// case watch.Bookmark: -// // Un-used -// case watch.Error: -// log.Infoln("err") - -// // This round trip allows us to handle unstructured status -// errObject := apierrors.FromObject(event.Object) -// statusErr, ok := errObject.(*apierrors.StatusError) -// if !ok { -// log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) -// // Retry unknown errors -// //return false, 0 -// } - -// status := statusErr.ErrStatus -// log.Errorf("%v", status) -// default: -// } -// } -// return nil -// } - // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context) error { - // Build a options structure to defined what we're looking for - // listOptions := metav1.ListOptions{ - // FieldSelector: fields.S, - // } - // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { From 4178a31de78a1fd100c121cc3644eadf6056aef5 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 26 Nov 2020 19:11:41 +0000 Subject: [PATCH 026/542] Ensures that BGP Manager isn't blocked cntrl plane --- pkg/manager/manager_bgp.go | 65 +++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index feaee182..5623f3f1 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -42,31 +42,6 @@ func (sm *Manager) startBGP() error { if err != nil { return err } - - // Defer a function to check if the bgpServer has been created and if so attempt to close it - defer func() { - if sm.bgpServer != nil { - sm.bgpServer.Close() - } - }() - - if sm.config.EnableControlPane { - cpCluster, err = cluster.InitCluster(sm.config, false) - if err != nil { - return err - } - err = cpCluster.StartLoadBalancerService(sm.config, sm.bgpServer) - if err != nil { - return err - } - // ns = sm.config.Namespace - // } else { - // ns, err = returnNameSpace() - // if err != nil { - // return err - // } - } - // use a Go context so we can tell the leaderelection code when we // want to step down ctx, cancel := context.WithCancel(context.Background()) @@ -91,6 +66,46 @@ func (sm *Manager) startBGP() error { cancel() }() + // Defer a function to check if the bgpServer has been created and if so attempt to close it + defer func() { + if sm.bgpServer != nil { + sm.bgpServer.Close() + } + }() + + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-signalChan + log.Info("Received termination, signaling shutdown") + if sm.config.EnableControlPane { + cpCluster.Stop() + } + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + if sm.config.EnableControlPane { + + cpCluster, err = cluster.InitCluster(sm.config, false) + if err != nil { + return err + } + go func() { + err = cpCluster.StartLoadBalancerService(sm.config, sm.bgpServer) + if err != nil { + log.Errorf("Control Pane Error [%v]", err) + // Trigger the shutdown of this manager instance + signalChan <- syscall.SIGINT + } + }() + // ns = sm.config.Namespace + // } else { + // ns, err = returnNameSpace() + // if err != nil { + // return err + // } + } + sm.servicesWatcher(ctx) log.Infof("Shutting down Kube-Vip") From d28a49ca538c5aacc2d7e5bdca2e97435399167d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 30 Nov 2020 10:59:27 +0000 Subject: [PATCH 027/542] removes kube-vip binary before build --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4f76a192..aa1fa130 100644 --- a/Makefile +++ b/Makefile @@ -67,12 +67,12 @@ docker: # This will build a local docker image (x86 only), use make dockerLocal for all architectures dockerx86Local: - @rm ./kube-vip + @-rm ./kube-vip @docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created dockerLocal: - @rm ./kube-vip + @-rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created From 8930298f9382ce635cca42cd33d935335ba27239 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 1 Dec 2020 13:54:45 +0000 Subject: [PATCH 028/542] Fixes to docs --- README.md | 2 +- docs/architecture/index.md | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 40cdc851..8b8fa499 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The idea behind `kube-vip` is a small self-contained Highly-Available option for ## Features -Kube-Vip was originally created to provide a HA solutions for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). +Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). - Control Plane with ARP (Layer 2) or BGP (Layer 3) - Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 9bda3715..e76eafbe 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -15,11 +15,11 @@ There are a number of technologies or functional design choices that provide hig ### Cluster -The `kube-vip` service builds a multi-node or multi-pod cluster to provide High-Availability. When a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster. +The `kube-vip` service builds a multi-node or multi-pod cluster to provide High-Availability. In ARP mode a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster, whereas with BGP all nodes will advertise the VIP address. When using ARP or layer2 it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) -It is also possible to use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology, but this approach has largely been superseded by leader election. +It is also possible to use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology, but this approach has largely been superseded by leader election especially when running in cluster. ### Virtual IP @@ -56,11 +56,11 @@ Request timeout for icmp_seq 150 ### Load Balancing -Within a Kubernetes cluster, the load-balancing is managed by the `plndr-cloud-provider` which watches all service that are created, and for those of `type: LoadBalancer` will create the configuration for `kube-vip` to consume. +Within a Kubernetes cluster, the load-balancing is managed by the `plndr-cloud-provider` which watches all service that are created, and for those of `type=LoadBalancer` will create the configuration for `kube-vip` to consume. #### Load Balancing (Inside a cluster) -When using `type:LoadBalancer` within a Kubernetes cluster `kube-vip` will assign the VIP to the leader (when using ARP) all to all running Pods (when using BGP). When traffic is directed to a node with the VIP then the rules configured by `kube-proxy` will redirect the traffic to one of the pods running in the service. +When using `type=LoadBalancer` within a Kubernetes cluster `kube-vip` will assign the VIP to the leader (when using ARP) or to all running Pods (when using BGP). When traffic is directed to a node with the VIP then the rules configured by `kube-proxy` will redirect the traffic to one of the pods running in the service. #### Load Balancing (Outside a cluster) @@ -133,7 +133,3 @@ data: cidr-plunder: 192.168.0.210/29 cidr-testing: 192.168.0.220/29 ``` - -### Kube-vip - - The `kube-vip` pod should exist in every namespace that requires load-balancing services, it also implements a "client-go watch" over a `configMap` in its current namespace. These configurations and created and managed by the cloud-provider, when `kube-vip` sees a change happen (i.e. a new service is defined) then it will implement the virtual IP and start the load-balancer. Furthermore `kube-vip` implements a second "watch" over the endpoints of the service and as that service changes (pods die, scaling etc..) so will the the endpoints that `kube-vip` will load-balancer over. From a009f8a259df3fcf71d68349baf23a5af37e2474 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 4 Dec 2020 18:46:40 +0000 Subject: [PATCH 029/542] Moves the Status update to kube-vip --- pkg/manager/services.go | 18 ++++++++++++++---- pkg/manager/watcher.go | 10 ++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 5dfa8e9b..537ebd68 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -71,7 +71,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { log.Debugf("[STARTING] Service Sync") // Iterate through the synchronising services foundInstance := false - newServiceAddress := service.Status.LoadBalancer.Ingress[0].IP + newServiceAddress := service.Spec.LoadBalancerIP newServiceUID := string(service.UID) for x := range sm.serviceInstances { @@ -197,10 +197,15 @@ func (sm *Manager) syncServices(service *v1.Service) error { updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) if err != nil { - log.Errorf("Error updating Service [%s] : %v", newService.ServiceName, err) + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return + } + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(ns).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) return } - sm.upnpMap(newService) }, @@ -257,7 +262,12 @@ func (sm *Manager) syncServices(service *v1.Service) error { // TODO - we may need this // go sm.serviceWatcher(&newService, sm.config.Namespace) - // Add new service to manager configuration + // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it + service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services("").UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + } sm.serviceInstances = append(sm.serviceInstances, newService) } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 4fdddfea..0b40c73d 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -44,12 +44,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - log.Infof("Found Service [%s], it has [%d] external addresses", svc.Name, len(svc.Status.LoadBalancer.Ingress)) - if len(svc.Status.LoadBalancer.Ingress) > 0 { - err = sm.syncServices(svc) - if err != nil { - log.Error(err) - } + log.Infof("Found Service [%s], it has an assigned external addresses [%s]", svc.Name, len(svc.Spec.LoadBalancerIP)) + err = sm.syncServices(svc) + if err != nil { + log.Error(err) } case watch.Deleted: From 6e7a7a6ddae87cfe6529288718ea3ec8a03a92af Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sun, 6 Dec 2020 16:50:00 +0000 Subject: [PATCH 030/542] Fixes to service deletion and errors --- Makefile | 2 +- pkg/kubevip/config_generator.go | 4 ++++ pkg/manager/manager_arp.go | 5 ++++- pkg/manager/manager_bgp.go | 5 ++++- pkg/manager/services.go | 30 ++++++++++++++++-------------- pkg/manager/watcher.go | 23 +++++++++++++++++------ 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 5da56e04..98f50da9 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.2.2 +VERSION := 0.2.3 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index f136125d..30aca0c5 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -488,6 +488,10 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { Name: vipInterface, Value: c.Interface, }, + { + Name: port, + Value: fmt.Sprintf("%d", c.Port), + }, } // If a CIDR is used add it to the manifest diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index c24a77eb..aba28dba 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -128,7 +128,10 @@ func (sm *Manager) startARP() error { RetryPeriod: 1 * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - sm.servicesWatcher(ctx) + err = sm.servicesWatcher(ctx) + if err != nil { + log.Error(err) + } }, OnStoppedLeading: func() { // we can do cleanup here diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 5623f3f1..bbdd2aee 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -106,7 +106,10 @@ func (sm *Manager) startBGP() error { // } } - sm.servicesWatcher(ctx) + err = sm.servicesWatcher(ctx) + if err != nil { + return err + } log.Infof("Shutting down Kube-Vip") diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 537ebd68..685973b6 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -183,25 +183,27 @@ func (sm *Manager) syncServices(service *v1.Service) error { sm.serviceInstances = append(sm.serviceInstances, newService) // Update the service - ns, err := returnNameSpace() - if err != nil { - log.Errorf("Error finding Namespace") - return - } - dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.ServiceName, metav1.GetOptions{}) - if err != nil { - log.Errorf("Error finding Service [%s] : %v", newService.ServiceName, err) - return - } - dhcpService.Spec.LoadBalancerIP = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) + // ns, err := returnNameSpace() + // if err != nil { + // log.Errorf("Error finding Namespace") + // return + // } + // dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.ServiceName, metav1.GetOptions{}) + // if err != nil { + // log.Errorf("Error finding Service [%s] : %v", newService.ServiceName, err) + // return + // } + + // Update the service with DHCP information + service.Spec.LoadBalancerIP = newVip.VIP + updatedService, err := sm.clientSet.CoreV1().Services(service.Namespace).Update(context.TODO(), service, metav1.UpdateOptions{}) log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) if err != nil { log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) return } updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(ns).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) if err != nil { log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) return @@ -264,7 +266,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services("").UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) + _, err = sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) if err != nil { log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 0b40c73d..88c49eb4 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -44,18 +44,29 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - log.Infof("Found Service [%s], it has an assigned external addresses [%s]", svc.Name, len(svc.Spec.LoadBalancerIP)) - err = sm.syncServices(svc) - if err != nil { - log.Error(err) + if svc.Spec.LoadBalancerIP == "" { + log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) + } else { + log.Infof("Service [%s] has been addded/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + err = sm.syncServices(svc) + if err != nil { + log.Error(err) + } } - case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - sm.deleteService(string(svc.UID)) + err = sm.stopService(string(svc.UID)) + if err != nil { + log.Error(err) + } + err = sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) + } + log.Infof("Service [%s] has been deleted", svc.Name) case watch.Bookmark: // Un-used From ddfc9e23a84ed5606415640089a9fc9d885453f4 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 7 Dec 2020 17:35:07 +0000 Subject: [PATCH 031/542] Hybrid mode is now implemented --- cmd/kube-vip.go | 35 +++++++++++++++++++++++++++++++++ pkg/kubevip/config_generator.go | 29 ++++++++++++++++++++++++--- pkg/kubevip/config_types.go | 3 +++ pkg/manager/manager.go | 21 ++++++++++++++++++-- pkg/manager/manager_arp.go | 26 ++++++++++-------------- pkg/manager/manager_bgp.go | 34 +++++++++++--------------------- 6 files changed, 104 insertions(+), 44 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index e81c5c71..4ed61f40 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -103,9 +103,11 @@ func init() { // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) + kubeVipCmd.AddCommand(kubeVipManager) kubeVipCmd.AddCommand(kubeVipSample) kubeVipCmd.AddCommand(kubeVipService) kubeVipCmd.AddCommand(kubeVipStart) @@ -175,3 +177,36 @@ var kubeVipService = &cobra.Command{ } }, } + +var kubeVipManager = &cobra.Command{ + Use: "manager", + Short: "Start the kube-vip manager", + Run: func(cmd *cobra.Command, args []string) { + // Set the logging level for all subsequent functions + log.SetLevel(log.Level(logLevel)) + + // parse environment variables, these will overwrite anything loaded or flags + err := kubevip.ParseEnvironment(&initConfig) + if err != nil { + log.Fatalln(err) + } + + // User Environment variables as an option to make manifest clearer + envConfigMap := os.Getenv("vip_configmap") + if envConfigMap != "" { + configMap = envConfigMap + } + + // Define the new service manager + mgr, err := manager.New(configMap, &initConfig) + if err != nil { + log.Fatalf("%v", err) + } + + // 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) + } + }, +} diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 30aca0c5..5677daa6 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -99,6 +99,9 @@ const ( //cpEnable starts kube-vip in the hybrid mode cpEnable = "cp_enable" + //cpEnable starts kube-vip in the hybrid mode + svcEnable = "svc_enable" + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" @@ -223,7 +226,7 @@ func ParseEnvironment(c *Config) error { c.Namespace = env } - // Find vipDdns + // Find controlplane toggle env = os.Getenv(cpEnable) if env != "" { b, err := strconv.ParseBool(env) @@ -233,6 +236,16 @@ func ParseEnvironment(c *Config) error { c.EnableControlPane = b } + // Find Services toggle + env = os.Getenv(svcEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableServices = b + } + // Find vip address cidr range env = os.Getenv(vipCidr) if env != "" { @@ -477,7 +490,7 @@ func parseEnvironmentLoadBalancer(c *Config) error { // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { - command := "start" + command := "manager" // build environment variables newEnvironment := []corev1.EnvVar{ { @@ -509,7 +522,6 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { // If we're doing the hybrid mode if c.EnableControlPane { - command = "service" cp := []corev1.EnvVar{ { Name: cpEnable, @@ -523,6 +535,17 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { newEnvironment = append(newEnvironment, cp...) } + // If we're doing the hybrid mode + if c.EnableServices { + cp := []corev1.EnvVar{ + { + Name: svcEnable, + Value: strconv.FormatBool(c.EnableServices), + }, + } + newEnvironment = append(newEnvironment, cp...) + } + // If Leader election is enabled then add the configuration to the manifest if c.EnableLeaderElection { // Generate Kubernetes Leader Election configuration diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 436d7572..e611c759 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -18,6 +18,9 @@ type Config struct { // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPane bool `yaml:"enableControlPane"` + // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) + EnableServices bool `yaml:"enableServices"` + // LeaderElection defines the settings around Kubernetes LeaderElection LeaderElection diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 8f518cbe..ade49002 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -4,8 +4,10 @@ import ( "fmt" "io/ioutil" "os" + "os/signal" "path/filepath" "strings" + "syscall" dhclient "github.com/digineo/go-dhclient" "github.com/kamhlos/upnp" @@ -20,8 +22,6 @@ import ( const plunderLock = "plndr-svcs-lock" -var signalChan chan os.Signal - // Manager degines the manager of the load-balancing services type Manager struct { clientSet *kubernetes.Clientset @@ -36,8 +36,12 @@ type Manager struct { // Additional functionality upnp *upnp.Upnp + //BGP Manager, this is a singleton that manages all BGP advertisements bgpServer *bgp.Server + + // This channel is used to signal a shutdown + signalChan chan os.Signal } type dhcpService struct { @@ -127,6 +131,19 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) Start() error { + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + sm.signalChan = make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(sm.signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(sm.signalChan, syscall.SIGTERM) + + // Add Notification for SIGKILL (sent from Kubernetes) + signal.Notify(sm.signalChan, syscall.SIGKILL) + // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { log.Infoln("Starting Kube-vip loadBalancer Service with the BGP engine") diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index aba28dba..90871395 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -3,7 +3,6 @@ package manager import ( "context" "os" - "os/signal" "strconv" "syscall" "time" @@ -27,22 +26,9 @@ func (sm *Manager) startARP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // listen for interrupts or the Linux SIGTERM signal and cancel - // our context, which the leader election code will observe and - // step down - signalChan := make(chan os.Signal, 1) - // Add Notification for Userland interrupt - signal.Notify(signalChan, syscall.SIGINT) - - // Add Notification for SIGTERM (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGTERM) - - // Add Notification for SIGKILL (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGKILL) - // Shutdown function that will wait on this signal, unless we call it ourselves go func() { - <-signalChan + <-sm.signalChan log.Info("Received termination, signaling shutdown") if sm.config.EnableControlPane { cpCluster.Stop() @@ -66,11 +52,19 @@ func (sm *Manager) startARP() error { if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance - signalChan <- syscall.SIGINT + sm.signalChan <- syscall.SIGINT } }() + // Check if we're also starting the services, if now we can sit and wait on the closing channel and return here + if !sm.config.EnableServices { + <-sm.signalChan + log.Infof("Shutting down Kube-Vip") + + return nil + } + ns = sm.config.Namespace } else { ns, err = returnNameSpace() diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index bbdd2aee..becb6533 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -2,8 +2,6 @@ package manager import ( "context" - "os" - "os/signal" "syscall" "github.com/packethost/packngo" @@ -47,20 +45,8 @@ func (sm *Manager) startBGP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // listen for interrupts or the Linux SIGTERM signal and cancel - // our context, which the leader election code will observe and - // step down - signalChan = make(chan os.Signal, 1) - // Add Notification for Userland interrupt - signal.Notify(signalChan, syscall.SIGINT) - - // Add Notification for SIGTERM (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGTERM) - - // Add Notification for SIGKILL (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGKILL) go func() { - <-signalChan + <-sm.signalChan log.Info("Received termination, signaling shutdown") // Cancel the context, which will in turn cancel the leadership cancel() @@ -75,7 +61,7 @@ func (sm *Manager) startBGP() error { // Shutdown function that will wait on this signal, unless we call it ourselves go func() { - <-signalChan + <-sm.signalChan log.Info("Received termination, signaling shutdown") if sm.config.EnableControlPane { cpCluster.Stop() @@ -95,15 +81,17 @@ func (sm *Manager) startBGP() error { if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance - signalChan <- syscall.SIGINT + sm.signalChan <- syscall.SIGINT } }() - // ns = sm.config.Namespace - // } else { - // ns, err = returnNameSpace() - // if err != nil { - // return err - // } + + // Check if we're also starting the services, if now we can sit and wait on the closing channel and return here + if !sm.config.EnableServices { + <-sm.signalChan + log.Infof("Shutting down Kube-Vip") + + return nil + } } err = sm.servicesWatcher(ctx) From 879cfa7666203072fd802e4a85a70a6cbc94c4f1 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 8 Dec 2020 12:43:58 +0000 Subject: [PATCH 032/542] This adds support for BGP Peer password --- cmd/kube-vip.go | 1 + pkg/bgp/peers.go | 1 + pkg/bgp/types.go | 5 +++-- pkg/kubevip/config_generator.go | 12 ++++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 4ed61f40..32682135 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -93,6 +93,7 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.AS, "localAS", 65000, "The local AS number for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index f3f24879..35dcd96f 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -28,6 +28,7 @@ func (b *Server) AddPeer(peer Peer) (err error) { Conf: &api.PeerConf{ NeighborAddress: peer.Address, PeerAs: peer.AS, + AuthPassword: peer.Password, }, Timers: &api.Timers{ diff --git a/pkg/bgp/types.go b/pkg/bgp/types.go index 4d54924d..d4da9dd1 100644 --- a/pkg/bgp/types.go +++ b/pkg/bgp/types.go @@ -4,8 +4,9 @@ import gobgp "github.com/osrg/gobgp/pkg/server" // Peer defines a BGP Peer type Peer struct { - Address string - AS uint32 + Address string + AS uint32 + Password string } // Config defines the BGP server configuration diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 5677daa6..2bc9c1b7 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -92,6 +92,8 @@ const ( bgpPeerAddress = "bgp_peeraddress" //bgpPeerAS defines the AS for a BGP peer bgpPeerAS = "bgp_peeras" + //bgpPeerAS defines the AS for a BGP peer + bgpPeerPassword = "bgp_peerpass" //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" @@ -374,6 +376,12 @@ func ParseEnvironment(c *Config) error { c.BGPPeerConfig.AS = uint32(u64) } + // BGP Peer password + env = os.Getenv(bgpPeerPassword) + if env != "" { + c.BGPPeerConfig.Address = env + } + // BGP Peer options env = os.Getenv(bgpPeerAddress) if env != "" { @@ -641,6 +649,10 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { Name: bgpPeerAddress, Value: c.BGPPeerConfig.Address, }, + { + Name: bgpPeerPassword, + Value: c.BGPPeerConfig.Password, + }, { Name: bgpPeerAS, Value: fmt.Sprintf("%d", c.BGPPeerConfig.AS), From d5a618c244e4fc1a09750548dbbab16913ed725d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 9 Dec 2020 17:10:30 +0000 Subject: [PATCH 033/542] Fixes to manifest gen --- cmd/kube-vip-manifests.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 77666e79..11870114 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -43,7 +43,8 @@ var kubeManifestPod = &cobra.Command{ log.Fatalln("No interface is specified for kube-vip to bind to") } - if initConfig.VIP == "" { + // The control plane has a requirement for a VIP being specified + if initConfig.EnableControlPane && initConfig.VIP == "" { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } @@ -68,7 +69,8 @@ var kubeManifestDaemon = &cobra.Command{ log.Fatalln("No interface is specified for kube-vip to bind to") } - if initConfig.VIP == "" { + // The control plane has a requirement for a VIP being specified + if initConfig.EnableControlPane && initConfig.VIP == "" { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } From 5e0add5737813799cd9cc6eb209fa5b8045335db Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 11 Dec 2020 13:46:45 +0000 Subject: [PATCH 034/542] inCluster manifest --- cmd/kube-vip-kubeadm.go | 4 ++-- cmd/kube-vip-manifests.go | 8 +++++-- cmd/kube-vip.go | 18 +++++++++++++++ pkg/kubevip/config_generator.go | 41 +++++++++++++++++++-------------- pkg/packet/utils.go | 22 ++++++++++++++++++ 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index 485c3f9b..c31880be 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -54,7 +54,7 @@ var kubeKubeadmInit = &cobra.Command{ cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version) + cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) fmt.Println(cfg) }, @@ -123,7 +123,7 @@ var kubeKubeadmJoin = &cobra.Command{ } // Generate manifest and print - cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version) + cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) fmt.Println(cfg) }, } diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 11870114..99497e4d 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -13,7 +13,11 @@ import ( // - Pod spec manifest, mainly used for a static pod (kubeadm) // - Daemonset manifest, mainly used to run kube-vip as a deamonset within Kubernetes (k3s/rke) +//var inCluster bool + func init() { + kubeManifestPod.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") + kubeManifestDaemon.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") kubeManifest.AddCommand(kubeManifestPod) kubeManifest.AddCommand(kubeManifestDaemon) @@ -48,7 +52,7 @@ var kubeManifestPod = &cobra.Command{ cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version) + cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) fmt.Println(cfg) }, @@ -74,7 +78,7 @@ var kubeManifestDaemon = &cobra.Command{ cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version) + cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version, inCluster) fmt.Println(cfg) }, diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 32682135..5dfe21a3 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -6,6 +6,7 @@ import ( "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/manager" + "github.com/plunder-app/kube-vip/pkg/packet" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -31,6 +32,9 @@ var configMap string // Configure the level of loggin var logLevel uint32 +// Provider Config +var providerConfig string + // Release - this struct contains the release information populated when building kube-vip var Release struct { Version string @@ -78,6 +82,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnablePacket, "packet", false, "This will use the Packet API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketAPIKey, "packetKey", "", "The API token for authenticating with the Packet API") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProject, "packetProject", "", "The name of project already created within Packet") + kubeVipCmd.PersistentFlags().StringVar(&providerConfig, "provider-config", "", "The path to a provider configuration") // Load Balancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "lbEnable", false, "Enable a load-balancer on the VIP") @@ -103,6 +108,7 @@ func init() { // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") @@ -198,6 +204,18 @@ var kubeVipManager = &cobra.Command{ configMap = envConfigMap } + // If Packet is enabled and there is a provider configuration passed + if initConfig.EnablePacket { + if providerConfig != "" { + providerAPI, providerProject, err := packet.GetPacketConfig(providerConfig) + if err != nil { + log.Fatalf("%v", err) + } + initConfig.PacketAPIKey = providerAPI + initConfig.PacketProject = providerProject + } + } + // Define the new service manager mgr, err := manager.New(configMap, &initConfig) if err != nil { diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 2bc9c1b7..4d481367 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -497,7 +497,7 @@ func parseEnvironmentLoadBalancer(c *Config) error { } // generatePodSpec will take a kube-vip config and generate a Pod spec -func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { +func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" // build environment variables newEnvironment := []corev1.EnvVar{ @@ -751,10 +751,6 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { }, Env: newEnvironment, VolumeMounts: []corev1.VolumeMount{ - { - Name: "kubeconfig", - MountPath: "/etc/kubernetes/admin.conf", - }, { Name: "ca-certs", MountPath: "/etc/ssl/certs", @@ -764,14 +760,6 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { }, }, Volumes: []corev1.Volume{ - { - Name: "kubeconfig", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/etc/kubernetes/admin.conf", - }, - }, - }, { Name: "ca-certs", VolumeSource: corev1.VolumeSource{ @@ -784,21 +772,40 @@ func generatePodSpec(c *Config, imageVersion string) *corev1.Pod { HostNetwork: true, }, } + + // If this isn't inside a cluster then add the external path mount + if !inCluster { + + adminConfMount := corev1.VolumeMount{ + Name: "kubeconfig", + MountPath: "/etc/kubernetes/admin.conf", + } + newManifest.Spec.Containers[0].VolumeMounts = append(newManifest.Spec.Containers[0].VolumeMounts, adminConfMount) + adminConfVolume := corev1.Volume{ + Name: "kubeconfig", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/etc/kubernetes/admin.conf", + }, + }, + } + newManifest.Spec.Volumes = append(newManifest.Spec.Volumes, adminConfVolume) + } return newManifest } // GeneratePodManifestFromConfig will take a kube-vip config and generate a manifest -func GeneratePodManifestFromConfig(c *Config, imageVersion string) string { - newManifest := generatePodSpec(c, imageVersion) +func GeneratePodManifestFromConfig(c *Config, imageVersion string, inCluster bool) string { + newManifest := generatePodSpec(c, imageVersion, inCluster) b, _ := yaml.Marshal(newManifest) return string(b) } // GenerateDeamonsetManifestFromConfig will take a kube-vip config and generate a manifest -func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string) string { +func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inCluster bool) string { - podSpec := generatePodSpec(c, imageVersion).Spec + podSpec := generatePodSpec(c, imageVersion, inCluster).Spec newManifest := &appv1.DaemonSet{ TypeMeta: metav1.TypeMeta{ Kind: "DaemonSet", diff --git a/pkg/packet/utils.go b/pkg/packet/utils.go index 1d624073..aa7378f7 100644 --- a/pkg/packet/utils.go +++ b/pkg/packet/utils.go @@ -1,6 +1,9 @@ package packet import ( + "encoding/json" + "fmt" + "io/ioutil" "os" "github.com/packethost/packngo" @@ -34,3 +37,22 @@ func findSelf(c *packngo.Client, projectID string) *packngo.Device { } return nil } + +func GetPacketConfig(providerConfig string) (string, string, error) { + var config struct { + AuthToken string `json:"apiKey"` + ProjectID string `json:"projectId"` + } + // get our token and project + if providerConfig != "" { + configBytes, err := ioutil.ReadFile(providerConfig) + if err != nil { + return "", "", fmt.Errorf("failed to get read configuration file at path %s: %v", providerConfig, err) + } + err = json.Unmarshal(configBytes, &config) + if err != nil { + return "", "", fmt.Errorf("failed to process json of configuration file at path %s: %v", providerConfig, err) + } + } + return config.AuthToken, config.ProjectID, nil +} From d3160001c4ecdff53cc129b1befe7c889a2bc01b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 11 Dec 2020 14:04:46 +0000 Subject: [PATCH 035/542] Enables BGP multihop --- cmd/kube-vip.go | 1 + pkg/bgp/peers.go | 6 ++++++ pkg/bgp/types.go | 1 + pkg/kubevip/config_generator.go | 16 ++++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 5dfe21a3..cf669ddf 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -99,6 +99,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 35dcd96f..6c24503f 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -37,6 +37,12 @@ func (b *Server) AddPeer(peer Peer) (err error) { }, }, + // This enables routes to be sent to routers across multiple hops + EbgpMultihop: &api.EbgpMultihop{ + Enabled: peer.MultiHop, + MultihopTtl: 50, + }, + Transport: &api.Transport{ MtuDiscovery: true, RemoteAddress: peer.Address, diff --git a/pkg/bgp/types.go b/pkg/bgp/types.go index d4da9dd1..2e06f888 100644 --- a/pkg/bgp/types.go +++ b/pkg/bgp/types.go @@ -7,6 +7,7 @@ type Peer struct { Address string AS uint32 Password string + MultiHop bool } // Config defines the BGP server configuration diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 4d481367..444b9d17 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -94,6 +94,8 @@ const ( bgpPeerAS = "bgp_peeras" //bgpPeerAS defines the AS for a BGP peer bgpPeerPassword = "bgp_peerpass" + //bgpMultiHop enables mulithop routing + bgpMultiHop = "bgp_multihop" //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" @@ -376,6 +378,16 @@ func ParseEnvironment(c *Config) error { c.BGPPeerConfig.AS = uint32(u64) } + // BGP Peer mutlihop + env = os.Getenv(bgpMultiHop) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.BGPPeerConfig.MultiHop = b + } + // BGP Peer password env = os.Getenv(bgpPeerPassword) if env != "" { @@ -649,6 +661,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: bgpPeerAddress, Value: c.BGPPeerConfig.Address, }, + { + Name: bgpMultiHop, + Value: strconv.FormatBool(c.BGPPeerConfig.MultiHop), + }, { Name: bgpPeerPassword, Value: c.BGPPeerConfig.Password, From b8c40e926b9a7685388a1546d654edf41b4fdfb6 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 11 Dec 2020 17:44:53 +0000 Subject: [PATCH 036/542] Multihop_and_use CCM Secret --- cmd/kube-vip-manifests.go | 7 ++- cmd/kube-vip.go | 2 +- docs/manifests/kube-vip-em.yaml | 97 +++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 1 + pkg/cluster/clusterLeader.go | 2 +- pkg/kubevip/config_generator.go | 81 ++++++++++++++++++++------- pkg/kubevip/config_types.go | 3 + pkg/manager/manager_bgp.go | 15 ++++- pkg/packet/bgp.go | 21 ++++--- pkg/service/manager_bgp.go | 2 +- 11 files changed, 197 insertions(+), 36 deletions(-) create mode 100644 docs/manifests/kube-vip-em.yaml diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 99497e4d..9e3e6e8a 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -14,10 +14,11 @@ import ( // - Daemonset manifest, mainly used to run kube-vip as a deamonset within Kubernetes (k3s/rke) //var inCluster bool +var taint bool func init() { - kubeManifestPod.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") - kubeManifestDaemon.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") + kubeManifest.PersistentFlags().BoolVar(&inCluster, "inCluster", false, "Use the incluster token to authenticate to Kubernetes") + kubeManifestDaemon.PersistentFlags().BoolVar(&taint, "taint", false, "Taint the manifest for only running on control planes") kubeManifest.AddCommand(kubeManifestPod) kubeManifest.AddCommand(kubeManifestDaemon) @@ -78,7 +79,7 @@ var kubeManifestDaemon = &cobra.Command{ cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version, inCluster) + cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) fmt.Println(cfg) }, diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index cf669ddf..9c0ab3a9 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -82,7 +82,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnablePacket, "packet", false, "This will use the Packet API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketAPIKey, "packetKey", "", "The API token for authenticating with the Packet API") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProject, "packetProject", "", "The name of project already created within Packet") - kubeVipCmd.PersistentFlags().StringVar(&providerConfig, "provider-config", "", "The path to a provider configuration") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // Load Balancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "lbEnable", false, "Enable a load-balancer on the VIP") diff --git a/docs/manifests/kube-vip-em.yaml b/docs/manifests/kube-vip-em.yaml new file mode 100644 index 00000000..c82fbc79 --- /dev/null +++ b/docs/manifests/kube-vip-em.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-vip + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:kube-vip-role +rules: + - apiGroups: [""] + resources: ["services", "services/status"] + verbs: ["list","get","watch", "update"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:kube-vip-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-vip-role +subjects: +- kind: ServiceAccount + name: kube-vip + namespace: kube-system +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: lo + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: svc_enable + value: "true" + - name: provider_config + value: /etc/cloud-sa/cloud-sa.json + - name: vip_packet + value: "true" + - name: bgp_enable + value: "true" + image: plndr/kube-vip:0.2.3 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + volumeMounts: + - mountPath: /etc/ssl/certs + name: ca-certs + readOnly: true + - mountPath: /etc/cloud-sa + name: cloud-sa-volume + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - hostPath: + path: /etc/ssl/certs + name: ca-certs + - name: cloud-sa-volume + secret: + secretName: packet-cloud-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 \ No newline at end of file diff --git a/go.mod b/go.mod index e99bd1d1..749f342e 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/osrg/gobgp v2.0.0+incompatible - github.com/packethost/packngo v0.5.0 + github.com/packethost/packngo v0.5.1 github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.6.0 diff --git a/go.sum b/go.sum index 1d0cda1d..967558a1 100644 --- a/go.sum +++ b/go.sum @@ -381,6 +381,7 @@ github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyT github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= github.com/packethost/packngo v0.5.0 h1:WGpfeRMstPqgyXGUXl6b9xFsbUudXU3p0+JlYri290U= github.com/packethost/packngo v0.5.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= +github.com/packethost/packngo v0.5.1/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index b2c72df8..c21e5238 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -161,7 +161,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // We're using Packet with BGP, popuplate the Peer information from the API if c.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, c) + err = packet.BGPLookup(packetClient, c, "") //TODO: This will need looking at in the future if err != nil { log.Error(err) } diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 444b9d17..5c07ad4d 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -74,12 +74,15 @@ const ( //vipAddPeersToLB defines that RAFT peers should be added to the load-balancer vipAddPeersToLB = "vip_addpeerstolb" - //vipPacket defines that the packet API will be used tor EIP + //vipPacket defines that the packet API will be used for EIP vipPacket = "vip_packet" //vipPacket defines which project within Packet to use vipPacketProject = "vip_packetproject" + //providerConfig defines a path to a configuration that should be parsed + providerConfig = "provider_config" + //bgpEnable defines if BGP should be enabled bgpEnable = "bgp_enable" //bgpRouterID defines the routerID for the BGP server @@ -150,8 +153,13 @@ func ParseEnvironment(c *Config) error { c.Interface = env } - // Find Kubernetes Leader Election configuration + // Find provider configuration + env = os.Getenv(providerConfig) + if env != "" { + c.ProviderConfig = env + } + // Find Kubernetes Leader Election configuration env = os.Getenv(vipLeaderElection) if env != "" { b, err := strconv.ParseBool(env) @@ -622,6 +630,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, raft...) } + // If we're specifying a configuration + if c.ProviderConfig != "" { + provider := []corev1.EnvVar{ + { + Name: providerConfig, + Value: c.ProviderConfig, + }, + } + newEnvironment = append(newEnvironment, provider...) + } + // If Packet is enabled then add it to the manifest if c.EnablePacket { packet := []corev1.EnvVar{ @@ -639,16 +658,21 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } newEnvironment = append(newEnvironment, packet...) - } - // If BGP is enabled then add it to the manifest + // If BGP, but we're not using packet if c.EnableBGP { bgp := []corev1.EnvVar{ { Name: bgpEnable, Value: strconv.FormatBool(c.EnableBGP), }, + } + newEnvironment = append(newEnvironment, bgp...) + } + // If BGP, but we're not using packet + if c.EnableBGP && !c.EnablePacket { + bgpConfig := []corev1.EnvVar{ { Name: bgpRouterID, Value: c.BGPConfig.RouterID, @@ -661,10 +685,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: bgpPeerAddress, Value: c.BGPPeerConfig.Address, }, - { - Name: bgpMultiHop, - Value: strconv.FormatBool(c.BGPPeerConfig.MultiHop), - }, { Name: bgpPeerPassword, Value: c.BGPPeerConfig.Password, @@ -674,7 +694,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Value: fmt.Sprintf("%d", c.BGPPeerConfig.AS), }, } - newEnvironment = append(newEnvironment, bgp...) + newEnvironment = append(newEnvironment, bgpConfig...) } @@ -807,6 +827,27 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newManifest.Spec.Volumes = append(newManifest.Spec.Volumes, adminConfVolume) } + + if c.ProviderConfig != "" { + providerConfigMount := corev1.VolumeMount{ + Name: "cloud-sa-volume", + MountPath: "/etc/cloud-sa", + ReadOnly: true, + } + newManifest.Spec.Containers[0].VolumeMounts = append(newManifest.Spec.Containers[0].VolumeMounts, providerConfigMount) + + providerConfigVolume := corev1.Volume{ + Name: "cloud-sa-volume", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "packet-cloud-config", + }, + }, + } + newManifest.Spec.Volumes = append(newManifest.Spec.Volumes, providerConfigVolume) + + } + return newManifest } @@ -819,7 +860,7 @@ func GeneratePodManifestFromConfig(c *Config, imageVersion string, inCluster boo } // GenerateDeamonsetManifestFromConfig will take a kube-vip config and generate a manifest -func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inCluster bool) string { +func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inCluster, taint bool) string { podSpec := generatePodSpec(c, imageVersion, inCluster).Spec newManifest := &appv1.DaemonSet{ @@ -847,17 +888,17 @@ func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inClust }, }, } - - newManifest.Spec.Template.Spec.Tolerations = []corev1.Toleration{ - { - Key: "node-role.kubernetes.io/master", - Effect: corev1.TaintEffectNoSchedule, - }, - } - newManifest.Spec.Template.Spec.NodeSelector = map[string]string{ - "node-role.kubernetes.io/master": "true", + if taint { + newManifest.Spec.Template.Spec.Tolerations = []corev1.Toleration{ + { + Key: "node-role.kubernetes.io/master", + Effect: corev1.TaintEffectNoSchedule, + }, + } + newManifest.Spec.Template.Spec.NodeSelector = map[string]string{ + "node-role.kubernetes.io/master": "true", + } } - b, _ := yaml.Marshal(newManifest) return string(b) } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index e611c759..2002908e 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -76,6 +76,9 @@ type Config struct { // PacketProject, is the name of a particular defined project PacketProject string + // ProviderConfig, is the path to a provider configuration file + ProviderConfig string + // LoadBalancers are the various services we can load balance over LoadBalancers []LoadBalancer `yaml:"loadBalancers,omitempty"` } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index becb6533..61df1584 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -2,6 +2,7 @@ package manager import ( "context" + "os" "syscall" "github.com/packethost/packngo" @@ -20,6 +21,18 @@ func (sm *Manager) startBGP() error { // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client if sm.config.EnablePacket { + var projectID string + if sm.config.ProviderConfig != "" { + key, project, err := packet.GetPacketConfig(sm.config.ProviderConfig) + if err != nil { + log.Error(err) + } else { + // Set the environment variable with the key for the project + os.Setenv("PACKET_AUTH_TOKEN", key) + // Update the configuration with the project key + projectID = project + } + } packetClient, err = packngo.NewClient() if err != nil { log.Error(err) @@ -28,7 +41,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config) + err = packet.BGPLookup(packetClient, sm.config, projectID) if err != nil { log.Error(err) } diff --git a/pkg/packet/bgp.go b/pkg/packet/bgp.go index a8cc5924..4fbd6beb 100644 --- a/pkg/packet/bgp.go +++ b/pkg/packet/bgp.go @@ -10,13 +10,17 @@ import ( ) // BGPLookup will use the Packet API functions to populate the BGP information -func BGPLookup(c *packngo.Client, k *kubevip.Config) error { - - proj := findProject(k.PacketProject, c) - if proj == nil { - return fmt.Errorf("Unable to find Project [%s]", k.PacketProject) +func BGPLookup(c *packngo.Client, k *kubevip.Config, projectID string) error { + var thisDevice *packngo.Device + if projectID == "" { + proj := findProject(k.PacketProject, c) + if proj == nil { + return fmt.Errorf("Unable to find Project [%s]", k.PacketProject) + } + thisDevice = findSelf(c, proj.ID) + } else { + thisDevice = findSelf(c, projectID) } - thisDevice := findSelf(c, proj.ID) if thisDevice == nil { return fmt.Errorf("Unable to find local/this device in packet API") } @@ -47,8 +51,9 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error { // Add the peer(s) for x := range neighbours[0].PeerIps { peer := bgp.Peer{ - Address: neighbours[0].PeerIps[x], - AS: uint32(neighbours[0].PeerAs), + Address: neighbours[0].PeerIps[x], + AS: uint32(neighbours[0].PeerAs), + MultiHop: neighbours[0].Multihop, } k.BGPConfig.Peers = append(k.BGPConfig.Peers, peer) } diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index c5f2525f..1d664f99 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -30,7 +30,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config) + err = packet.BGPLookup(packetClient, sm.config, "") // TODO: This will need looking at in the future if err != nil { log.Error(err) } From 38e0966fa694509d91c70e2beb90e0978f531052 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 11 Dec 2020 20:46:43 +0000 Subject: [PATCH 037/542] Now uses projectID from env/cli --- cmd/kube-vip.go | 1 + go.sum | 1 + pkg/cluster/clusterLeader.go | 2 +- pkg/kubevip/config_generator.go | 16 +++++++++++++++- pkg/kubevip/config_types.go | 3 +++ pkg/manager/manager.go | 8 ++++---- pkg/manager/manager_bgp.go | 5 ++--- pkg/packet/bgp.go | 6 +++--- pkg/service/manager_bgp.go | 2 +- 9 files changed, 31 insertions(+), 13 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 9c0ab3a9..8f71fc55 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -82,6 +82,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnablePacket, "packet", false, "This will use the Packet API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketAPIKey, "packetKey", "", "The API token for authenticating with the Packet API") kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProject, "packetProject", "", "The name of project already created within Packet") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProjectID, "packetProjectID", "", "The ID of project already created within Packet") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // Load Balancer flags diff --git a/go.sum b/go.sum index 967558a1..5406c09c 100644 --- a/go.sum +++ b/go.sum @@ -381,6 +381,7 @@ github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyT github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= github.com/packethost/packngo v0.5.0 h1:WGpfeRMstPqgyXGUXl6b9xFsbUudXU3p0+JlYri290U= github.com/packethost/packngo v0.5.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= +github.com/packethost/packngo v0.5.1 h1:y+jWcMnyArP3hVZRsBkAXTLhokuqdYg6JUmkshX2SMk= github.com/packethost/packngo v0.5.1/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index c21e5238..b2c72df8 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -161,7 +161,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // We're using Packet with BGP, popuplate the Peer information from the API if c.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, c, "") //TODO: This will need looking at in the future + err = packet.BGPLookup(packetClient, c) if err != nil { log.Error(err) } diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 5c07ad4d..1e7c9978 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -77,9 +77,12 @@ const ( //vipPacket defines that the packet API will be used for EIP vipPacket = "vip_packet" - //vipPacket defines which project within Packet to use + //vipPacketProject defines which project within Packet to use vipPacketProject = "vip_packetproject" + //vipPacketProjectID defines which projectID within Packet to use + vipPacketProjectID = "vip_packetprojectid" + //providerConfig defines a path to a configuration that should be parsed providerConfig = "provider_config" @@ -427,6 +430,13 @@ func ParseEnvironment(c *Config) error { c.PacketProject = env } + // Find the Packet project ID + env = os.Getenv(vipPacketProjectID) + if env != "" { + // TODO - parse address net.Host() + c.PacketProjectID = env + } + // Enable the load-balancer env = os.Getenv(lbEnable) if env != "" { @@ -652,6 +662,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: vipPacketProject, Value: c.PacketProject, }, + { + Name: vipPacketProjectID, + Value: c.PacketProjectID, + }, { Name: "PACKET_AUTH_TOKEN", Value: c.PacketAPIKey, diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 2002908e..e4511316 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -76,6 +76,9 @@ type Config struct { // PacketProject, is the name of a particular defined project PacketProject string + // PacketProjectID, is the name of a particular defined project + PacketProjectID string + // ProviderConfig, is the path to a provider configuration file ProviderConfig string diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index ade49002..3eaf21d2 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -146,15 +146,15 @@ func (sm *Manager) Start() error { // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { - log.Infoln("Starting Kube-vip loadBalancer Service with the BGP engine") - log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane) + log.Infoln("Starting Kube-vip Manager with the BGP engine") + log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane && sm.config.EnableServices) return sm.startBGP() } // If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs if sm.config.EnableARP { - log.Infoln("Starting loadBalancer Service with the ARP engine") - log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane) + log.Infoln("Starting Kube-vip Manager with the ARP engine") + log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane && sm.config.EnableServices) return sm.startARP() } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 61df1584..31c5418e 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -21,7 +21,6 @@ func (sm *Manager) startBGP() error { // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client if sm.config.EnablePacket { - var projectID string if sm.config.ProviderConfig != "" { key, project, err := packet.GetPacketConfig(sm.config.ProviderConfig) if err != nil { @@ -30,7 +29,7 @@ func (sm *Manager) startBGP() error { // Set the environment variable with the key for the project os.Setenv("PACKET_AUTH_TOKEN", key) // Update the configuration with the project key - projectID = project + sm.config.PacketProjectID = project } } packetClient, err = packngo.NewClient() @@ -41,7 +40,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config, projectID) + err = packet.BGPLookup(packetClient, sm.config) if err != nil { log.Error(err) } diff --git a/pkg/packet/bgp.go b/pkg/packet/bgp.go index 4fbd6beb..f62551e0 100644 --- a/pkg/packet/bgp.go +++ b/pkg/packet/bgp.go @@ -10,16 +10,16 @@ import ( ) // BGPLookup will use the Packet API functions to populate the BGP information -func BGPLookup(c *packngo.Client, k *kubevip.Config, projectID string) error { +func BGPLookup(c *packngo.Client, k *kubevip.Config) error { var thisDevice *packngo.Device - if projectID == "" { + if k.PacketProjectID == "" { proj := findProject(k.PacketProject, c) if proj == nil { return fmt.Errorf("Unable to find Project [%s]", k.PacketProject) } thisDevice = findSelf(c, proj.ID) } else { - thisDevice = findSelf(c, projectID) + thisDevice = findSelf(c, k.PacketProjectID) } if thisDevice == nil { return fmt.Errorf("Unable to find local/this device in packet API") diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 1d664f99..c5f2525f 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -30,7 +30,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config, "") // TODO: This will need looking at in the future + err = packet.BGPLookup(packetClient, sm.config) if err != nil { log.Error(err) } From 3869c3520ba37ee87ca65059540d0acb2b6fa89c Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 14 Dec 2020 18:29:49 +0000 Subject: [PATCH 038/542] Adds Dockerfile Fix --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 4126ef08..74a9e456 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,5 +12,8 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ CGO_ENABLED=0 GOOS=linux make build FROM scratch +# Add Certificates into the image, for anything that does API calls +COPY --from=dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +# Add kube-vip binary COPY --from=dev /src/kube-vip / ENTRYPOINT ["/kube-vip"] \ No newline at end of file From e91ef9fc5c6bdff70b75b969e5d3c931d5a59d92 Mon Sep 17 00:00:00 2001 From: Plunder <46795316+plunder-app@users.noreply.github.com> Date: Tue, 15 Dec 2020 13:53:32 +0000 Subject: [PATCH 039/542] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..dd84ea78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. From 568af564dae72778e1da829983c66d97362a02e1 Mon Sep 17 00:00:00 2001 From: Plunder <46795316+plunder-app@users.noreply.github.com> Date: Tue, 15 Dec 2020 13:56:00 +0000 Subject: [PATCH 040/542] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea78..2e9dd2aa 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,16 +23,13 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +**Environment (please complete the following information):** + - OS/Distro: [e.g. Ubuntu 1804] + - Kubernetes Version: [e.g. v.1.18] + - Kube-vip Version: [e.g. 0.2.3] + +**`Kube-vip.yaml`:** +If Possible add in your kube-vip manifest (please remove anything that is confidential) **Additional context** Add any other context about the problem here. From 92f01a7d00c0883fe6d22977d9e66cc2062e58cd Mon Sep 17 00:00:00 2001 From: Plunder <46795316+plunder-app@users.noreply.github.com> Date: Tue, 15 Dec 2020 13:56:41 +0000 Subject: [PATCH 041/542] Update issue templates --- .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 058cfd7c0904530857db3019fe7319ec82b15157 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 15 Dec 2020 19:45:57 +0000 Subject: [PATCH 042/542] Adds multiple peers from manifest --- cmd/kube-vip.go | 1 + pkg/bgp/peers.go | 34 +++++++++++++++++++++++++++++++++ pkg/kubevip/config_generator.go | 34 +++++++++++++++++++++++++++++++-- pkg/kubevip/config_types.go | 1 + 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 8f71fc55..9c3a360b 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -101,6 +101,7 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support") + kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{"192.168.0.2:65000:password:true", "192.168.0.3:65000:password:true"}, "Comma seperated BGP Peer, format: address:as:password:multihop") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 6c24503f..d4524ea1 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -104,3 +104,37 @@ func (b *Server) getPath(ip net.IP) *api.Path { Pattrs: []*any.Any{a1, a2}, } } + +// ParseBGPPeerConfig - take a string and parses it into an array of peers +func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) { + peers := strings.Split(config, ",") + if len(peers) == 0 { + return nil, fmt.Errorf("No BGP Peer configurations found") + } + + for x := range peers { + peer := strings.Split(peers[x], ":") + if len(peer) != 4 { + return nil, fmt.Errorf("BGP Peer configuration format error :::") + } + ASNumber, err := strconv.Atoi(peer[1]) + if err != nil { + return nil, fmt.Errorf("BGP Peer AS format error [%s]", peer[1]) + + } + multiHop, err := strconv.ParseBool(peer[3]) + if err != nil { + return nil, fmt.Errorf("BGP MultiHop format error (true/false) [%s]", peer[1]) + } + + peerConfig := Peer{ + Address: peer[0], + AS: uint32(ASNumber), + Password: peer[2], + MultiHop: multiHop, + } + + bgpPeers = append(bgpPeers, peerConfig) + } + return +} diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 1e7c9978..77058750 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/ghodss/yaml" + "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/detector" log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" @@ -96,6 +97,8 @@ const ( bgpRouterAS = "bgp_as" //bgpPeerAddress defines the address for a BGP peer bgpPeerAddress = "bgp_peeraddress" + //bgpPeers defines the address for a BGP peer + bgpPeers = "bgp_peers" //bgpPeerAS defines the AS for a BGP peer bgpPeerAS = "bgp_peeras" //bgpPeerAS defines the AS for a BGP peer @@ -389,6 +392,16 @@ func ParseEnvironment(c *Config) error { c.BGPPeerConfig.AS = uint32(u64) } + // Peer AS + env = os.Getenv(bgpPeers) + if env != "" { + peers, err := bgp.ParseBGPPeerConfig(env) + if err != nil { + return err + } + c.BGPConfig.Peers = peers + } + // BGP Peer mutlihop env = os.Getenv(bgpMultiHop) if env != "" { @@ -402,10 +415,10 @@ func ParseEnvironment(c *Config) error { // BGP Peer password env = os.Getenv(bgpPeerPassword) if env != "" { - c.BGPPeerConfig.Address = env + c.BGPPeerConfig.Password = env } - // BGP Peer options + // BGP Peer options, add them if relevant env = os.Getenv(bgpPeerAddress) if env != "" { c.BGPPeerConfig.Address = env @@ -708,6 +721,23 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Value: fmt.Sprintf("%d", c.BGPPeerConfig.AS), }, } + + var peers string + if len(c.BGPPeers) != 0 { + for x := range c.BGPPeers { + if x != 0 { + peers = fmt.Sprintf("%s,%s", peers, c.BGPPeers[x]) + } else { + peers = c.BGPPeers[x] + } + } + bgpConfig = append(bgpConfig, corev1.EnvVar{ + Name: bgpPeers, + Value: peers, + }, + ) + } + newEnvironment = append(newEnvironment, bgpConfig...) } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index e4511316..a3afa3f8 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -66,6 +66,7 @@ type Config struct { // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer + BGPPeers []string // EnablePacket, will use the packet API to update the EIP <-> VIP (if BGP is enabled then BGP will be used) EnablePacket bool `yaml:"enablePacket"` From ff407ab6062c3236731d9ddde54505d3a0b401e9 Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 16 Dec 2020 11:36:27 +0100 Subject: [PATCH 043/542] Bootstrap CI for kube-vip on GitHub Action This commit bootstraps a CI pipeline for kube-vip using GitHub action. --- .github/workflows/ci.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..3be8c3cd --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,23 @@ +name: For each commit and PR +on: + push: + pull_request: + +jobs: + validation: + runs-on: ubuntu-latest + env: + CGO_ENABLED: 0 + steps: + - name: Init + run: apt-get update && apt-get install -y build-essential golint + - name: Checkout code + uses: actions/checkout@v2 + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.15' + - name: checks + run: make check + - name: test docker build + run: make dockerLocal From dc159b32d50cf630b802e813e5cf80e8f1c11b7d Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 16 Dec 2020 11:56:26 +0100 Subject: [PATCH 044/542] Fixed deprecated call to go vet and add go mod tidy This commit migrates: $ go tools vet ./... To $ go vet ./... Because the first one triggers a deprecation warning. It also adds a go mod tidy to validate that go mods are all right. --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 98f50da9..6aabfe8f 100644 --- a/Makefile +++ b/Makefile @@ -80,9 +80,11 @@ simplify: @gofmt -s -l -w $(SRC) check: + @go mod tidy + @test -z "$(git status --porcelain)" @test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" @for d in $$(go list ./... | grep -v /vendor/); do golint $${d}; done - @go tool vet ${SRC} + @go vet ${SRC} run: install @$(TARGET) From 17cbd665cb32774de622220997b3556c341e2798 Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 16 Dec 2020 14:42:44 +0100 Subject: [PATCH 045/542] Fix permission access in GitHub Action I use `act` locally to run GitHub Action and apparently it works differently and on GitHub you have to run apt as sudo. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3be8c3cd..cfea4704 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,7 +10,7 @@ jobs: CGO_ENABLED: 0 steps: - name: Init - run: apt-get update && apt-get install -y build-essential golint + run: sudo apt-get update && sudo apt-get install -y build-essential golint - name: Checkout code uses: actions/checkout@v2 - name: Install Go From 178142f0bdc102c9d6081f6d06d068e0fe764bc4 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 16 Dec 2020 16:08:54 +0000 Subject: [PATCH 046/542] This PR adds all of the updated documentation --- cmd/kube-vip.go | 2 +- docs/control-plane/index.md | 2 +- docs/hyrbid/daemonset/index.md | 0 docs/hyrbid/index.md | 87 ++++++++++++++++++++++++++++++++++ docs/hyrbid/static/index.md | 68 ++++++++++++++++++++++++++ docs/index/index.md | 10 ++-- docs/kubernetes/index.md | 2 +- testing/create.sh | 41 ++++++++++++++++ testing/lb_clean.sh | 15 ++++++ testing/teardown.sh | 10 ++++ testing/testing.sh | 8 ++++ 11 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 docs/hyrbid/daemonset/index.md create mode 100644 docs/hyrbid/index.md create mode 100644 docs/hyrbid/static/index.md create mode 100644 testing/create.sh create mode 100644 testing/lb_clean.sh create mode 100644 testing/teardown.sh create mode 100755 testing/testing.sh diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 9c3a360b..3ead9d62 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -101,7 +101,7 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support") - kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{"192.168.0.2:65000:password:true", "192.168.0.3:65000:password:true"}, "Comma seperated BGP Peer, format: address:as:password:multihop") + kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma seperated BGP Peer, format: address:as:password:multihop") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md index ff498a11..3371d549 100644 --- a/docs/control-plane/index.md +++ b/docs/control-plane/index.md @@ -1,6 +1,6 @@ # Load Balancing a Kubernetes Cluster (Control-Plane) -**Note**: The most common deployment currently for HA Kubernetes clusters w/`kub-vip` involved `kubeadm`, however recently we've worked to bring a method of bringing `kube-vip` to other types of Kubernetes cluster. Typically this deployment method makes use of a daemonset that is usually brought up during the cluster instantiation.. So for those wanting to deploy [k3s](https://k3s.io), we now have installation steps available [here](https://kube-vip.io/control-plane/#k3s), +**Note**: The most common deployment currently for HA Kubernetes clusters w/`kube-vip` involved `kubeadm`, however recently we've worked to bring a method of bringing `kube-vip` to other types of Kubernetes cluster. Typically this deployment method makes use of a daemonset that is usually brought up during the cluster instantiation.. So for those wanting to deploy [k3s](https://k3s.io), we now have installation steps available [here](https://kube-vip.io/control-plane/#k3s), This document covers the newer (post `0.1.6`) method for using `kube-vip` to provide HA for a Kubernetes Cluster. The documentation for older releases can be found [here](./0.1.5/) diff --git a/docs/hyrbid/daemonset/index.md b/docs/hyrbid/daemonset/index.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/hyrbid/index.md b/docs/hyrbid/index.md new file mode 100644 index 00000000..6f519742 --- /dev/null +++ b/docs/hyrbid/index.md @@ -0,0 +1,87 @@ +# Using `kube-vip` in Hybrid Mode + +We can deploy kube-vip in two different methods, which completely depends on your use-case and method for installing Kubernetes: + +- Static Pods (hybrid) +- Daemonset (services only) + +## Static Pods + +Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. + +The sequence of events for this to work follows: +1. Generate a `kube-vip` manifest in the static pods manifest folder +2. Run `kubeadm init`, this generates the manifests for the control plane and wait to connect to the VIP +3. The `kubelet` will parse and execute all manifest, including the `kube-vip` manifest +4. `kube-vip` starts and advertises our VIP +5. The `kubeadm init` finishes succesfully. + +## Daemonset + +Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a daemonset for all control plane nodes. + +# Deploying `kube-vip` + +The simplest method for generating the Kubernetes manifests is with `kube-vip` itself.. The subcommand `manifest pod|daemonset` can be used to generate specific types of Kubernetes manifests for use in a cluster. These subcommands can be configured with additional flags to enable/disable BGP/ARP/LeaderElection and a host of other options. + +Both Examples will use the same Architecture: + +#### Infrastructure architecture + +The infrastructure for our example HA Kubernetes cluster is as follows: + +| Node | Address | +|----------------|------------| +| VIP | 10.0.0.40 | +| controlPlane01 | 10.0.0.41 | +| controlPlane02 | 10.0.0.42 | +| controlPlane03 | 10.0.0.43 | +| worker01 | 10.0.0.44 | + +All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.19.0, we only have one worker as we're going to use our controlPlanes in "hybrid" mode. + +## As a static Pod (for kubeadm) + +The details for creating a static pod are available [here](./static/) + +## As a daemonset + +When using `kube-vip` as a daemonset the details are available [here](./daemonset/) + +# Kube-Vip flag reference + +| Category | Flag | Usage | Notes | +|--------------|------|-------|-------| +|**Mode** |||| +| |`--controlPlane`|Enables `kube-vip` control-plane functionality|| +| |`--servcies`|Enables `kube-vip` to watch services of type:LoadBalancer|| +|**Vip Config** |||| +| |`--arp`|Enables ARP brodcasts from Leader|| +| |`--bgp`|Enables BGP peering from `kube-vip`|| +| |`--vip`|\|(deprecated)| +| |`--address`|\ or \|| +| |`--interface`|\|| +| |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| +|**Services**|||| +| |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| +|**Kubernetes**|||| +| |`--inCluster`|Defaults to looking inside the Pod for the token|| +|**LeaderElection**|||| +| |`--leaseDuration`|default 5|Seconds a lease is held for| +| |`--leaseRenewDuration`|default 3|Seconds a leader can attempt to renew the lease| +| |`--leaseRetry`|default 1|Number of times the leader will hold the lease for| +| |`--namespace`|"kube-vip"|The namespace where the lease will reside| +|**BGP**|||| +| |`--bgpRouterID`|\|Typically the address of the local node| +| |`--localAS`|default 65000|The AS we peer from| +| |`--bgppeers`|``|Comma seperate list of BGP peers| +| |`--peerAddress`|\|(deprecated), Address of a single BGP Peer| +| |`--peerAS`|default 65000|(deprecated), AS of a single BGP Peer| +| |`--peerPass`|""|(deprecated), Password to work with a single BGP Peer| +| |`--multiHop`|Enables eBGP MultiHop|(deprecated), Enable multiHop with a single BGP Peer| +|**Packet**|||(To be deprecated)| +| |`--packet`|Enables Packet API calls|| +| |`--packetKey`|Packet API token|| +| |`--packetProject`|Packet Project (Name)|| +| |`--packetProjectID`|Packet Project (UUID)|| +| |`--provider-config`|Path to the Packet provider configuration|Requires the Packet CCM| \ No newline at end of file diff --git a/docs/hyrbid/static/index.md b/docs/hyrbid/static/index.md new file mode 100644 index 00000000..991b30c6 --- /dev/null +++ b/docs/hyrbid/static/index.md @@ -0,0 +1,68 @@ +# Kube-vip as a Static Pod + +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. + +The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. + +## Generating a Manifest + +This section details creating a number of manifests for various use cases + +## Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an environmemnt variable for different container runtimes. + +### containerd +`export KUBE-VIP="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` + +### Docker +`export KUBE-VIP="docker run --network host --rm plndr/kube-vip:0.2.3"` + +### ARP + +This configuration will create a manifest that starts `kube-vip` providing **controlplane** and **services** management, using **leaderElection**. When this instance is elected as the leader it will bind the `vip` to the specified `interface`, this is also the same for services of `type:LoadBalancer`. +``` +$KUBE-VIP kube-vip manifest pod \ + --interface eth0 \ + --vip 192.168.0.40 \ + --controlplane \ + --services \ + --arp \ + --leaderElection +``` + +### BGP + +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. + +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. + +``` +$KUBE-VIP kube-vip manifest pod \ + --interface lo \ + --vip 192.168.0.40 \ + --controlplane \ + --services \ + --bgp \ + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false +``` + +### BGP with Packet + +We can enable `kube-vip` with the capability to pull all of the required configuration for BGP by passing the `--packet` flag and the API Key and our project ID. + +``` +$KUBE-VIP kube-vip manifest pod \ + --interface lo \ + --vip 192.168.0.40 \ + --controlplane \ + --services \ + --bgp \ + --packet \ + --packetAPI xxxxxxx \ + --packetProjectID xxxxx +``` + +## Services + +At this point your `kube-vip` static pods will be up and running and where passed with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. \ No newline at end of file diff --git a/docs/index/index.md b/docs/index/index.md index 045e0099..f3a886c8 100644 --- a/docs/index/index.md +++ b/docs/index/index.md @@ -8,16 +8,20 @@ A Load-Balancer for both **inside** and **outside** a Kubernetes cluster The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) -## Control-plane load balancer + +## (New) Hybrid- Control-plane HA and Kubernetes service `type=LoadBalancer` + +With the newest release of `kube-vip` the internal "manager" can handle the lifecycle of VIPs for both HA and for Kubernetes Load-Balancing. The main driver for this is being most effective for large nodes that can run control-plane components and run applications. The details for hybrid mode are [here](/hybrid/) + +## (Legacy) Control-plane load balancer The details are [here](/control-plane/) -## Kubernetes service `"type: LoadBalancer"` +## (Legacy) Kubernetes service `"type: LoadBalancer"` The details are [here](/kubernetes/) ## GitHub Repositories - The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) -- The Starboard Daemonset -> [https://github.com/plunder-app/starboard](https://github.com/plunder-app/starboard) - The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) \ No newline at end of file diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md index b3971bb7..adaeb0e8 100644 --- a/docs/kubernetes/index.md +++ b/docs/kubernetes/index.md @@ -6,7 +6,7 @@ The below instructions *should just work* on Kubernetes regardless of architectu If you just want things to "work", then you can quickly install the "latest" components: -**Install the `plndr-cloud-provider`, `starboard` and `kube-vip`** +**Install the `plndr-cloud-provider`, and `kube-vip`** ``` kubectl apply -f https://kube-vip.io/manifests/controller.yaml diff --git a/testing/create.sh b/testing/create.sh new file mode 100644 index 00000000..d1c73dba --- /dev/null +++ b/testing/create.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [[ -z $1 && -z $2 && -z $3 ]]; then + echo "Usage:" + echo " Param 1: Kubernetes Version" + echo " Param 2: Kube-Vip Version" + echo " Param 3: Vip address" + echo "" + echo "" ./create_k8s.sh 1.18.5 0.1.8 192.168.0.41 + exit 1 +fi + +echo "Creating First node!" +ssh k8s01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --controlplane --interface ens160 --vip $3 --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml" +CONTROLPLANE_CMD=$(ssh k8s01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $3 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") +ssh k8s01 "sudo rm -rf ~/.kube/" +ssh k8s01 "mkdir -p .kube" +ssh k8s01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" +ssh k8s01 "sudo chown dan:dan .kube/config" +echo "Enabling strict ARP on kube-proxy" +ssh k8s01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" +ssh k8s01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" +ssh k8s01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" +JOIN_CMD=$(ssh k8s01 " sudo kubeadm token create --print-join-command 2> /dev/null") + +ssh k8s02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" +sleep 3 +ssh k8s02 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $3 --arp --leaderElection --controlplane | sudo tee /etc/kubernetes/manifests/vip.yaml" + +ssh k8s03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" +sleep 3 +ssh k8s03 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $3 --arp --leaderElection --controlplane | sudo tee /etc/kubernetes/manifests/vip.yaml" +ssh k8s04 "sudo $JOIN_CMD" +ssh k8s05 "sudo $JOIN_CMD" +echo +echo " Nodes should be deployed at this point, waiting 5 secs and querying the deployment" +sleep 5 +ssh k8s01 "kubectl get nodes" +ssh k8s01 "kubectl get pods -A" +echo +echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $3" \ No newline at end of file diff --git a/testing/lb_clean.sh b/testing/lb_clean.sh new file mode 100644 index 00000000..43bbcfa6 --- /dev/null +++ b/testing/lb_clean.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [[ -z $1 ]]; then + echo "Usage:" + echo " Param 1: kube-vip Version" + exit 1 +fi + +echo "Removing docker images from workers" +sleep 2 +ssh k8s05 "sudo docker rmi plndr/kube-vip:$1" +ssh k8s04 "sudo docker rmi plndr/kube-vip:$1" +ssh k8s03 "sudo docker rmi plndr/kube-vip:$1" +ssh k8s02 "sudo docker rmi plndr/kube-vip:$1" +ssh k8s01 "sudo docker rmi plndr/kube-vip:$1" diff --git a/testing/teardown.sh b/testing/teardown.sh new file mode 100644 index 00000000..515562a3 --- /dev/null +++ b/testing/teardown.sh @@ -0,0 +1,10 @@ +#!/bin/bash +echo "Wiping Nodes in reverse order, and rebooting" +ssh k8s05 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh k8s04 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh k8s03 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh k8s02 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh k8s01 "sudo kubeadm reset -f --skip-phases preflight update-cluster-status remove-etcd-member; sudo rm -rf /etc/cni/net.d; sudo reboot" +echo +echo "All Control Plane Nodes have been reset" +echo "Consider removing kube-vip images if changing version" \ No newline at end of file diff --git a/testing/testing.sh b/testing/testing.sh new file mode 100755 index 00000000..9b72b35b --- /dev/null +++ b/testing/testing.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +make build +./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection +./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp +./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true +./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection +rm ./kube-vip \ No newline at end of file From 564013bd1473187e828e166df81e0a2ae5f21572 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 16 Dec 2020 22:23:33 +0000 Subject: [PATCH 047/542] Further doc updates, and serviceAccount Fix --- docs/hyrbid/daemonset/index.md | 120 ++++++++++++++++++++++++++++++++ docs/hyrbid/index.md | 48 ++++++++++++- docs/hyrbid/services/index.md | 0 docs/hyrbid/static/index.md | 68 +++++++++++++----- docs/manifests/rbac.yaml | 29 ++++++++ pkg/kubevip/config_generator.go | 3 +- 6 files changed, 249 insertions(+), 19 deletions(-) create mode 100644 docs/hyrbid/services/index.md create mode 100644 docs/manifests/rbac.yaml diff --git a/docs/hyrbid/daemonset/index.md b/docs/hyrbid/daemonset/index.md index e69de29b..5df11514 100644 --- a/docs/hyrbid/daemonset/index.md +++ b/docs/hyrbid/daemonset/index.md @@ -0,0 +1,120 @@ +# Kube-Vip as a daemonset + +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. + + +**Note about Daemonsets** + +The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. + +If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. + +Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. + +## Generating a Manifest + +This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). + +**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `daemonset` and NOT `pod`. + +### Set configuration details + +`export VIP=192.168.0.40` + +`export INTERFACE=` + +### Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +#### containerd +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` + +#### Docker +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.2.3"` + +### BGP Example + +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. + +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. + +**Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. + +`export INTERFACE=lo` + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --vip $VIP \ + --controlplane \ + --services \ + --inCluster \ + --bgp \ + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false +``` + +### Generated Manifest + +``` +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: lo + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: svc_enable + value: "true" + - name: bgp_enable + value: "true" + - name: bgp_peers + value: "192.168.0.10:65000::false,192.168.0.11:65000::false" + - name: vip_address + value: 192.168.0.40 + image: plndr/kube-vip:0.2.3 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + volumeMounts: + - mountPath: /etc/ssl/certs + name: ca-certs + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - hostPath: + path: /etc/ssl/certs + name: ca-certs + updateStrategy: {} +``` \ No newline at end of file diff --git a/docs/hyrbid/index.md b/docs/hyrbid/index.md index 6f519742..04e2d58e 100644 --- a/docs/hyrbid/index.md +++ b/docs/hyrbid/index.md @@ -5,7 +5,7 @@ We can deploy kube-vip in two different methods, which completely depends on you - Static Pods (hybrid) - Daemonset (services only) -## Static Pods +## Static Pods Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. @@ -84,4 +84,48 @@ When using `kube-vip` as a daemonset the details are available [here](./daemonse | |`--packetKey`|Packet API token|| | |`--packetProject`|Packet Project (Name)|| | |`--packetProjectID`|Packet Project (UUID)|| -| |`--provider-config`|Path to the Packet provider configuration|Requires the Packet CCM| \ No newline at end of file +| |`--provider-config`|Path to the Packet provider configuration|Requires the Packet CCM| + +## Changelog + +### Static DNS Support (added in 0.2.0) + +A new flag `--address` is introduced to support using a DNS record as the control plane endpoint. `kube-vip` will do a dns lookup to retrieve the IP for the DNS record, and use that IP as the VIP. An `dnsUpdater` periodically checks and updates the system if IP changes for the DNS record. + +### Dynamic DNS Support (added in 0.2.1) + +`kube-vip` was also updated to support DHCP + [Dynamic DNS](https://en.wikipedia.org/wiki/Dynamic_DNS), for the use case where it's not able to reserve a static IP for the control plane endpoint. + +A new flag `--ddns` is introduced. Once enabled, `kube-vip` expects the input `--address` will be a FQDN without binding to an IP. Then `kube-vip` will start a dhcp client to allocate an IP for the hostname of FQDN, and maintain the lease for it. + +Once DHCP returns an IP for the FQDN, the same `dnsUpdater` runs to periodically checks and updates if IP got changed. + +## BGP Support (added in 0.1.8) + +In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. + +The following new flags are used: + +- `--bgp` This will enable BGP support within kube-vip +- `--localAS` The local AS number +- `--bgpRouterID` The local router address +- `--peerAS` The AS number for a BGP peer +- `--peerAddress` The address of a BGP peer + +### BGP Packet support + +If the `--bgp` flag is passed alone with the Packet flags `packet, packetKey and packetProject`, then the Packet API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Packet much simpler. + +## Packet Support (added in 0.1.7) + +Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Packet Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Packet account and create a EIP (either public (eek) or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Packet project we can now apply this address to the servers that live in the same project. + +In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. + +The following new flags are used: + +- `--packet` which enables the use of the Packet API +- `--packetKey` which is our API key +- `--packetProject`which is the name of our Packet project where our servers and EIP are located. + +*Also* the `--arp` flag should NOT be used as it wont work within the Packet network. \ No newline at end of file diff --git a/docs/hyrbid/services/index.md b/docs/hyrbid/services/index.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/hyrbid/static/index.md b/docs/hyrbid/static/index.md index 991b30c6..68ded17b 100644 --- a/docs/hyrbid/static/index.md +++ b/docs/hyrbid/static/index.md @@ -8,23 +8,33 @@ The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, an This section details creating a number of manifests for various use cases -## Configure to use a container runtime +### Set configuration details -The easiest method to generate a manifest is using the container itself, below will create an environmemnt variable for different container runtimes. +`export VIP=192.168.0.40` -### containerd -`export KUBE-VIP="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` +`export INTERFACE=` + +### Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +#### containerd +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` + +#### Docker +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.2.3"` -### Docker -`export KUBE-VIP="docker run --network host --rm plndr/kube-vip:0.2.3"` ### ARP This configuration will create a manifest that starts `kube-vip` providing **controlplane** and **services** management, using **leaderElection**. When this instance is elected as the leader it will bind the `vip` to the specified `interface`, this is also the same for services of `type:LoadBalancer`. + +`export INTERFACE=eth0` + ``` -$KUBE-VIP kube-vip manifest pod \ - --interface eth0 \ - --vip 192.168.0.40 \ +kube-vip manifest pod \ + --interface $INTERFACE \ + --vip $VIP \ --controlplane \ --services \ --arp \ @@ -37,10 +47,12 @@ This configuration will create a manifest that will start `kube-vip` providing * **Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. +`export INTERFACE=lo` + ``` -$KUBE-VIP kube-vip manifest pod \ - --interface lo \ - --vip 192.168.0.40 \ +kube-vip manifest pod \ + --interface $INTERFACE \ + --vip $VIP \ --controlplane \ --services \ --bgp \ @@ -52,9 +64,9 @@ $KUBE-VIP kube-vip manifest pod \ We can enable `kube-vip` with the capability to pull all of the required configuration for BGP by passing the `--packet` flag and the API Key and our project ID. ``` -$KUBE-VIP kube-vip manifest pod \ - --interface lo \ - --vip 192.168.0.40 \ +kube-vip manifest pod \ + --interface $INTERFACE\ + --vip $VIP \ --controlplane \ --services \ --bgp \ @@ -63,6 +75,30 @@ $KUBE-VIP kube-vip manifest pod \ --packetProjectID xxxxx ``` +## Deploy your Kubernetes Cluster + +### First node + +``` +sudo kubeadm init \ + --kubernetes-version 1.19.0 \ + --control-plane-endpoint $VIP \ + --upload-certs +``` + +### Additional Node(s) + +Due to an oddity with `kubeadm` we can't have our `kube-vip` manifest present **before** joining our additional nodes. So on these control plane nodes we will add them first to the cluster. + +``` +sudo kubeadm join $VIP:6443 \ + --token w5atsr.blahblahblah + --control-plane \ + --certificate-key abc123 +``` + +**Once**, joined these nodes can have the same command that we ran on the first node to populate the `/etc/kubernetes/manifests/` folder with the `kube-vip` manifest. + ## Services -At this point your `kube-vip` static pods will be up and running and where passed with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. \ No newline at end of file +At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. \ No newline at end of file diff --git a/docs/manifests/rbac.yaml b/docs/manifests/rbac.yaml new file mode 100644 index 00000000..7e835985 --- /dev/null +++ b/docs/manifests/rbac.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kube-vip + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:kube-vip-role +rules: + - apiGroups: [""] + resources: ["services", "services/status"] + verbs: ["list","get","watch", "update"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: system:kube-vip-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-vip-role +subjects: +- kind: ServiceAccount + name: kube-vip + namespace: kube-system diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 77058750..bd21bc80 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -849,7 +849,8 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, }, }, - HostNetwork: true, + HostNetwork: true, + ServiceAccountName: "kube-vip", }, } From 3271ccdfae8d8b5e449deb2d09aff842fc685852 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 17 Dec 2020 15:49:29 +0000 Subject: [PATCH 048/542] Final bits of documentation --- docs/hyrbid/daemonset/index.md | 24 +++-- docs/hyrbid/services/index.md | 182 ++++++++++++++++++++++++++++++++ docs/manifests/kube-vip-em.yaml | 6 -- pkg/kubevip/config_generator.go | 17 --- 4 files changed, 197 insertions(+), 32 deletions(-) diff --git a/docs/hyrbid/daemonset/index.md b/docs/hyrbid/daemonset/index.md index 5df11514..46bce550 100644 --- a/docs/hyrbid/daemonset/index.md +++ b/docs/hyrbid/daemonset/index.md @@ -11,6 +11,14 @@ If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. +## Create the RBAC settings + +As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` + ## Generating a Manifest This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). @@ -106,15 +114,13 @@ spec: add: - NET_ADMIN - SYS_TIME - volumeMounts: - - mountPath: /etc/ssl/certs - name: ca-certs - readOnly: true hostNetwork: true serviceAccountName: kube-vip - volumes: - - hostPath: - path: /etc/ssl/certs - name: ca-certs updateStrategy: {} -``` \ No newline at end of file +``` + +### Manifest Overview + +- `serviceAccountName: kube-vip` - this specifies the user in the `rbac` that will give us the permissions to get/update services. +- `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) +- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. \ No newline at end of file diff --git a/docs/hyrbid/services/index.md b/docs/hyrbid/services/index.md index e69de29b..284c1dba 100644 --- a/docs/hyrbid/services/index.md +++ b/docs/hyrbid/services/index.md @@ -0,0 +1,182 @@ +# Kube-vip services + +We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. + +## Flow + +This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: + +1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` +2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = ServiceTypeLoadBalancer` +3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. +4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. +5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. +6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. +7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. +8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. + +## CCM + +We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for exist CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. + +The below instructions *should just work* on Kubernetes regardless of architecture, Linux as the Operating System is the only requirement. + +## Using the Plunder Cloud Provider (CCM) + +If you just want things to "work", then you can quickly install the "latest" components: + +**Install the `plndr-cloud-provider` + +``` +kubectl apply -f https://kube-vip.io/manifests/controller.yaml +``` + +**Create the `cidr` for the `global` namespace** + +``` +kubectl create configmap --namespace kube-system plndr --from-literal cidr-global=192.168.0.200/29 +``` + +Creating services of `type: LoadBalancer` in the default namespace will now take addresses from the **global** cidr defined in the `configmap`. + +**Additional namespaces** + +Edit the `configmap` and add in the cidr ranges for those namespaces, the key in the cidr should be `cidr-`, then ensure that `kube-vip` is deployed into that namespac +e with the above `apply` command with the `-n namespace` flag. + +## The Detailed guide + +### Deploy the `plndr-cloud-provider` + +To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/controller.yaml`, specific versions should be found in the repository as detailed below: + +From the GitHub repository [https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod](https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/p +od), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Githu +b will provide the url that can be applied directly with a `kubectl apply -f `. + +The following output should appear when the manifest is applied: + +``` +serviceaccount/plunder-cloud-controller created +clusterrole.rbac.authorization.k8s.io/system:plunder-cloud-controller-role created +clusterrolebinding.rbac.authorization.k8s.io/system:plunder-cloud-controller-binding created +pod/plndr-cloud-provider created +``` + +We can validate the cloud-provider by examining the pods: + +`kubectl logs -n kube-system plndr-cloud-provider-0 -f` + +#### The `plndr-cloud-provider` `configmap` + +The `configmap` details a CIDR range *per* namespace, however as of (`kube-vip 0.2.1` and `plnder-cloud-provider 0.1.4`), there is now the option of having a **global** CIDR rang +e (`cidr-global)`. + +To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within th +e `configmap` should be that the key is in the format `cidr-` and the value should be the cidr range. + +Example Configmap: + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: plndr + namespace: kube-system +data: + cidr-default: 192.168.0.200/29 + cidr-global: 192.168.0.210/29 +``` + +### Expose a service + +We can now expose a service and once the cloud provider has provided an address `kube-vip` will start to advertise that address to the outside world as shown below! + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx +``` + +We can also expose a specific address by specifying it on the command line: + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` + +### Using DHCP for Load Balancers (experimental) + +With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a + Kubernetes service on the network. + +In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the +address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it wi +ll assign it as the VIP and update the Kubernetes service! + +``` +$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc +service/nginx-dhcp exposed +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s + +{ ... a second or so later ... } + +$ k get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s +``` + +### Using UPNP to expose a service to the outside world + +With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the inte +rnet. + +Most simple networks look something like the following: + +`<----- ----> Internet` + +Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. + +#### Enable UPNP + +Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. + +**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) + +``` +- name: enableUPNP + value: "true" +``` + +#### Exposing a service + +To expose a port successfully we'll need to change the command slightly: + +`--target-port=80` the port of the application in the pods (HTT/NGINX) +`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) + +`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` + +The above example should expose a port on your external (internet facing address), that can be tested externally with: + +``` +$ curl externalIP:32380 + + +... +``` + +### Expose with packet (using the `plndr-cloud-provider`) + +Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! + +``` +# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 ++-------+---------------+--------+----------------------+ +| ID | ADDRESS | PUBLIC | CREATED | ++-------+---------------+--------+----------------------+ +| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | ++-------+---------------+--------+----------------------+ + +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` \ No newline at end of file diff --git a/docs/manifests/kube-vip-em.yaml b/docs/manifests/kube-vip-em.yaml index c82fbc79..0cf6e178 100644 --- a/docs/manifests/kube-vip-em.yaml +++ b/docs/manifests/kube-vip-em.yaml @@ -74,18 +74,12 @@ spec: - NET_ADMIN - SYS_TIME volumeMounts: - - mountPath: /etc/ssl/certs - name: ca-certs - readOnly: true - mountPath: /etc/cloud-sa name: cloud-sa-volume readOnly: true hostNetwork: true serviceAccountName: kube-vip volumes: - - hostPath: - path: /etc/ssl/certs - name: ca-certs - name: cloud-sa-volume secret: secretName: packet-cloud-config diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index bd21bc80..13496692 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -830,23 +830,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod command, }, Env: newEnvironment, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "ca-certs", - MountPath: "/etc/ssl/certs", - ReadOnly: true, - }, - }, - }, - }, - Volumes: []corev1.Volume{ - { - Name: "ca-certs", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/etc/ssl/certs", - }, - }, }, }, HostNetwork: true, From ad34e96627360b7a69aed1ae948267317c41a308 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 17 Dec 2020 16:27:07 +0000 Subject: [PATCH 049/542] hostname_fix --- docs/hyrbid/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/hyrbid/index.md b/docs/hyrbid/index.md index 04e2d58e..77a373b6 100644 --- a/docs/hyrbid/index.md +++ b/docs/hyrbid/index.md @@ -5,6 +5,10 @@ We can deploy kube-vip in two different methods, which completely depends on you - Static Pods (hybrid) - Daemonset (services only) +## **Prerequisites** + +In order for `kube-vip` to be able to speak with the Kubernetes API server, we need to be able to resolve the hostname within the pod. In order to ensure this will work as expected the `/etc/hosts` file should have the `hostname` of the server within it. The `/etc/hosts` file is passed into the running container and will ensure that the pod isn't "confused" by any Kubernetes networking. + ## Static Pods Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. From 325958c2a47f05d7846936f62acd9b4539f6fffe Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 17 Dec 2020 17:48:43 +0000 Subject: [PATCH 050/542] Move to 0.3.0 and doc fixes --- Makefile | 2 +- docs/{hyrbid => hybrid}/daemonset/index.md | 0 docs/{hyrbid => hybrid}/index.md | 4 ++++ docs/{hyrbid => hybrid}/services/index.md | 0 docs/{hyrbid => hybrid}/static/index.md | 0 docs/index/index.md | 2 +- 6 files changed, 6 insertions(+), 2 deletions(-) rename docs/{hyrbid => hybrid}/daemonset/index.md (100%) rename docs/{hyrbid => hybrid}/index.md (97%) rename docs/{hyrbid => hybrid}/services/index.md (100%) rename docs/{hyrbid => hybrid}/static/index.md (100%) diff --git a/Makefile b/Makefile index 23d13f51..80e7ace2 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.2.3 +VERSION := 0.3.0 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/docs/hyrbid/daemonset/index.md b/docs/hybrid/daemonset/index.md similarity index 100% rename from docs/hyrbid/daemonset/index.md rename to docs/hybrid/daemonset/index.md diff --git a/docs/hyrbid/index.md b/docs/hybrid/index.md similarity index 97% rename from docs/hyrbid/index.md rename to docs/hybrid/index.md index 77a373b6..2e784a3f 100644 --- a/docs/hyrbid/index.md +++ b/docs/hybrid/index.md @@ -9,6 +9,10 @@ We can deploy kube-vip in two different methods, which completely depends on you In order for `kube-vip` to be able to speak with the Kubernetes API server, we need to be able to resolve the hostname within the pod. In order to ensure this will work as expected the `/etc/hosts` file should have the `hostname` of the server within it. The `/etc/hosts` file is passed into the running container and will ensure that the pod isn't "confused" by any Kubernetes networking. +## Kubernetes Services (`type:LoadBalancer`) + +To learn more about how `kube-vip` in hybrid works with the LoadBalancer services within a kubernetes cluster the documentation is [here](./services/). To get `kube-vip` deployed read on ! + ## Static Pods Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. diff --git a/docs/hyrbid/services/index.md b/docs/hybrid/services/index.md similarity index 100% rename from docs/hyrbid/services/index.md rename to docs/hybrid/services/index.md diff --git a/docs/hyrbid/static/index.md b/docs/hybrid/static/index.md similarity index 100% rename from docs/hyrbid/static/index.md rename to docs/hybrid/static/index.md diff --git a/docs/index/index.md b/docs/index/index.md index 5a04fe97..d09a3d66 100644 --- a/docs/index/index.md +++ b/docs/index/index.md @@ -9,7 +9,7 @@ The **kube-vip** project provides High-Availability and load-balancing for both The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) -## (New) Hybrid- Control-plane HA and Kubernetes service `type=LoadBalancer` +## (New) Hybrid Control-plane HA and Kubernetes service `type=LoadBalancer` With the newest release of `kube-vip` the internal "manager" can handle the lifecycle of VIPs for both HA and for Kubernetes Load-Balancing. The main driver for this is being most effective for large nodes that can run control-plane components and run applications. The details for hybrid mode are [here](/hybrid/) From a8a44b9240bde106a226dec6afde720f0b4575e0 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 17 Dec 2020 19:10:14 +0000 Subject: [PATCH 051/542] Fixes to formatting and taint --- docs/hybrid/daemonset/index.md | 8 ++++++++ docs/hybrid/index.md | 13 +++++++------ go.sum | 2 -- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 46bce550..f7ee5a1f 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -49,6 +49,8 @@ This configuration will create a manifest that will start `kube-vip` providing * **Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. +**Note 2** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. + `export INTERFACE=lo` ``` @@ -58,6 +60,7 @@ kube-vip manifest daemonset \ --controlplane \ --services \ --inCluster \ + --taint \ --bgp \ --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false ``` @@ -116,6 +119,11 @@ spec: - SYS_TIME hostNetwork: true serviceAccountName: kube-vip + nodeSelector: + node-role.kubernetes.io/master: "true" + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master updateStrategy: {} ``` diff --git a/docs/hybrid/index.md b/docs/hybrid/index.md index 2e784a3f..dc856616 100644 --- a/docs/hybrid/index.md +++ b/docs/hybrid/index.md @@ -3,7 +3,7 @@ We can deploy kube-vip in two different methods, which completely depends on your use-case and method for installing Kubernetes: - Static Pods (hybrid) -- Daemonset (services only) +- Daemonset (hybrid, requires taint) ## **Prerequisites** @@ -66,24 +66,25 @@ When using `kube-vip` as a daemonset the details are available [here](./daemonse |**Vip Config** |||| | |`--arp`|Enables ARP brodcasts from Leader|| | |`--bgp`|Enables BGP peering from `kube-vip`|| -| |`--vip`|\|(deprecated)| -| |`--address`|\ or \|| -| |`--interface`|\|| +| |`--vip`|``|(deprecated)| +| |`--address`|`` or ``|| +| |`--interface`|``|| | |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| |**Services**|||| | |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| |**Kubernetes**|||| | |`--inCluster`|Defaults to looking inside the Pod for the token|| +| |`--taint`|Enables a taint, stopping control plane daemonset being on workers|| |**LeaderElection**|||| | |`--leaseDuration`|default 5|Seconds a lease is held for| | |`--leaseRenewDuration`|default 3|Seconds a leader can attempt to renew the lease| | |`--leaseRetry`|default 1|Number of times the leader will hold the lease for| | |`--namespace`|"kube-vip"|The namespace where the lease will reside| |**BGP**|||| -| |`--bgpRouterID`|\|Typically the address of the local node| +| |`--bgpRouterID`|``|Typically the address of the local node| | |`--localAS`|default 65000|The AS we peer from| | |`--bgppeers`|``|Comma seperate list of BGP peers| -| |`--peerAddress`|\|(deprecated), Address of a single BGP Peer| +| |`--peerAddress`|``|(deprecated), Address of a single BGP Peer| | |`--peerAS`|default 65000|(deprecated), AS of a single BGP Peer| | |`--peerPass`|""|(deprecated), Password to work with a single BGP Peer| | |`--multiHop`|Enables eBGP MultiHop|(deprecated), Enable multiHop with a single BGP Peer| diff --git a/go.sum b/go.sum index 5406c09c..bdf82c67 100644 --- a/go.sum +++ b/go.sum @@ -379,8 +379,6 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyTzf1c5VubkPi+Q83O9oBCNgA= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= -github.com/packethost/packngo v0.5.0 h1:WGpfeRMstPqgyXGUXl6b9xFsbUudXU3p0+JlYri290U= -github.com/packethost/packngo v0.5.0/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/packethost/packngo v0.5.1 h1:y+jWcMnyArP3hVZRsBkAXTLhokuqdYg6JUmkshX2SMk= github.com/packethost/packngo v0.5.1/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= From 93703e553514c8749388efc683b2d06c92ef5ccf Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 18 Dec 2020 10:39:05 +0000 Subject: [PATCH 052/542] Update index.md --- docs/hybrid/daemonset/index.md | 52 +++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index f7ee5a1f..e8e80d5b 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -129,6 +129,56 @@ spec: ### Manifest Overview +- `nodeSelector` - Ensures that this particular daemonset only runs on control plane nodes - `serviceAccountName: kube-vip` - this specifies the user in the `rbac` that will give us the permissions to get/update services. - `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) -- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. \ No newline at end of file +- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. + +## K3s overview (on packet) + +### Step 1: TIDY (best if something was running before) +`rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; ip addr flush dev lo; ip addr add 127.0.0.1/8 dev lo; mkdir -p /var/lib/rancher/k3s/server/manifests/` + +### Step 2: Get rbac +`curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/rbac.yaml` + +### Step 3: Generate kube-vip (get EIP from CLI or UI) + +``` +export EIP=x.x.x.x +export INTERFACE=lo +``` + +``` +kube-vip manifest daemonset \ +--interface $INTERFACE \ +--vip $EIP \ +--controlplane \ +--services \ +--inCluster \ +--taint \ +--bgp \ +--packet \ +--provider-config /etc/cloud-sa/cloud-sa.json | tee /var/lib/rancher/k3s/server/manifests/vip.yaml +``` + +NOTE: the `—provider-config` actually comes from the secret we apply in step 5 (this will leave kube-vip waiting to start) + +### Step 4: Up Cluster +`K3S_TOKEN=SECRET k3s server --cluster-init --tls-san $EIP --no-deploy servicelb --disable-cloud-controller` + +### Step 5: Add CCM + +`alias k="k3s kubectl"` +`k apply -f ./secret.yaml` + +(^ https://github.com/packethost/packet-ccm/blob/master/deploy/template/secret.yaml) + +`k apply -f https://gist.githubusercontent.com/thebsdbox/c86dd970549638105af8d96439175a59/raw/4abf90fb7929ded3f7a201818efbb6164b7081f0/ccm.yaml` + +### Step 6: Demo ! +`k apply -f https://k8s.io/examples/application/deployment.yaml` +`k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` + +### Step 7 watch and test: +`k get svc --watch` From 22751059bf3f4025728e09dfdbdf08b1b398e8a2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 18 Dec 2020 10:41:18 +0000 Subject: [PATCH 053/542] Update index.md --- docs/hybrid/daemonset/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index e8e80d5b..3cc131a7 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -36,10 +36,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.0 vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.2.3"` +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.0"` ### BGP Example From fbb7bf9a963c851823d24e741e866c155da0c232 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 18 Dec 2020 10:43:02 +0000 Subject: [PATCH 054/542] Update index.md --- docs/hybrid/daemonset/index.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 3cc131a7..a63835b3 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -150,16 +150,16 @@ export INTERFACE=lo ``` ``` -kube-vip manifest daemonset \ ---interface $INTERFACE \ ---vip $EIP \ ---controlplane \ ---services \ ---inCluster \ ---taint \ ---bgp \ ---packet \ ---provider-config /etc/cloud-sa/cloud-sa.json | tee /var/lib/rancher/k3s/server/manifests/vip.yaml +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --vip $EIP \ + --controlplane \ + --services \ + --inCluster \ + --taint \ + --bgp \ + --packet \ + --provider-config /etc/cloud-sa/cloud-sa.json | tee /var/lib/rancher/k3s/server/manifests/vip.yaml ``` NOTE: the `—provider-config` actually comes from the secret we apply in step 5 (this will leave kube-vip waiting to start) From 13cc1cd9955cc3774672c514e275dc6475789a44 Mon Sep 17 00:00:00 2001 From: Michael Huttner Date: Fri, 18 Dec 2020 14:17:00 +0100 Subject: [PATCH 055/542] Fix documentation, kube-vip alias for containerd Fixes #142 --- docs/hybrid/static/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 68ded17b..e6955646 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -19,7 +19,7 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip"` +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip /kube-vip"` #### Docker `alias kube-vip="docker run --network host --rm plndr/kube-vip:0.2.3"` @@ -101,4 +101,4 @@ sudo kubeadm join $VIP:6443 \ ## Services -At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. \ No newline at end of file +At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. From 2e62ad98c209a05d2633f3f7e89e2cf32b4737c4 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 09:46:02 +0000 Subject: [PATCH 056/542] Fixes to capabilities and CI --- go.mod | 14 +++++++++++++- pkg/cluster/clusterLeader.go | 10 +++++----- pkg/kubevip/config_generator.go | 1 + pkg/leaderElection/leaderelection.go | 9 +++++---- pkg/packet/utils.go | 1 + pkg/vip/ddns.go | 1 + 6 files changed, 26 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 749f342e..6343db4c 100644 --- a/go.mod +++ b/go.mod @@ -58,4 +58,16 @@ require ( k8s.io/utils v0.0.0-20200912215256-4140de9c8800 // indirect ) -replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 +replace ( + github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 + + // CI fixes + github.com/plunder-app/kube-vip/pkg/bgp => ./github.com/plunder-app/kube-vip/pkg/bgp + github.com/plunder-app/kube-vip/pkg/cluster => ./github.com/plunder-app/kube-vip/pkg/cluster + github.com/plunder-app/kube-vip/pkg/detector => ./github.com/plunder-app/kube-vip/pkg/detector + github.com/plunder-app/kube-vip/pkg/kubevip => ./github.com/plunder-app/kube-vip/pkg/kubevip + github.com/plunder-app/kube-vip/pkg/leaderElection => ./github.com/plunder-app/kube-vip/pkg/leaderElection + github.com/plunder-app/kube-vip/pkg/loadbalancer => ./github.com/plunder-app/kube-vip/pkg/loadbalancer + github.com/plunder-app/kube-vip/pkg/manager => ./github.com/plunder-app/kube-vip/pkg/manager + github.com/plunder-app/kube-vip/pkg/packet => ./github.com/plunder-app/kube-vip/pkg/packet +) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index b2c72df8..c9be1e74 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -112,8 +112,8 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // use a Go context so we can tell the dns loop code when we // want to step down - ctxDns, cancelDns := context.WithCancel(context.Background()) - defer cancelDns() + ctxDNS, cancelDNS := context.WithCancel(context.Background()) + defer cancelDNS() // listen for interrupts or the Linux SIGTERM signal and cancel // our context, which the leader election code will observe and @@ -212,7 +212,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // setup ddns first // for first time, need to wait until IP is allocated from DHCP if cluster.Network.IsDDNS() { - if err := cluster.StartDDNS(ctxDns); err != nil { + if err := cluster.StartDDNS(ctxDNS); err != nil { log.Error(err) } } @@ -221,7 +221,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if cluster.Network.IsDNS() { log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) ipUpdater := vip.NewIPUpdater(cluster.Network) - ipUpdater.Run(ctxDns) + ipUpdater.Run(ctxDNS) } err = cluster.Network.AddIP() @@ -301,7 +301,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe log.Info("This node is becoming a follower within the cluster") // Stop the dns context - cancelDns() + cancelDNS() // Stop the Arp context if it is running cancelArp() diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 13496692..ed11fcd1 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -822,6 +822,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Capabilities: &corev1.Capabilities{ Add: []corev1.Capability{ "NET_ADMIN", + "NET_RAW", "SYS_TIME", }, }, diff --git a/pkg/leaderElection/leaderelection.go b/pkg/leaderElection/leaderelection.go index 155b7222..24afd72d 100644 --- a/pkg/leaderElection/leaderelection.go +++ b/pkg/leaderElection/leaderelection.go @@ -69,7 +69,7 @@ import ( ) const ( - JitterFactor = 1.2 + jitterFactor = 1.2 ) // NewLeaderElector creates a LeaderElector from a LeaderElectionConfig @@ -77,7 +77,7 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) { if lec.LeaseDuration <= lec.RenewDeadline { return nil, fmt.Errorf("leaseDuration must be greater than renewDeadline") } - if lec.RenewDeadline <= time.Duration(JitterFactor*float64(lec.RetryPeriod)) { + if lec.RenewDeadline <= time.Duration(jitterFactor*float64(lec.RetryPeriod)) { return nil, fmt.Errorf("renewDeadline must be greater than retryPeriod*JitterFactor") } if lec.LeaseDuration < 1 { @@ -97,7 +97,7 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) { } if lec.Lock == nil { - return nil, fmt.Errorf("Lock must not be nil.") + return nil, fmt.Errorf("Lock must not be nil") } le := LeaderElector{ config: lec, @@ -108,6 +108,7 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) { return &le, nil } +// LeaderElectionConfig defines the configuration for the leaderElection type LeaderElectionConfig struct { // Lock is the resource that will be used for locking Lock rl.Interface @@ -251,7 +252,7 @@ func (le *LeaderElector) acquire(ctx context.Context) bool { le.metrics.leaderOn(le.config.Name) klog.Infof("successfully acquired lease %v", desc) cancel() - }, le.config.RetryPeriod, JitterFactor, true, ctx.Done()) + }, le.config.RetryPeriod, jitterFactor, true, ctx.Done()) return succeeded } diff --git a/pkg/packet/utils.go b/pkg/packet/utils.go index aa7378f7..6cbe0406 100644 --- a/pkg/packet/utils.go +++ b/pkg/packet/utils.go @@ -38,6 +38,7 @@ func findSelf(c *packngo.Client, projectID string) *packngo.Device { return nil } +//GetPacketConfig will lookup the configuration from a file path func GetPacketConfig(providerConfig string) (string, string, error) { var config struct { AuthToken string `json:"apiKey"` diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 2d0801b3..788f67f7 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -23,6 +23,7 @@ type ddnsManager struct { network Network } +// NewDDNSManager returns a newly created Dynamic DNS manager func NewDDNSManager(ctx context.Context, network Network) DDNSManager { return &ddnsManager{ ctx: ctx, From 94204c3d5826053f4b549dc7c0998b4ae03163d3 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 13:15:23 +0000 Subject: [PATCH 057/542] Makefile fix --- Makefile | 27 ++++++++++----------------- go.mod | 13 +------------ 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 80e7ace2..1a61bc79 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - SHELL := /bin/sh # The name of the executable (default is current directory name) @@ -14,10 +13,6 @@ TARGETOS=linux # Use linker flags to provide version/build settings to the target LDFLAGS=-ldflags "-s -w -X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -extldflags -static" - -# go source files, ignore vendor directory -SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*") - DOCKERTAG ?= $(VERSION) REPOSITORY = plndr @@ -25,7 +20,7 @@ REPOSITORY = plndr all: check install -$(TARGET): $(SRC) +$(TARGET): @go build $(LDFLAGS) -o $(TARGET) build: $(TARGET) @@ -42,7 +37,7 @@ uninstall: clean @rm -f $$(which ${TARGET}) fmt: - @gofmt -l -w $(SRC) + @gofmt -l -w ./... demo: @cd demo @@ -51,7 +46,6 @@ demo: @cd .. ## Remote (push of images) - # This build a local docker image (x86 only) for quick testing dockerx86: @-rm ./kube-vip @@ -64,7 +58,6 @@ docker: @echo New Multi Architecture Docker image created ## Local (docker load of images) - # This will build a local docker image (x86 only), use make dockerLocal for all architectures dockerx86Local: @-rm ./kube-vip @@ -77,14 +70,14 @@ dockerLocal: @echo New Multi Architecture Docker image created simplify: - @gofmt -s -l -w $(SRC) + @gofmt -s -l -w ./... check: - @go mod tidy - @test -z "$(git status --porcelain)" - @test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" - @for d in $$(go list ./... | grep -v /vendor/); do golint $${d}; done - @go vet ${SRC} - + go mod tidy + test -z "$(git status --porcelain)" + test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" + golint ./... + go vet ./... + run: install - @$(TARGET) + @$(TARGET) \ No newline at end of file diff --git a/go.mod b/go.mod index 6343db4c..e9b3ee51 100644 --- a/go.mod +++ b/go.mod @@ -58,16 +58,5 @@ require ( k8s.io/utils v0.0.0-20200912215256-4140de9c8800 // indirect ) -replace ( - github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 +replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 - // CI fixes - github.com/plunder-app/kube-vip/pkg/bgp => ./github.com/plunder-app/kube-vip/pkg/bgp - github.com/plunder-app/kube-vip/pkg/cluster => ./github.com/plunder-app/kube-vip/pkg/cluster - github.com/plunder-app/kube-vip/pkg/detector => ./github.com/plunder-app/kube-vip/pkg/detector - github.com/plunder-app/kube-vip/pkg/kubevip => ./github.com/plunder-app/kube-vip/pkg/kubevip - github.com/plunder-app/kube-vip/pkg/leaderElection => ./github.com/plunder-app/kube-vip/pkg/leaderElection - github.com/plunder-app/kube-vip/pkg/loadbalancer => ./github.com/plunder-app/kube-vip/pkg/loadbalancer - github.com/plunder-app/kube-vip/pkg/manager => ./github.com/plunder-app/kube-vip/pkg/manager - github.com/plunder-app/kube-vip/pkg/packet => ./github.com/plunder-app/kube-vip/pkg/packet -) From b0f53c69dfceb35e3652b0209bc48ca9f30b7641 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 13:21:50 +0000 Subject: [PATCH 058/542] go vet fixes --- pkg/leaderElection/leaderelection_test.go | 28 ----------------------- pkg/loadbalancer/lb_tcp.go | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/pkg/leaderElection/leaderelection_test.go b/pkg/leaderElection/leaderelection_test.go index 10acfa7d..8c22697a 100644 --- a/pkg/leaderElection/leaderelection_test.go +++ b/pkg/leaderElection/leaderelection_test.go @@ -26,12 +26,10 @@ import ( coordinationv1 "k8s.io/api/coordination/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/apimachinery/pkg/util/diff" "k8s.io/client-go/kubernetes/fake" fakeclient "k8s.io/client-go/testing" rl "k8s.io/client-go/tools/leaderelection/resourcelock" @@ -335,32 +333,6 @@ func TestTryAcquireOrRenewLeases(t *testing.T) { testTryAcquireOrRenew(t, "leases") } -func TestLeaseSpecToLeaderElectionRecordRoundTrip(t *testing.T) { - holderIdentity := "foo" - leaseDurationSeconds := int32(10) - leaseTransitions := int32(1) - oldSpec := coordinationv1.LeaseSpec{ - HolderIdentity: &holderIdentity, - LeaseDurationSeconds: &leaseDurationSeconds, - AcquireTime: &metav1.MicroTime{time.Now()}, - RenewTime: &metav1.MicroTime{time.Now()}, - LeaseTransitions: &leaseTransitions, - } - - oldRecord := rl.LeaseSpecToLeaderElectionRecord(&oldSpec) - newSpec := rl.LeaderElectionRecordToLeaseSpec(oldRecord) - - if !equality.Semantic.DeepEqual(oldSpec, newSpec) { - t.Errorf("diff: %v", diff.ObjectReflectDiff(oldSpec, newSpec)) - } - - newRecord := rl.LeaseSpecToLeaderElectionRecord(&newSpec) - - if !equality.Semantic.DeepEqual(oldRecord, newRecord) { - t.Errorf("diff: %v", diff.ObjectReflectDiff(oldRecord, newRecord)) - } -} - func multiLockType(t *testing.T, objectType string) (primaryType, secondaryType string) { switch objectType { case rl.EndpointsLeasesResourceLock: diff --git a/pkg/loadbalancer/lb_tcp.go b/pkg/loadbalancer/lb_tcp.go index 8ce2cf61..fcb1442f 100644 --- a/pkg/loadbalancer/lb_tcp.go +++ b/pkg/loadbalancer/lb_tcp.go @@ -42,7 +42,7 @@ func (lb *LBInstance) startTCP(bindAddress string) error { err = l.SetDeadline(time.Now().Add(200 * time.Millisecond)) if err != nil { - log.Errorf("Error setting TCP deadline", err) + log.Errorf("Error setting TCP deadline [%v]", err) } fd, err := l.Accept() if err != nil { From c68a86d7acce91d75f4c2db7d84b6c6e101e0b17 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 13:25:16 +0000 Subject: [PATCH 059/542] Docker build fix --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cfea4704..1e083aec 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,4 +20,4 @@ jobs: - name: checks run: make check - name: test docker build - run: make dockerLocal + run: make dockerx86Local From 6dab4a4f35057a60f9d71d8cf7eaaa90788b5eda Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 17:14:45 +0000 Subject: [PATCH 060/542] Tidying of testing --- .github/workflows/ci.yaml | 2 ++ Makefile | 5 +++++ cmd/kube-vip-manifests.go | 4 ++-- pkg/kubevip/config_types.go | 2 +- testing/testing.sh | 12 ++++++------ 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1e083aec..731db6b3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,3 +21,5 @@ jobs: run: make check - name: test docker build run: make dockerx86Local + - name: Manifest generate + run: ./testing/testing.sh diff --git a/Makefile b/Makefile index 1a61bc79..63784b49 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,11 @@ dockerx86Local: @docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created +dockerx86Action: + @-rm ./kube-vip + @docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):action . + @echo New Multi Architecture Docker image created + dockerLocal: @-rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 9e3e6e8a..96288eb1 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -49,7 +49,7 @@ var kubeManifestPod = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && initConfig.VIP == "" { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "") { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } @@ -75,7 +75,7 @@ var kubeManifestDaemon = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && initConfig.VIP == "" { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "") { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index a3afa3f8..6313f827 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -33,7 +33,7 @@ type Config struct { // AddPeersAsBackends, this will automatically add RAFT peers as backends to a loadbalancer AddPeersAsBackends bool `yaml:"addPeersAsBackends"` - // VIP is the Virtual IP address exposed for the cluster + // VIP is the Virtual IP address exposed for the cluster (TODO: deprecate) VIP string `yaml:"vip"` // VIPCIDR is cidr range for the VIP (primarily needed for BGP) diff --git a/testing/testing.sh b/testing/testing.sh index 9b72b35b..8b51f4b3 100755 --- a/testing/testing.sh +++ b/testing/testing.sh @@ -1,8 +1,8 @@ #!/bin/bash -make build -./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection -./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp -./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true -./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection -rm ./kube-vip \ No newline at end of file +alias kube-vip="docker run --network host --rm plndr/kube-vip:action" + +kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection +kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp +kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true +kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection From d89e8a5852c750d4f46b4e387ad8d86b4c74cb78 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 17:23:01 +0000 Subject: [PATCH 061/542] Fix workflow --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 731db6b3..1dc40704 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,6 +20,6 @@ jobs: - name: checks run: make check - name: test docker build - run: make dockerx86Local + run: make dockerx86Action - name: Manifest generate run: ./testing/testing.sh From 627ec8da3c23696bb5c98cee798b4b3dbe0d5183 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 24 Dec 2020 17:28:55 +0000 Subject: [PATCH 062/542] final fix --- testing/testing.sh | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/testing/testing.sh b/testing/testing.sh index 8b51f4b3..4df91091 100755 --- a/testing/testing.sh +++ b/testing/testing.sh @@ -1,8 +1,5 @@ #!/bin/bash - -alias kube-vip="docker run --network host --rm plndr/kube-vip:action" - -kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection -kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp -kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true -kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection +docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection +docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp +docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true +docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection From 792369ccb2ac2f8bc08fbc903b2c28ab779b9b43 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sat, 26 Dec 2020 17:22:09 +0000 Subject: [PATCH 063/542] Fixes to serviceAccount --- pkg/kubevip/config_generator.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index ed11fcd1..3508e751 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -833,14 +833,15 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Env: newEnvironment, }, }, - HostNetwork: true, - ServiceAccountName: "kube-vip", + HostNetwork: true, }, } - // If this isn't inside a cluster then add the external path mount - if !inCluster { - + if inCluster { + // If we're running this inCluster then the acccount name will be required + newManifest.Spec.ServiceAccountName = "kube-vip" + } else { + // If this isn't inside a cluster then add the external path mount adminConfMount := corev1.VolumeMount{ Name: "kubeconfig", MountPath: "/etc/kubernetes/admin.conf", From 52468cef643db79867507c475910b7074e034f6b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 31 Dec 2020 11:45:25 +0000 Subject: [PATCH 064/542] Fixes to testing and config --- pkg/kubevip/config_generator.go | 24 ++++++++++++++++------ testing/testing.sh | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 3508e751..1519f44a 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -39,14 +39,19 @@ const ( //vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" + //vipCidr - defines the cidr that the vip will use + vipCidr = "vip_cidr" + + ///////////////////////////////////// + // TO DO: + // Determine how to tidy this mess up + ///////////////////////////////////// + //vipAddress - defines the address that the vip will expose // DEPRECATED: will be removed in a next release vipAddress = "vip_address" - //vipCidr - defines the cidr that the vip will use - vipCidr = "vip_cidr" - - //address - defines the address that would be used as a vip + // address - defines the address that would be used as a vip // it may be an IP or a DNS name, in case of a DNS name // kube-vip will try to resolve it and use the IP as a VIP address = "address" @@ -208,8 +213,15 @@ func ParseEnvironment(c *Config) error { if env != "" { // TODO - parse address net.Host() c.VIP = env - } else { - c.Address = os.Getenv(address) + // } else { + // c.VIP = os.Getenv(address) + } + + // Find address + env = os.Getenv(address) + if env != "" { + // TODO - parse address net.Host() + c.Address = env } // Find vip port diff --git a/testing/testing.sh b/testing/testing.sh index 4df91091..b94f69c6 100755 --- a/testing/testing.sh +++ b/testing/testing.sh @@ -1,5 +1,40 @@ #!/bin/bash + +abort() +{ + echo >&2 ' +*************** +*** ABORTED *** +*************** +' + echo "An error occurred. Exiting..." >&2 + exit 1 +} + +trap 'abort' 0 + +set -e +set -o pipefail + +echo "==> ARP w/services & controlplane" docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --services --leaderElection + +echo "==> BGP w/controlplane" docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp + +echo "==> BGP w/controlplane and specified peers" docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --bgp --bgppeers 192.168.0.2:12345::true,192.168.0.3:12345::true + +echo "==> BGP w/services & controlplane" docker run --network host --rm plndr/kube-vip:action manifest pod --interface eth0 --vip 192.168.0.1 --controlplane --arp --leaderElection + +echo "==> ARP w/controlplane (using --address)" +docker run --network host --rm plndr/kube-vip:action manifest pod --interface enx001e063262b1 --address k8s-api-vip.lan --arp --leaderElection --controlplane + +trap : 0 + +echo >&2 ' +************ +*** DONE *** +************ +' From 8d5a7b25d782fad72ee36ff9248961a3911b697e Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 31 Dec 2020 15:39:28 +0000 Subject: [PATCH 065/542] Update index.md --- docs/hybrid/static/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index e6955646..2c4b4373 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -19,10 +19,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.2.3 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.0 vip /kube-vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.2.3"` +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.0"` ### ARP @@ -38,7 +38,7 @@ kube-vip manifest pod \ --controlplane \ --services \ --arp \ - --leaderElection + --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml ``` ### BGP @@ -56,7 +56,7 @@ kube-vip manifest pod \ --controlplane \ --services \ --bgp \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml ``` ### BGP with Packet @@ -72,7 +72,7 @@ kube-vip manifest pod \ --bgp \ --packet \ --packetAPI xxxxxxx \ - --packetProjectID xxxxx + --packetProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml ``` ## Deploy your Kubernetes Cluster From 7cd9d9a6549d3b3e175994de899cae1c362a4b53 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 31 Dec 2020 15:40:48 +0000 Subject: [PATCH 066/542] Update index.md --- docs/hybrid/static/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 2c4b4373..8b63a1ff 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -71,7 +71,7 @@ kube-vip manifest pod \ --services \ --bgp \ --packet \ - --packetAPI xxxxxxx \ + --packetAPI xxxxxxx \ --packetProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml ``` From 22103ef8574cfab9e37f72b3e82f36898ad2787c Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 31 Dec 2020 15:41:14 +0000 Subject: [PATCH 067/542] Update index.md --- docs/hybrid/static/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 8b63a1ff..0e835ebe 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -71,7 +71,7 @@ kube-vip manifest pod \ --services \ --bgp \ --packet \ - --packetAPI xxxxxxx \ + --packetKey xxxxxxx \ --packetProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml ``` From 8570ae8310714c8379284a66a6c64e73263367d8 Mon Sep 17 00:00:00 2001 From: Franciosi Date: Tue, 5 Jan 2021 17:02:45 -0300 Subject: [PATCH 068/542] Update README.md Small typo fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b8fa499..aa82eaf5 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ The purpose of `kube-vip` is to simplify the building of HA Kubernetes clusters, **LoadBalancing**: - [HAProxy](http://www.haproxy.org/) - [Nginx](http://nginx.com) -- Hardware Load-balancer(functionality differs per vendor) +- Hardware Load-balancer (functionality differs per vendor) All of these would require a separate level of configuration and in some infrastructures multiple teams in order to implement. Also when considering the software components, they may require packaging into containers or if they’re pre-packaged then security and transparency may be an issue. Finally, in edge environments we may have limited room for hardware (no HW load-balancer) or packages solutions in the correct architectures might not exist (e.g. ARM). Luckily with `kube-vip` being written in GO, it’s small(ish) and easy to build for multiple architectures, with the added security benefit of being the only thing needed in the container. From db9da78bff5717efe40d5c3a60708ecd615ec7a3 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 20 Jan 2021 13:29:52 +0000 Subject: [PATCH 069/542] Annotaions watcher --- Makefile | 2 +- cmd/kube-vip.go | 1 + pkg/kubevip/config_envvar.go | 134 +++++++++++++++++++++++++++++ pkg/kubevip/config_generator.go | 148 ++++---------------------------- pkg/kubevip/config_types.go | 3 + pkg/manager/manager.go | 24 +++++- pkg/manager/manager_bgp.go | 9 +- pkg/manager/watcher.go | 120 ++++++++++++++++++++++++++ 8 files changed, 300 insertions(+), 141 deletions(-) create mode 100644 pkg/kubevip/config_envvar.go diff --git a/Makefile b/Makefile index 63784b49..aed17ac2 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.3.0 +VERSION := 0.3.1 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 3ead9d62..ffac8c6f 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -67,6 +67,7 @@ func init() { kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "listen port for the VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go new file mode 100644 index 00000000..cd3fbd9b --- /dev/null +++ b/pkg/kubevip/config_envvar.go @@ -0,0 +1,134 @@ +package kubevip + +// Environment variables +const ( + + //vipArp - defines if the arp broadcast should be enabled + vipArp = "vip_arp" + + //vipLeaderElection - defines if the kubernetes algorithim should be used + vipLeaderElection = "vip_leaderelection" + + //vipLeaderElection - defines if the kubernetes algorithim should be used + vipLeaseDuration = "vip_leaseduration" + + //vipLeaderElection - defines if the kubernetes algorithim should be used + vipRenewDeadline = "vip_renewdeadline" + + //vipLeaderElection - defines if the kubernetes algorithim should be used + vipRetryPeriod = "vip_retryperiod" + + //vipLogLevel - defines the level of logging to produce (5 being the most verbose) + vipLogLevel = "vip_loglevel" + + //vipInterface - defines the interface that the vip should bind too + vipInterface = "vip_interface" + + //vipCidr - defines the cidr that the vip will use + vipCidr = "vip_cidr" + + ///////////////////////////////////// + // TO DO: + // Determine how to tidy this mess up + ///////////////////////////////////// + + //vipAddress - defines the address that the vip will expose + // DEPRECATED: will be removed in a next release + vipAddress = "vip_address" + + // address - defines the address that would be used as a vip + // it may be an IP or a DNS name, in case of a DNS name + // kube-vip will try to resolve it and use the IP as a VIP + address = "address" + + //port - defines the port for the VIP + port = "port" + + // annotations + annotations = "annotation" + + //vipDdns - defines if use dynamic dns to allocate IP for "address" + vipDdns = "vip_ddns" + + //vipSingleNode - defines the vip start as a single node cluster + vipSingleNode = "vip_singlenode" + + //vipStartLeader - will start this instance as the leader of the cluster + vipStartLeader = "vip_startleader" + + //vipPeers defines the configuration of raft peer(s) + vipPeers = "vip_peers" + + //vipLocalPeer defines the configuration of the local raft peer + vipLocalPeer = "vip_localpeer" + + //vipRemotePeers defines the configuration of the local raft peer + vipRemotePeers = "vip_remotepeers" + + //vipAddPeersToLB defines that RAFT peers should be added to the load-balancer + vipAddPeersToLB = "vip_addpeerstolb" + + //vipPacket defines that the packet API will be used for EIP + vipPacket = "vip_packet" + + //vipPacketProject defines which project within Packet to use + vipPacketProject = "vip_packetproject" + + //vipPacketProjectID defines which projectID within Packet to use + vipPacketProjectID = "vip_packetprojectid" + + //providerConfig defines a path to a configuration that should be parsed + providerConfig = "provider_config" + + //bgpEnable defines if BGP should be enabled + bgpEnable = "bgp_enable" + //bgpRouterID defines the routerID for the BGP server + bgpRouterID = "bgp_routerid" + //bgpRouterInterface defines the interface that we can find the address for + bgpRouterInterface = "bgp_routerinterface" + //bgpRouterAS defines the AS for the BGP server + bgpRouterAS = "bgp_as" + //bgpPeerAddress defines the address for a BGP peer + bgpPeerAddress = "bgp_peeraddress" + //bgpPeers defines the address for a BGP peer + bgpPeers = "bgp_peers" + //bgpPeerAS defines the AS for a BGP peer + bgpPeerAS = "bgp_peeras" + //bgpPeerAS defines the AS for a BGP peer + bgpPeerPassword = "bgp_peerpass" + //bgpMultiHop enables mulithop routing + bgpMultiHop = "bgp_multihop" + + //cpNamespace defines the namespace the control plane pods will run in + cpNamespace = "cp_namespace" + + //cpEnable starts kube-vip in the hybrid mode + cpEnable = "cp_enable" + + //cpEnable starts kube-vip in the hybrid mode + svcEnable = "svc_enable" + + //lbEnable defines if the load-balancer should be enabled + lbEnable = "lb_enable" + + //lbBindToVip defines if the load-balancer should bind ONLY to the virtual IP + lbBindToVip = "lb_bindtovip" + + //lbName defines the name of load-balancer + lbName = "lb_name" + + //lbType defines the type of load-balancer + lbType = "lb_type" + + //lbPort defines the port of load-balancer + lbPort = "lb_port" + + //lbBackendPort defines a port that ALL backends are using + lbBackendPort = "lb_backendport" + + //lbBackends defines the backends of load-balancer + lbBackends = "lb_backends" + + //vipConfigMap defines the configmap that kube-vip will watch for service definitions + vipConfigMap = "vip_configmap" +) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 1519f44a..480380e2 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -15,136 +15,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Environment variables -const ( - - //vipArp - defines if the arp broadcast should be enabled - vipArp = "vip_arp" - - //vipLeaderElection - defines if the kubernetes algorithim should be used - vipLeaderElection = "vip_leaderelection" - - //vipLeaderElection - defines if the kubernetes algorithim should be used - vipLeaseDuration = "vip_leaseduration" - - //vipLeaderElection - defines if the kubernetes algorithim should be used - vipRenewDeadline = "vip_renewdeadline" - - //vipLeaderElection - defines if the kubernetes algorithim should be used - vipRetryPeriod = "vip_retryperiod" - - //vipLogLevel - defines the level of logging to produce (5 being the most verbose) - vipLogLevel = "vip_loglevel" - - //vipInterface - defines the interface that the vip should bind too - vipInterface = "vip_interface" - - //vipCidr - defines the cidr that the vip will use - vipCidr = "vip_cidr" - - ///////////////////////////////////// - // TO DO: - // Determine how to tidy this mess up - ///////////////////////////////////// - - //vipAddress - defines the address that the vip will expose - // DEPRECATED: will be removed in a next release - vipAddress = "vip_address" - - // address - defines the address that would be used as a vip - // it may be an IP or a DNS name, in case of a DNS name - // kube-vip will try to resolve it and use the IP as a VIP - address = "address" - - //port - defines the port for the VIP - port = "port" - - //vipDdns - defines if use dynamic dns to allocate IP for "address" - vipDdns = "vip_ddns" - - //vipSingleNode - defines the vip start as a single node cluster - vipSingleNode = "vip_singlenode" - - //vipStartLeader - will start this instance as the leader of the cluster - vipStartLeader = "vip_startleader" - - //vipPeers defines the configuration of raft peer(s) - vipPeers = "vip_peers" - - //vipLocalPeer defines the configuration of the local raft peer - vipLocalPeer = "vip_localpeer" - - //vipRemotePeers defines the configuration of the local raft peer - vipRemotePeers = "vip_remotepeers" - - //vipAddPeersToLB defines that RAFT peers should be added to the load-balancer - vipAddPeersToLB = "vip_addpeerstolb" - - //vipPacket defines that the packet API will be used for EIP - vipPacket = "vip_packet" - - //vipPacketProject defines which project within Packet to use - vipPacketProject = "vip_packetproject" - - //vipPacketProjectID defines which projectID within Packet to use - vipPacketProjectID = "vip_packetprojectid" - - //providerConfig defines a path to a configuration that should be parsed - providerConfig = "provider_config" - - //bgpEnable defines if BGP should be enabled - bgpEnable = "bgp_enable" - //bgpRouterID defines the routerID for the BGP server - bgpRouterID = "bgp_routerid" - //bgpRouterInterface defines the interface that we can find the address for - bgpRouterInterface = "bgp_routerinterface" - //bgpRouterAS defines the AS for the BGP server - bgpRouterAS = "bgp_as" - //bgpPeerAddress defines the address for a BGP peer - bgpPeerAddress = "bgp_peeraddress" - //bgpPeers defines the address for a BGP peer - bgpPeers = "bgp_peers" - //bgpPeerAS defines the AS for a BGP peer - bgpPeerAS = "bgp_peeras" - //bgpPeerAS defines the AS for a BGP peer - bgpPeerPassword = "bgp_peerpass" - //bgpMultiHop enables mulithop routing - bgpMultiHop = "bgp_multihop" - - //cpNamespace defines the namespace the control plane pods will run in - cpNamespace = "cp_namespace" - - //cpEnable starts kube-vip in the hybrid mode - cpEnable = "cp_enable" - - //cpEnable starts kube-vip in the hybrid mode - svcEnable = "svc_enable" - - //lbEnable defines if the load-balancer should be enabled - lbEnable = "lb_enable" - - //lbBindToVip defines if the load-balancer should bind ONLY to the virtual IP - lbBindToVip = "lb_bindtovip" - - //lbName defines the name of load-balancer - lbName = "lb_name" - - //lbType defines the type of load-balancer - lbType = "lb_type" - - //lbPort defines the port of load-balancer - lbPort = "lb_port" - - //lbBackendPort defines a port that ALL backends are using - lbBackendPort = "lb_backendport" - - //lbBackends defines the backends of load-balancer - lbBackends = "lb_backends" - - //vipConfigMap defines the configmap that kube-vip will watch for service definitions - vipConfigMap = "vip_configmap" -) - // ParseEnvironment - will popultate the configuration from environment variables func ParseEnvironment(c *Config) error { @@ -292,6 +162,12 @@ func ParseEnvironment(c *Config) error { c.SingleNode = b } + // Find annotation configuration + env = os.Getenv(annotations) + if env != "" { + c.Annotations = env + } + // Find Start As Leader // TODO - does this need depricating? // Required when the host sets itself as leader before the state change @@ -665,6 +541,18 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, raft...) } + // If we're specifying an annotation configuration + if c.Annotations != "" { + annotations := []corev1.EnvVar{ + { + Name: annotations, + Value: c.Annotations, + }, + } + newEnvironment = append(newEnvironment, annotations...) + + } + // If we're specifying a configuration if c.ProviderConfig != "" { provider := []corev1.EnvVar{ diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 6313f827..59959e15 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -21,6 +21,9 @@ type Config struct { // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) EnableServices bool `yaml:"enableServices"` + // Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations + Annotations string + // LeaderElection defines the settings around Kubernetes LeaderElection LeaderElection diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 3eaf21d2..98c82fb1 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -84,12 +84,12 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { if err != nil { return nil, err } - log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) + log.Debugf("Using external Kubernetes configuration from file [%s]", configPath) } else { // Second check in home directory for kube config configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") if fileExists(configPath) { - log.Debugf("Using outside Kubernetes configuration from file [%s]", configPath) + log.Debugf("Using external Kubernetes configuration from file [%s]", configPath) cfg, err = clientcmd.BuildConfigFromFlags("", configPath) if err != nil { return nil, err @@ -109,6 +109,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. if config.EnableControlPane { + log.Debugf("Modifying address of Kubernetes server to hostname") // We modify the config so that we can always speak to the correct host id, err := os.Hostname() if err != nil { @@ -144,6 +145,12 @@ func (sm *Manager) Start() error { // Add Notification for SIGKILL (sent from Kubernetes) signal.Notify(sm.signalChan, syscall.SIGKILL) + // If Annotations have been set then we will look them up + err := sm.parseAnnotations() + if err != nil { + return err + } + // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { log.Infoln("Starting Kube-vip Manager with the BGP engine") @@ -179,3 +186,16 @@ func fileExists(filename string) bool { } return !info.IsDir() } + +func (sm *Manager) parseAnnotations() error { + if sm.config.Annotations == "" { + log.Fatalln("No Node annotations to parse") + return nil + } + + err := sm.annotationsWatcher() + if err != nil { + return err + } + return nil +} diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 31c5418e..33f9aa7e 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -57,13 +57,6 @@ func (sm *Manager) startBGP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - go func() { - <-sm.signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context, which will in turn cancel the leadership - cancel() - }() - // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { if sm.bgpServer != nil { @@ -97,7 +90,7 @@ func (sm *Manager) startBGP() error { } }() - // Check if we're also starting the services, if now we can sit and wait on the closing channel and return here + // 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") diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 88c49eb4..844ac49d 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -3,6 +3,8 @@ package manager import ( "context" "fmt" + "os" + "strconv" log "github.com/sirupsen/logrus" @@ -10,6 +12,7 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" watchtools "k8s.io/client-go/tools/watch" "k8s.io/apimachinery/pkg/watch" @@ -89,3 +92,120 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } + +// This file handles the watching of node annotations for configuration, it will exit once the annotations are +// present +func (sm *Manager) annotationsWatcher() error { + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + log.Infoln("Kube-Vip is waiting for annotations to be present on this node") + hostname, err := os.Hostname() + if err != nil { + return err + } + + // TEST - REMOVE + hostname = "k8s.bgp01" + + labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": hostname}} + listOptions := metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + } + + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Nodes().Watch(context.Background(), listOptions) + }, + }) + if err != nil { + return fmt.Errorf("error creating annotations watcher: %s", err.Error()) + } + + go func() { + <-sm.signalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context + rw.Stop() + }() + + ch := rw.ResultChan() + //defer rw.Stop() + + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + + nodeAsn := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] + if nodeAsn != "" { + u64, err := strconv.ParseUint(nodeAsn, 10, 32) + if err != nil { + return err + } + sm.config.BGPConfig.AS = uint32(u64) + } else { + continue + } + srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] + if srcIP != "" { + sm.config.BGPConfig.SourceIP = srcIP + } else { + continue + } + peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] + if peerASN != "" { + u64, err := strconv.ParseUint(peerASN, 10, 32) + if err != nil { + return err + } + sm.config.BGPPeerConfig.AS = uint32(u64) + } else { + continue + } + peerIP := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] + if peerIP != "" { + sm.config.BGPPeerConfig.Address = peerIP + } else { + continue + } + // Add the peer configuration to the overall BGP configuration + log.Infoln("Annotations have been succesfully parsed") + sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + rw.Stop() + break + case watch.Deleted: + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + + log.Infof("Node [%s] has been deleted", node.Name) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Error("Error attempting to watch Kubernetes services") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + + log.Infoln("Exiting Annotations watcher") + return nil + +} From 50945b85f5b67705fe8a07c4f045eddd5be5b291 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 20 Jan 2021 19:46:16 +0000 Subject: [PATCH 070/542] Fixes to rbac and signals --- docs/manifests/rbac.yaml | 2 +- pkg/bgp/hosts.go | 2 +- pkg/cluster/singleNode.go | 3 +-- pkg/manager/manager.go | 2 +- pkg/manager/manager_bgp.go | 2 +- pkg/manager/watcher.go | 21 ++++++++++++--------- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/manifests/rbac.yaml b/docs/manifests/rbac.yaml index 7e835985..446929bb 100644 --- a/docs/manifests/rbac.yaml +++ b/docs/manifests/rbac.yaml @@ -12,7 +12,7 @@ metadata: name: system:kube-vip-role rules: - apiGroups: [""] - resources: ["services", "services/status"] + resources: ["services", "services/status", "nodes"] verbs: ["list","get","watch", "update"] --- kind: ClusterRoleBinding diff --git a/pkg/bgp/hosts.go b/pkg/bgp/hosts.go index 2c2f0211..5d78b3b9 100644 --- a/pkg/bgp/hosts.go +++ b/pkg/bgp/hosts.go @@ -15,7 +15,7 @@ func (b *Server) AddHost(addr string) (err error) { } p := b.getPath(ip) if p == nil { - return + return err } _, err = b.s.AddPath(context.Background(), &api.AddPathRequest{ diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 0f06291b..8cccdec4 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -108,7 +108,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro // StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) error { // Start a kube-vip loadbalancer service - log.Infoln("Starting kube-vip as a LoadBalancer Service") + log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) @@ -135,7 +135,6 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // Lets advertise the VIP over BGP, the host needs to be passed using CIDR notation cidrVip := fmt.Sprintf("%s/%s", cluster.Network.IP(), c.VIPCIDR) log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) - err = bgp.AddHost(cidrVip) if err != nil { log.Error(err) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 98c82fb1..6bd13c60 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -189,7 +189,7 @@ func fileExists(filename string) bool { func (sm *Manager) parseAnnotations() error { if sm.config.Annotations == "" { - log.Fatalln("No Node annotations to parse") + log.Debugf("No Node annotations to parse") return nil } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 33f9aa7e..3223c68c 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -47,7 +47,7 @@ func (sm *Manager) startBGP() error { } } - log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + log.Info("Starting the BGP server to adverise VIP routes to BGP peers") sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) if err != nil { return err diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 844ac49d..2be34942 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -32,9 +32,13 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if err != nil { return fmt.Errorf("error creating services watcher: %s", err.Error()) } - + go func() { + <-sm.signalChan + // Cancel the context + rw.Stop() + }() ch := rw.ResultChan() - defer rw.Stop() + //defer rw.Stop() log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { @@ -103,9 +107,6 @@ func (sm *Manager) annotationsWatcher() error { return err } - // TEST - REMOVE - hostname = "k8s.bgp01" - labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/hostname": hostname}} listOptions := metav1.ListOptions{ LabelSelector: labels.Set(labelSelector.MatchLabels).String(), @@ -141,9 +142,9 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - nodeAsn := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] - if nodeAsn != "" { - u64, err := strconv.ParseUint(nodeAsn, 10, 32) + nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] + if nodeASN != "" { + u64, err := strconv.ParseUint(nodeASN, 10, 32) if err != nil { return err } @@ -153,7 +154,7 @@ func (sm *Manager) annotationsWatcher() error { } srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] if srcIP != "" { - sm.config.BGPConfig.SourceIP = srcIP + sm.config.BGPConfig.RouterID = srcIP } else { continue } @@ -176,6 +177,8 @@ func (sm *Manager) annotationsWatcher() error { // Add the peer configuration to the overall BGP configuration log.Infoln("Annotations have been succesfully parsed") sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + log.Debugf("%s / %d / %s / %d \n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) + rw.Stop() break case watch.Deleted: From a945113b3d8116a914db7627c569177c11338e26 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 22 Jan 2021 12:10:59 +0000 Subject: [PATCH 071/542] Rename and docs update --- cmd/kube-vip.go | 14 ++++++------ docs/hybrid/daemonset/index.md | 38 +++++++++++++++++++++++++++++---- docs/hybrid/index.md | 37 ++++++++++++++++---------------- docs/hybrid/services/index.md | 2 +- docs/hybrid/static/index.md | 37 ++++++++++++++++++++++++++------ pkg/cluster/clusterLeader.go | 4 ++-- pkg/kubevip/config_generator.go | 18 ++++++++-------- pkg/kubevip/config_types.go | 16 +++++++------- pkg/manager/manager_bgp.go | 4 ++-- pkg/packet/bgp.go | 10 ++++----- pkg/packet/eip.go | 4 ++-- pkg/service/manager_bgp.go | 2 +- 12 files changed, 120 insertions(+), 66 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index ffac8c6f..c9b7f815 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -80,10 +80,10 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AddPeersAsBackends, "addPeersToLB", true, "Add raft peers to the load-balancer") // Packet flags - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnablePacket, "packet", false, "This will use the Packet API (requires the token ENV) to update the EIP <-> VIP") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketAPIKey, "packetKey", "", "The API token for authenticating with the Packet API") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProject, "packetProject", "", "The name of project already created within Packet") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.PacketProjectID, "packetProjectID", "", "The ID of project already created within Packet") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableMetal, "metal", false, "This will use the Equinix Metal API (requires the token ENV) to update the EIP <-> VIP") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalAPIKey, "metalKey", "", "The API token for authenticating with the Equinix Metal API") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProject, "metalProject", "", "The name of project already created within Equinix Metal") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProjectID, "metalrojectID", "", "The ID of project already created within Equinix Metal") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // Load Balancer flags @@ -209,14 +209,14 @@ var kubeVipManager = &cobra.Command{ } // If Packet is enabled and there is a provider configuration passed - if initConfig.EnablePacket { + if initConfig.EnableMetal { if providerConfig != "" { providerAPI, providerProject, err := packet.GetPacketConfig(providerConfig) if err != nil { log.Fatalf("%v", err) } - initConfig.PacketAPIKey = providerAPI - initConfig.PacketProject = providerProject + initConfig.MetalAPIKey = providerAPI + initConfig.MetalProject = providerProject } } diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index a63835b3..86e17dad 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -36,10 +36,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.0 vip"` +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.0"` +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` ### BGP Example @@ -134,7 +134,37 @@ spec: - `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) - `env {...}` - We pass the configuration into the kube-vip pod through environment variables. -## K3s overview (on packet) +## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) + +The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations packet.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --services \ + --bgp \ + --annotations packet.com \ + --inCluster | k apply -f - +``` + +### Troubleshooting + +If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node: + +``` +kubectl describe node k8s.bgp02 +... +Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock + node.alpha.kubernetes.io/ttl: 0 + packet.com/node-asn: 65000 + packet.com/peer-asn: 65530 + packet.com/peer-ip: x.x.x.x + packet.com/src-ip: x.x.x.x +``` + +Additionally examining the logs of the Packet CCM may reveal why the node is not yet ready. + +## K3s overview (on Equinix Metal) ### Step 1: TIDY (best if something was running before) `rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; ip addr flush dev lo; ip addr add 127.0.0.1/8 dev lo; mkdir -p /var/lib/rancher/k3s/server/manifests/` @@ -158,7 +188,7 @@ kube-vip manifest daemonset \ --inCluster \ --taint \ --bgp \ - --packet \ + --metal \ --provider-config /etc/cloud-sa/cloud-sa.json | tee /var/lib/rancher/k3s/server/manifests/vip.yaml ``` diff --git a/docs/hybrid/index.md b/docs/hybrid/index.md index dc856616..fe82c3e1 100644 --- a/docs/hybrid/index.md +++ b/docs/hybrid/index.md @@ -84,16 +84,17 @@ When using `kube-vip` as a daemonset the details are available [here](./daemonse | |`--bgpRouterID`|``|Typically the address of the local node| | |`--localAS`|default 65000|The AS we peer from| | |`--bgppeers`|``|Comma seperate list of BGP peers| -| |`--peerAddress`|``|(deprecated), Address of a single BGP Peer| -| |`--peerAS`|default 65000|(deprecated), AS of a single BGP Peer| -| |`--peerPass`|""|(deprecated), Password to work with a single BGP Peer| -| |`--multiHop`|Enables eBGP MultiHop|(deprecated), Enable multiHop with a single BGP Peer| -|**Packet**|||(To be deprecated)| -| |`--packet`|Enables Packet API calls|| -| |`--packetKey`|Packet API token|| -| |`--packetProject`|Packet Project (Name)|| -| |`--packetProjectID`|Packet Project (UUID)|| -| |`--provider-config`|Path to the Packet provider configuration|Requires the Packet CCM| +| |`--peerAddress`|``|Address of a single BGP Peer| +| |`--peerAS`|default 65000|AS of a single BGP Peer| +| |`--peerPass`|""| Password to work with a single BGP Peer| +| |`--multiHop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| +| |`--annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| +|**Equinix Metal**|||(May be deprecated)| +| |`--metal`|Enables Equinix Metal API calls|| +| |`--metalKey`|Equinix Metal API token|| +| |`--metalProject`|Equinix Metal Project (Name)|| +| |`--metalProjectID`|Equinix Metal Project (UUID)|| +| |`--provider-config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| ## Changelog @@ -121,20 +122,20 @@ The following new flags are used: - `--peerAS` The AS number for a BGP peer - `--peerAddress` The address of a BGP peer -### BGP Packet support +### Equinix Metal BGP support -If the `--bgp` flag is passed alone with the Packet flags `packet, packetKey and packetProject`, then the Packet API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Packet much simpler. +If the `--bgp` flag is passed along with the Equinix Metal flags `metal, metalKey and metalProject`, then Equinix Metal API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Equinix Metal much simpler. -## Packet Support (added in 0.1.7) +## Equinix Metal Control Plane Support (added in 0.1.8) -Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Packet Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Packet account and create a EIP (either public (eek) or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Packet project we can now apply this address to the servers that live in the same project. +Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Equinix Metal Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Equinix Metal account and create a EIP (either public or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Equinix Metal project we can now apply this address to the servers that live in the same project. In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. The following new flags are used: -- `--packet` which enables the use of the Packet API -- `--packetKey` which is our API key -- `--packetProject`which is the name of our Packet project where our servers and EIP are located. +- `--metal` which enables the use of the Equinix Metal API +- `--metalKey` which is our API key +- `--metalProject`which is the name of our Equinix Metal project where our servers and EIP are located. -*Also* the `--arp` flag should NOT be used as it wont work within the Packet network. \ No newline at end of file +*Also* the `--arp` flag should NOT be used as it wont work within the Equinix Metal network. \ No newline at end of file diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index 284c1dba..4c77a63a 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -166,7 +166,7 @@ $ curl externalIP:32380 ... ``` -### Expose with packet (using the `plndr-cloud-provider`) +### Expose with Equinix Metal (using the `plndr-cloud-provider`) Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 0e835ebe..47df8a26 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -19,10 +19,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.0 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.0"` +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` ### ARP @@ -59,9 +59,31 @@ kube-vip manifest pod \ --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml ``` -### BGP with Packet +### BGP with Equinix Metal -We can enable `kube-vip` with the capability to pull all of the required configuration for BGP by passing the `--packet` flag and the API Key and our project ID. +When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). + +**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. + +#### Creating a manifest using the API + +We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. + +``` +kube-vip manifest pod \ + --interface $INTERFACE\ + --vip $VIP \ + --controlplane \ + --services \ + --bgp \ + --metal \ + --metalKey xxxxxxx \ + --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +#### Creating a manifest using the metadata + +We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. ``` kube-vip manifest pod \ @@ -70,9 +92,10 @@ kube-vip manifest pod \ --controlplane \ --services \ --bgp \ - --packet \ - --packetKey xxxxxxx \ - --packetProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml + --peerAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].peer_as') \ + --peerAddress $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].peer_ips[0]') \ + --localAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].customer_as') \ + --bgpRouterID $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].customer_ip') | sudo tee /etc/kubernetes/manifests/vip.yaml ``` ## Deploy your Kubernetes Cluster diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index c9be1e74..eb2b4a25 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -152,7 +152,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client - if c.EnablePacket { + if c.EnableMetal { packetClient, err = packngo.NewClient() if err != nil { log.Error(err) @@ -229,7 +229,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe log.Warnf("%v", err) } - if c.EnablePacket { + if c.EnableMetal { // We're not using Packet with BGP if !c.EnableBGP { // Attempt to attach the EIP in the standard manner diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 480380e2..87eab70a 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -321,21 +321,21 @@ func ParseEnvironment(c *Config) error { if err != nil { return err } - c.EnablePacket = b + c.EnableMetal = b } // Find the Packet project name env = os.Getenv(vipPacketProject) if env != "" { // TODO - parse address net.Host() - c.PacketProject = env + c.MetalProject = env } // Find the Packet project ID env = os.Getenv(vipPacketProjectID) if env != "" { // TODO - parse address net.Host() - c.PacketProjectID = env + c.MetalProjectID = env } // Enable the load-balancer @@ -565,23 +565,23 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } // If Packet is enabled then add it to the manifest - if c.EnablePacket { + if c.EnableMetal { packet := []corev1.EnvVar{ { Name: vipPacket, - Value: strconv.FormatBool(c.EnablePacket), + Value: strconv.FormatBool(c.EnableMetal), }, { Name: vipPacketProject, - Value: c.PacketProject, + Value: c.MetalProject, }, { Name: vipPacketProjectID, - Value: c.PacketProjectID, + Value: c.MetalProjectID, }, { Name: "PACKET_AUTH_TOKEN", - Value: c.PacketAPIKey, + Value: c.MetalAPIKey, }, } newEnvironment = append(newEnvironment, packet...) @@ -598,7 +598,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, bgp...) } // If BGP, but we're not using packet - if c.EnableBGP && !c.EnablePacket { + if c.EnableBGP && !c.EnableMetal { bgpConfig := []corev1.EnvVar{ { Name: bgpRouterID, diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 59959e15..92e26d48 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -71,17 +71,17 @@ type Config struct { BGPPeerConfig bgp.Peer BGPPeers []string - // EnablePacket, will use the packet API to update the EIP <-> VIP (if BGP is enabled then BGP will be used) - EnablePacket bool `yaml:"enablePacket"` + // EnablePacket, will use the metal API to update the EIP <-> VIP (if BGP is enabled then BGP will be used) + EnableMetal bool `yaml:"enableMetal"` - // PacketAPIKey, is the API token used to authenticate to the API - PacketAPIKey string + // MetalAPIKey, is the API token used to authenticate to the API + MetalAPIKey string - // PacketProject, is the name of a particular defined project - PacketProject string + // MetalProject, is the name of a particular defined project + MetalProject string - // PacketProjectID, is the name of a particular defined project - PacketProjectID string + // MetalProjectID, is the name of a particular defined project + MetalProjectID string // ProviderConfig, is the path to a provider configuration file ProviderConfig string diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 3223c68c..03b6ad99 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -20,7 +20,7 @@ func (sm *Manager) startBGP() error { // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client - if sm.config.EnablePacket { + if sm.config.EnableMetal { if sm.config.ProviderConfig != "" { key, project, err := packet.GetPacketConfig(sm.config.ProviderConfig) if err != nil { @@ -29,7 +29,7 @@ func (sm *Manager) startBGP() error { // Set the environment variable with the key for the project os.Setenv("PACKET_AUTH_TOKEN", key) // Update the configuration with the project key - sm.config.PacketProjectID = project + sm.config.MetalProjectID = project } } packetClient, err = packngo.NewClient() diff --git a/pkg/packet/bgp.go b/pkg/packet/bgp.go index f62551e0..01e80f14 100644 --- a/pkg/packet/bgp.go +++ b/pkg/packet/bgp.go @@ -9,17 +9,17 @@ import ( log "github.com/sirupsen/logrus" ) -// BGPLookup will use the Packet API functions to populate the BGP information +// BGPLookup will use the Equinix Metal API functions to populate the BGP information func BGPLookup(c *packngo.Client, k *kubevip.Config) error { var thisDevice *packngo.Device - if k.PacketProjectID == "" { - proj := findProject(k.PacketProject, c) + if k.MetalProjectID == "" { + proj := findProject(k.MetalProject, c) if proj == nil { - return fmt.Errorf("Unable to find Project [%s]", k.PacketProject) + return fmt.Errorf("Unable to find Project [%s]", k.MetalProject) } thisDevice = findSelf(c, proj.ID) } else { - thisDevice = findSelf(c, k.PacketProjectID) + thisDevice = findSelf(c, k.MetalProjectID) } if thisDevice == nil { return fmt.Errorf("Unable to find local/this device in packet API") diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index e3696476..8017dd8d 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -13,9 +13,9 @@ import ( func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { // Find our project - proj := findProject(k.PacketProject, c) + proj := findProject(k.MetalProject, c) if proj == nil { - return fmt.Errorf("Unable to find Project [%s]", k.PacketProject) + return fmt.Errorf("Unable to find Project [%s]", k.MetalProject) } ips, _, _ := c.ProjectIPs.List(proj.ID, &packngo.ListOptions{}) diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index c5f2525f..d3d82f5e 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -21,7 +21,7 @@ func (sm *Manager) startBGP() error { // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client - if sm.config.EnablePacket { + if sm.config.EnableMetal { packetClient, err = packngo.NewClient() if err != nil { log.Error(err) From 38d01b676bec48a349f4572c9a31af57ddbcf9b7 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 22 Jan 2021 12:21:12 +0000 Subject: [PATCH 072/542] Move annotation lookup inside BGP startup --- pkg/manager/manager.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 6bd13c60..b8eb2018 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -145,14 +145,15 @@ func (sm *Manager) Start() error { // Add Notification for SIGKILL (sent from Kubernetes) signal.Notify(sm.signalChan, syscall.SIGKILL) - // If Annotations have been set then we will look them up - err := sm.parseAnnotations() - if err != nil { - return err - } - // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { + + // If Annotations have been set then we will look them up + err := sm.parseAnnotations() + if err != nil { + return err + } + log.Infoln("Starting Kube-vip Manager with the BGP engine") log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane && sm.config.EnableServices) return sm.startBGP() From 9870cc1e699c2e617c14e8311b1e8ae1a2851131 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 22 Jan 2021 12:53:31 +0000 Subject: [PATCH 073/542] Cleaner details for deploying kube-vip on EM --- docs/hybrid/daemonset/index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 86e17dad..3fce052b 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -136,7 +136,11 @@ spec: ## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) -The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations packet.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. +The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. + +**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. + +This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations packet.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. ``` kube-vip manifest daemonset \ From 0d5341aab918d162a118ef28bde65ec40503a428 Mon Sep 17 00:00:00 2001 From: David McKay Date: Tue, 26 Jan 2021 17:29:03 +0000 Subject: [PATCH 074/542] fix: handle multiple peer-ips from ccm --- pkg/manager/watcher.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 2be34942..608fcd27 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "strconv" + "strings" log "github.com/sirupsen/logrus" @@ -168,15 +169,20 @@ func (sm *Manager) annotationsWatcher() error { } else { continue } - peerIP := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] - if peerIP != "" { - sm.config.BGPPeerConfig.Address = peerIP - } else { - continue + + peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] + + peerIPs := strings.Split(peerIPString, ",") + + for _, peerIP := range peerIPs { + ipAddr := strings.TrimSpace(peerIP) + + if ipAddr != "" { + sm.config.BGPPeerConfig.Address = ipAddr + sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + } } - // Add the peer configuration to the overall BGP configuration - log.Infoln("Annotations have been succesfully parsed") - sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + log.Debugf("%s / %d / %s / %d \n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) rw.Stop() From e2f8628211c2cb92a17907303b74241e623da6ca Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 27 Jan 2021 10:22:20 +0000 Subject: [PATCH 075/542] Update index.md --- docs/hybrid/daemonset/index.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 3fce052b..49016d5d 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -140,14 +140,14 @@ The below example is for running `type:LoadBalancer` services on worker nodes on **NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. -This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations packet.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. +This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. ``` kube-vip manifest daemonset \ --interface $INTERFACE \ --services \ --bgp \ - --annotations packet.com \ + --annotations metal.equinix.com \ --inCluster | k apply -f - ``` @@ -160,10 +160,18 @@ kubectl describe node k8s.bgp02 ... Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock node.alpha.kubernetes.io/ttl: 0 - packet.com/node-asn: 65000 - packet.com/peer-asn: 65530 - packet.com/peer-ip: x.x.x.x - packet.com/src-ip: x.x.x.x + metal.equinix.com/node-asn: 65000 + metal.equinix.com/peer-asn: 65530 + metal.equinix.com/peer-ip: x.x.x.x + metal.equinix.com/src-ip: x.x.x.x +``` + +If there are errors regarding `169.254.255.1` or `169.254.255.2` in the `kube-vip` logs then the routes to the ToR switches that provide BGP peering may by missing from the nodes. They can be replaced with the below command: + +``` +GATEWAY_IP=$(curl https://metadata.platformequinix.com/metadata | jq -r ".network.addresses[] | select(.public == false) | .gateway") +ip route add 169.254.255.1 via $GATEWAY_IP +ip route add 169.254.255.2 via $GATEWAY_IP ``` Additionally examining the logs of the Packet CCM may reveal why the node is not yet ready. From 45c704f5c895fd014454c2006d0f3ce7bb75099f Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Mon, 1 Feb 2021 12:47:12 +0100 Subject: [PATCH 076/542] Initialise Prometheus http endpoint This commit bootstrap the Prometheus endpoint. By default an HTTP server starts using port 2112. --- cmd/kube-vip.go | 53 +++++++++++++++++++++++++++++++++++++ go.mod | 4 +-- go.sum | 11 ++++++++ pkg/kubevip/config_types.go | 3 +++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index c9b7f815..788bde5f 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -1,12 +1,16 @@ package cmd import ( + "context" "fmt" + "net/http" "os" + "time" "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/manager" "github.com/plunder-app/kube-vip/pkg/packet" + "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -116,6 +120,9 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") + // Prometheus HTTP Server + kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "promethuesHTTPServer", ":2112", "Host and port used to expose Promethues metrics via an HTTP server") + kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) kubeVipCmd.AddCommand(kubeVipManager) @@ -196,6 +203,10 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) + go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ + Addr: initConfig.PrometheusHTTPServer, + }) + // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) if err != nil { @@ -233,3 +244,45 @@ var kubeVipManager = &cobra.Command{ } }, } + +type PrometheusHTTPServerConfig struct { + // Addr sets the http server address used to expose the metric endpoint + Addr string +} + +func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerConfig) { + var err error + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.Handler()) + + srv := &http.Server{ + Addr: config.Addr, + Handler: mux, + } + + go func() { + if err = srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Fatalf("listen:%+s\n", err) + } + }() + + log.Printf("server started") + + <-ctx.Done() + + log.Printf("server stopped") + + ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer func() { + cancel() + }() + + if err = srv.Shutdown(ctxShutDown); err != nil { + log.Fatalf("server Shutdown Failed:%+s", err) + } + + if err == http.ErrServerClosed { + err = nil + } + +} diff --git a/go.mod b/go.mod index e9b3ee51..e69d1b54 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/packethost/packngo v0.5.1 github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.4.0 github.com/sirupsen/logrus v1.6.0 github.com/spf13/afero v1.4.0 // indirect github.com/spf13/cast v1.3.1 // indirect @@ -45,7 +46,7 @@ require ( golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect golang.org/x/net v0.0.0-20201021035429-f5854403a974 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect - golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f + golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0 // indirect google.golang.org/grpc v1.32.0 // indirect @@ -59,4 +60,3 @@ require ( ) replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 - diff --git a/go.sum b/go.sum index bdf82c67..1ce57d97 100644 --- a/go.sum +++ b/go.sum @@ -67,12 +67,15 @@ github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -342,6 +345,7 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b h1:8Oryv4wHvBHAxi9Swzu1zyN4BFrJKvv5pOnN0scSTw8= github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= @@ -404,20 +408,24 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -540,6 +548,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -652,6 +661,8 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 92e26d48..59e6f32d 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -88,6 +88,9 @@ type Config struct { // LoadBalancers are the various services we can load balance over LoadBalancers []LoadBalancer `yaml:"loadBalancers,omitempty"` + + // The hostport used to expose Prometheus metrics over an HTTP server + PrometheusHTTPServer string `yaml:"prometheusHTTPServer,omitempty"` } // LeaderElection defines all of the settings for Kubernetes LeaderElection From a26af37c5d1f75037dc58d47b39c437f15e18414 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 3 Feb 2021 11:40:30 +0000 Subject: [PATCH 077/542] Fixes packet -> metal --- pkg/kubevip/config_generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 87eab70a..234c1438 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -770,7 +770,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: "cloud-sa-volume", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: "packet-cloud-config", + SecretName: "metal-cloud-config", }, }, } From 3491fe8e9345685a81a1244f777c0de53d8e820a Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 3 Feb 2021 13:22:20 +0000 Subject: [PATCH 078/542] Update index.md --- docs/hybrid/services/index.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index 4c77a63a..ae4e1ba1 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -179,4 +179,36 @@ Either through the CLI or through the UI, create a public IPv4 EIP address.. and +-------+---------------+--------+----------------------+ kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` \ No newline at end of file +``` + +## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) + +Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. + +**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. + +### Using Annotations + +This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --services \ + --bgp \ + --annotations metal.equinix.com \ + --inCluster | k apply -f - +``` + +### Using the CCM secret to + +Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. + +``` +kube-vip manifest daemonset --interface $INTERFACE \ +--services \ +--inCluster \ +--bgp \ +--metal \ +--provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - +``` From b5f5bb47df679ffeb1d82b8f7ba66258e421f4f5 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 3 Feb 2021 13:34:06 +0000 Subject: [PATCH 079/542] Update index.md --- docs/hybrid/services/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index ae4e1ba1..09045b46 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -200,7 +200,7 @@ kube-vip manifest daemonset \ --inCluster | k apply -f - ``` -### Using the CCM secret to +### Using the existing CCM secret Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. From d799eb06e4d215c6de34dce5f47829db5f242d2c Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 3 Feb 2021 17:20:06 +0100 Subject: [PATCH 080/542] Add counter for service events This commit adds a Prometheus counter that counts the number of events fired by the watcher grouped by event type --- Makefile | 2 +- cmd/kube-vip.go | 3 +++ pkg/manager/manager.go | 15 +++++++++++++++ pkg/manager/prom.go | 7 +++++++ pkg/manager/watcher.go | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 pkg/manager/prom.go diff --git a/Makefile b/Makefile index 85cc35cf..b4647999 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.3.1 +VERSION := 0.3.2 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 788bde5f..e3533c7e 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -10,6 +10,7 @@ import ( "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/manager" "github.com/plunder-app/kube-vip/pkg/packet" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -237,6 +238,8 @@ var kubeVipManager = &cobra.Command{ log.Fatalf("%v", err) } + prometheus.MustRegister(mgr.PromethesCollector()...) + // Start the service manager, this will watch the config Map and construct kube-vip services for it err = mgr.Start() if err != nil { diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index b8eb2018..b275ed54 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -14,7 +14,9 @@ import ( "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -42,6 +44,8 @@ type Manager struct { // This channel is used to signal a shutdown signalChan chan os.Signal + + countEndpointWatchEvent *prometheus.CounterVec } type dhcpService struct { @@ -126,6 +130,17 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { clientSet: clientset, configMap: configMap, config: config, + countEndpointWatchEvent: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "kube-vip", + Subsystem: "manager", + Name: "all_services_events", + Help: "Count all events fired by the service watcher categorised by event type", + }, []string{ + string(watch.Added), + string(watch.Modified), + string(watch.Deleted), + string(watch.Modified), + string(watch.Error)}), }, nil } diff --git a/pkg/manager/prom.go b/pkg/manager/prom.go new file mode 100644 index 00000000..942d3eaf --- /dev/null +++ b/pkg/manager/prom.go @@ -0,0 +1,7 @@ +package manager + +import "github.com/prometheus/client_golang/prometheus" + +func (sm *Manager) PromethesCollector() []prometheus.Collector { + return []prometheus.Collector{sm.countEndpointWatchEvent} +} diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 608fcd27..ce5251b2 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -43,6 +43,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { + sm.countEndpointWatchEvent.WithLabelValues(string(event.Type)).Add(1) // We need to inspect the event and get ResourceVersion out of it switch event.Type { From 72fcf743b1ca183c82b15dfbb2ddff76757864ad Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 3 Feb 2021 17:55:00 +0100 Subject: [PATCH 081/542] Fix the namespace for prometheus metrics --- pkg/manager/manager.go | 10 ++++++---- pkg/manager/prom.go | 2 +- pkg/manager/watcher.go | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index b275ed54..e02675a6 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -45,7 +45,9 @@ type Manager struct { // This channel is used to signal a shutdown signalChan chan os.Signal - countEndpointWatchEvent *prometheus.CounterVec + // This is a promethues counter used to count the number of events received + // from the service watcher + countServiceWatchEvent *prometheus.CounterVec } type dhcpService struct { @@ -130,8 +132,8 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { clientSet: clientset, configMap: configMap, config: config, - countEndpointWatchEvent: prometheus.NewCounterVec(prometheus.CounterOpts{ - Namespace: "kube-vip", + countServiceWatchEvent: prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: "kube_vip", Subsystem: "manager", Name: "all_services_events", Help: "Count all events fired by the service watcher categorised by event type", @@ -139,7 +141,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { string(watch.Added), string(watch.Modified), string(watch.Deleted), - string(watch.Modified), + string(watch.Bookmark), string(watch.Error)}), }, nil } diff --git a/pkg/manager/prom.go b/pkg/manager/prom.go index 942d3eaf..b22de320 100644 --- a/pkg/manager/prom.go +++ b/pkg/manager/prom.go @@ -3,5 +3,5 @@ package manager import "github.com/prometheus/client_golang/prometheus" func (sm *Manager) PromethesCollector() []prometheus.Collector { - return []prometheus.Collector{sm.countEndpointWatchEvent} + return []prometheus.Collector{sm.countServiceWatchEvent} } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index ce5251b2..43f9b69d 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -43,7 +43,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { - sm.countEndpointWatchEvent.WithLabelValues(string(event.Type)).Add(1) + sm.countServiceWatchEvent.WithLabelValues(string(event.Type)).Add(1) // We need to inspect the event and get ResourceVersion out of it switch event.Type { From 5061c552987ecfb1fda687c3d007ab62fd7763cc Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 3 Feb 2021 18:53:17 +0100 Subject: [PATCH 082/542] Fix label grouping with Prometheus --- pkg/manager/manager.go | 8 +------- pkg/manager/watcher.go | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index e02675a6..89ba964b 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -16,7 +16,6 @@ import ( "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -137,12 +136,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { Subsystem: "manager", Name: "all_services_events", Help: "Count all events fired by the service watcher categorised by event type", - }, []string{ - string(watch.Added), - string(watch.Modified), - string(watch.Deleted), - string(watch.Bookmark), - string(watch.Error)}), + }, []string{"type"}), }, nil } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 43f9b69d..cbea9231 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "github.com/davecgh/go-spew/spew" @@ -43,7 +44,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { - sm.countServiceWatchEvent.WithLabelValues(string(event.Type)).Add(1) + sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) // We need to inspect the event and get ResourceVersion out of it switch event.Type { From 72d961969fbd3cf537ece2d7196a185ab56ab3f9 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 4 Feb 2021 09:19:24 +0000 Subject: [PATCH 083/542] Update index.md --- docs/hybrid/static/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 47df8a26..b95b80d5 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -56,6 +56,8 @@ kube-vip manifest pod \ --controlplane \ --services \ --bgp \ + --localAS 65000 \ + --bgpRouterID 192.168.0.2 \ --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml ``` From ea5e24b31fbb8b0f8cbd4e8861203516c1586c14 Mon Sep 17 00:00:00 2001 From: Marques Johansson Date: Thu, 4 Feb 2021 11:26:32 -0500 Subject: [PATCH 084/542] fix "services" typo in hybrid docs --- docs/hybrid/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hybrid/index.md b/docs/hybrid/index.md index fe82c3e1..c1823e94 100644 --- a/docs/hybrid/index.md +++ b/docs/hybrid/index.md @@ -62,7 +62,7 @@ When using `kube-vip` as a daemonset the details are available [here](./daemonse |--------------|------|-------|-------| |**Mode** |||| | |`--controlPlane`|Enables `kube-vip` control-plane functionality|| -| |`--servcies`|Enables `kube-vip` to watch services of type:LoadBalancer|| +| |`--services`|Enables `kube-vip` to watch services of type:LoadBalancer|| |**Vip Config** |||| | |`--arp`|Enables ARP brodcasts from Leader|| | |`--bgp`|Enables BGP peering from `kube-vip`|| @@ -138,4 +138,4 @@ The following new flags are used: - `--metalKey` which is our API key - `--metalProject`which is the name of our Equinix Metal project where our servers and EIP are located. -*Also* the `--arp` flag should NOT be used as it wont work within the Equinix Metal network. \ No newline at end of file +*Also* the `--arp` flag should NOT be used as it wont work within the Equinix Metal network. From 42d49d30873c28bce9faf2cc6f5b31608c996c5a Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 15 Feb 2021 14:55:15 +0000 Subject: [PATCH 085/542] Update kube-vip-bgp-em-ds.yaml --- docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml b/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml index 4f14f962..574693f5 100644 --- a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml +++ b/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml @@ -27,7 +27,7 @@ spec: - name: vip_cidr value: "32" - name: cp_enable - value: "true" + value: "false" - name: cp_namespace value: kube-system - name: svc_enable From a3444b60dd7e52f90dfbec285aadbcbf62d5ca68 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 15 Feb 2021 14:55:29 +0000 Subject: [PATCH 086/542] Update kube-vip-bgp-em-ds.yaml --- docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml b/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml index 574693f5..a19807f1 100644 --- a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml +++ b/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml @@ -21,7 +21,7 @@ spec: - name: vip_arp value: "false" - name: vip_interface - value: eth0 + value: lo - name: port value: "6443" - name: vip_cidr From 51122839a64ce1729f759c962e222b22d2c299a5 Mon Sep 17 00:00:00 2001 From: Yassine TIJANI Date: Thu, 18 Feb 2021 16:46:51 +0100 Subject: [PATCH 087/542] exit when the leaderelection is lost Signed-off-by: Yassine TIJANI --- pkg/cluster/clusterLeader.go | 8 ++------ pkg/manager/manager_arp.go | 5 ++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index eb2b4a25..863acd51 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -323,6 +323,8 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if err != nil { log.Warnf("%v", err) } + + log.Fatal("lost leadership, restarting kube-vip") }, OnNewLeader: func(identity string) { // we're notified when new leader elected @@ -335,12 +337,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe }, }) - //<-signalChan - log.Infof("Shutting down Kube-Vip Leader Election cluster") - - // Force a removal of the VIP (ignore the error if we don't have it) - cluster.Network.DeleteIP() - return nil } diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 90871395..18a4004d 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -133,6 +133,8 @@ func (sm *Manager) startARP() error { for x := range sm.serviceInstances { sm.serviceInstances[x].cluster.Stop() } + + log.Fatal("lost leadership, restarting kube-vip") }, OnNewLeader: func(identity string) { // we're notified when new leader elected @@ -145,8 +147,5 @@ func (sm *Manager) startARP() error { }, }) - //<-signalChan - log.Infof("Shutting down Kube-Vip") - return nil } From 3744f05adcb6335f45732305851cebde7fe97542 Mon Sep 17 00:00:00 2001 From: Gianluca Arbezzano Date: Wed, 3 Mar 2021 12:08:19 +0100 Subject: [PATCH 088/542] Catch return value for StartLeaderCluster Error handling for the function StartLeaderCluster is not properly done. Signed-off-by: Gianluca Arbezzano --- pkg/manager/manager_arp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 18a4004d..1feaeabb 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -48,7 +48,7 @@ func (sm *Manager) startARP() error { } go func() { - cpCluster.StartLeaderCluster(sm.config, clusterManager, nil) + err := cpCluster.StartLeaderCluster(sm.config, clusterManager, nil) if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance From 6d1c60dae10742bd0235ba86ad51bddf2653ded1 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 8 Mar 2021 15:12:50 +0000 Subject: [PATCH 089/542] Fixes to arp/controller and manifests --- Makefile | 2 +- docs/manifests/controller.yaml | 5 +-- docs/manifests/rbac.yaml | 3 ++ pkg/kubevip/config_generator.go | 5 +-- testing/create.sh | 41 ---------------------- testing/k3s/create.sh | 43 +++++++++++++++++++++++ testing/k3s/teardown.sh | 13 +++++++ testing/kubeadm/create.sh | 61 +++++++++++++++++++++++++++++++++ testing/kubeadm/teardown.sh | 13 +++++++ testing/nodes | 6 ++++ testing/teardown.sh | 10 ------ testing/testing.sh | 6 ++++ 12 files changed, 152 insertions(+), 56 deletions(-) delete mode 100644 testing/create.sh create mode 100755 testing/k3s/create.sh create mode 100755 testing/k3s/teardown.sh create mode 100755 testing/kubeadm/create.sh create mode 100755 testing/kubeadm/teardown.sh create mode 100644 testing/nodes delete mode 100644 testing/teardown.sh diff --git a/Makefile b/Makefile index b4647999..b6e2b5f2 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.3.2 +VERSION := 0.3.3 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/docs/manifests/controller.yaml b/docs/manifests/controller.yaml index eb12755a..ba081c12 100644 --- a/docs/manifests/controller.yaml +++ b/docs/manifests/controller.yaml @@ -16,7 +16,7 @@ rules: verbs: ["*"] - apiGroups: [""] resources: ["nodes", "services"] - verbs: ["list","get","watch"] + verbs: ["list","get","watch","update"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 @@ -54,7 +54,8 @@ spec: containers: - command: - /plndr-cloud-provider - image: plndr/plndr-cloud-provider:0.1.4 + - --leader-elect-resource-name=plndr-cloud-controller + image: plndr/plndr-cloud-provider:0.1.5 name: plndr-cloud-provider imagePullPolicy: Always resources: {} diff --git a/docs/manifests/rbac.yaml b/docs/manifests/rbac.yaml index 446929bb..f35d79aa 100644 --- a/docs/manifests/rbac.yaml +++ b/docs/manifests/rbac.yaml @@ -14,6 +14,9 @@ rules: - apiGroups: [""] resources: ["services", "services/status", "nodes"] verbs: ["list","get","watch", "update"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["list", "get", "watch", "update", "create"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 234c1438..7643b0d6 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -821,8 +821,9 @@ func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inClust if taint { newManifest.Spec.Template.Spec.Tolerations = []corev1.Toleration{ { - Key: "node-role.kubernetes.io/master", - Effect: corev1.TaintEffectNoSchedule, + Key: "node-role.kubernetes.io/master", + Effect: corev1.TaintEffectNoSchedule, + Operator: corev1.TolerationOpExists, }, } newManifest.Spec.Template.Spec.NodeSelector = map[string]string{ diff --git a/testing/create.sh b/testing/create.sh deleted file mode 100644 index d1c73dba..00000000 --- a/testing/create.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -if [[ -z $1 && -z $2 && -z $3 ]]; then - echo "Usage:" - echo " Param 1: Kubernetes Version" - echo " Param 2: Kube-Vip Version" - echo " Param 3: Vip address" - echo "" - echo "" ./create_k8s.sh 1.18.5 0.1.8 192.168.0.41 - exit 1 -fi - -echo "Creating First node!" -ssh k8s01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --controlplane --interface ens160 --vip $3 --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml" -CONTROLPLANE_CMD=$(ssh k8s01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $3 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") -ssh k8s01 "sudo rm -rf ~/.kube/" -ssh k8s01 "mkdir -p .kube" -ssh k8s01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" -ssh k8s01 "sudo chown dan:dan .kube/config" -echo "Enabling strict ARP on kube-proxy" -ssh k8s01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" -ssh k8s01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" -ssh k8s01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" -JOIN_CMD=$(ssh k8s01 " sudo kubeadm token create --print-join-command 2> /dev/null") - -ssh k8s02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" -sleep 3 -ssh k8s02 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $3 --arp --leaderElection --controlplane | sudo tee /etc/kubernetes/manifests/vip.yaml" - -ssh k8s03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" -sleep 3 -ssh k8s03 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $3 --arp --leaderElection --controlplane | sudo tee /etc/kubernetes/manifests/vip.yaml" -ssh k8s04 "sudo $JOIN_CMD" -ssh k8s05 "sudo $JOIN_CMD" -echo -echo " Nodes should be deployed at this point, waiting 5 secs and querying the deployment" -sleep 5 -ssh k8s01 "kubectl get nodes" -ssh k8s01 "kubectl get pods -A" -echo -echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $3" \ No newline at end of file diff --git a/testing/k3s/create.sh b/testing/k3s/create.sh new file mode 100755 index 00000000..dcdac2f7 --- /dev/null +++ b/testing/k3s/create.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then + echo "Usage:" + echo " Param 1: Kube-Vip Version" + echo " Param 2: Kube-Vip mode [\"controlplane\"/\"services\"/\"hybrid\"]" + echo " Param 3: Vip address" + echo " Param 4: k3s url (https://github.com/k3s-io/k3s/releases/download/v1.20.4%2Bk3s1/k3s)" + echo "" ./create.sh 0.3.3 hybrid 192.168.0.40 + exit 1 +fi + +case "$2" in + +"controlplane") echo "Creating control plane only cluster" + mode="--controlplane" + ;; +"services") echo "Creating services only cluster" + mode="--services" + ;; +"hybrid") echo "Creating hybrid cluster" + mode="--controlplane --services" + ;; +*) echo "Unknown kube-vip mode [$2]" + exit -1 + ;; +esac + +source ./testing/nodes + +echo "Creating First node!" + +ssh $NODE01 "sudo mkdir -p /var/lib/rancher/k3s/server/manifests/" +ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest daemonset $mode --interface ens160 --vip $3 --arp --leaderElection --inCluster --taint | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml" +ssh $NODE01 "sudo curl https://kube-vip.io/manifests/rbac.yaml | sudo tee /var/lib/rancher/k3s/server/manifests/rbac.yaml" +ssh $NODE01 "sudo screen -dmSL k3s k3s server --cluster-init --tls-san $3 --no-deploy servicelb --disable-cloud-controller --token=test" +echo "Started first node, sleeping for 60 seconds" +sleep 60 +echo "Adding additional nodes" +ssh $NODE02 "sudo screen -dmSL k3s k3s server --server https://$3:6443 --token=test" +ssh $NODE03 "sudo screen -dmSL k3s k3s server --server https://$3:6443 --token=test" +sleep 20 +ssh $NODE01 "sudo k3s kubectl get node -o wide" diff --git a/testing/k3s/teardown.sh b/testing/k3s/teardown.sh new file mode 100755 index 00000000..070260b5 --- /dev/null +++ b/testing/k3s/teardown.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source ./testing/nodes + +echo "Wiping Nodes in reverse order, and rebooting" +ssh $NODE05 "sudo pkill k3s; sudo rm -rf /var/lib/rancher /etc/rancher; sudo reboot" +ssh $NODE04 "sudo pkill k3s; sudo rm -rf /var/lib/rancher /etc/rancher; sudo reboot" +ssh $NODE03 "sudo pkill k3s; sudo rm -rf /var/lib/rancher /etc/rancher; sudo reboot" +ssh $NODE02 "sudo pkill k3s; sudo rm -rf /var/lib/rancher /etc/rancher; sudo reboot" +ssh $NODE01 "sudo pkill k3s; sudo rm -rf /var/lib/rancher /etc/rancher; sudo reboot" +echo +echo "All Control Plane Nodes have been reset" +echo "Consider removing kube-vip images if changing version" \ No newline at end of file diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh new file mode 100755 index 00000000..99d6d2fe --- /dev/null +++ b/testing/kubeadm/create.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then + echo "Usage:" + echo " Param 1: Kubernetes Version" + echo " Param 2: Kube-Vip Version" + echo " Param 3: Kube-Vip mode [\"controlplane\"/\"services\"/\"hybrid\"]" + echo " Param 4: Vip address" + echo "" + echo "" ./create_k8s.sh 1.18.5 0.3.3 192.168.0.40 + exit 1 +fi + +case "$3" in + +"controlplane") echo "Sending SIGHUP signal" + mode="--controlplane" + ;; +"services") echo "Sending SIGINT signal" + mode="--services" + ;; +"hybrid") echo "Sending SIGQUIT signal" + mode="--controlplane --services" + ;; +*) echo "Unknown kube-vip mode [$3]" + exit -1 + ;; +esac + +source ./testing/nodes + +echo "Creating First node!" + +ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod $mode --interface ens160 --vip $4 --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml" +CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $4 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") +ssh $NODE01 "sudo rm -rf ~/.kube/" +ssh $NODE01 "mkdir -p .kube" +ssh $NODE01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" +ssh $NODE01 "sudo chown dan:dan .kube/config" +echo "Enabling strict ARP on kube-proxy" +ssh $NODE01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" +ssh $NODE01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" +ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" +JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") + +ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" +sleep 3 +ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection $mode | sudo tee /etc/kubernetes/manifests/vip.yaml" + +ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" +sleep 3 +ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection $mode | sudo tee /etc/kubernetes/manifests/vip.yaml" +ssh $NODE04 "sudo $JOIN_CMD" +ssh $NODE05 "sudo $JOIN_CMD" +echo +echo " Nodes should be deployed at this point, waiting 5 secs and querying the deployment" +sleep 5 +ssh $NODE01 "kubectl get nodes" +ssh $NODE01 "kubectl get pods -A" +echo +echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $4" \ No newline at end of file diff --git a/testing/kubeadm/teardown.sh b/testing/kubeadm/teardown.sh new file mode 100755 index 00000000..4532b5df --- /dev/null +++ b/testing/kubeadm/teardown.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source ./testing/nodes + +echo "Wiping Nodes in reverse order, and rebooting" +ssh $NODE05 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh $NODE04 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh $NODE03 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh $NODE02 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" +ssh $NODE01 "sudo kubeadm reset -f --skip-phases preflight update-cluster-status remove-etcd-member; sudo rm -rf /etc/cni/net.d; sudo reboot" +echo +echo "All Control Plane Nodes have been reset" +echo "Consider removing kube-vip images if changing version" \ No newline at end of file diff --git a/testing/nodes b/testing/nodes new file mode 100644 index 00000000..f624c23c --- /dev/null +++ b/testing/nodes @@ -0,0 +1,6 @@ +# Home lab (for testing) +NODE01=k8s01.fnnrn.me +NODE02=k8s02.fnnrn.me +NODE03=k8s03.fnnrn.me +NODE04=k8s04.fnnrn.me +NODE05=k8s05.fnnrn.me \ No newline at end of file diff --git a/testing/teardown.sh b/testing/teardown.sh deleted file mode 100644 index 515562a3..00000000 --- a/testing/teardown.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -echo "Wiping Nodes in reverse order, and rebooting" -ssh k8s05 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" -ssh k8s04 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" -ssh k8s03 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" -ssh k8s02 "sudo kubeadm reset -f; sudo rm -rf /etc/cni/net.d; sudo reboot" -ssh k8s01 "sudo kubeadm reset -f --skip-phases preflight update-cluster-status remove-etcd-member; sudo rm -rf /etc/cni/net.d; sudo reboot" -echo -echo "All Control Plane Nodes have been reset" -echo "Consider removing kube-vip images if changing version" \ No newline at end of file diff --git a/testing/testing.sh b/testing/testing.sh index b94f69c6..95885670 100755 --- a/testing/testing.sh +++ b/testing/testing.sh @@ -31,6 +31,12 @@ docker run --network host --rm plndr/kube-vip:action manifest pod --interface et echo "==> ARP w/controlplane (using --address)" docker run --network host --rm plndr/kube-vip:action manifest pod --interface enx001e063262b1 --address k8s-api-vip.lan --arp --leaderElection --controlplane +echo "==> ARP w/controlplane (using --address)" +docker run --network host --rm plndr/kube-vip:action manifest daemonset --interface eth0 --vip 192.168.0.1 --controlplane \ + --services \ + --inCluster \ + --taint + trap : 0 echo >&2 ' From dbfc39cee3e70790fb60ab7a9e51090bb68474ec Mon Sep 17 00:00:00 2001 From: Edwin Xie Date: Fri, 19 Feb 2021 19:14:13 +0000 Subject: [PATCH 090/542] Support IPv6 - Implement gratuitous NDP neighbor advertisements - Add e2e tests for IPv6 neighbor advertisements and IPv4 ARP broadcasts - Adds a README.md for e2e tests - Adds go.mod dependencies - Kind to run clusters - Ginkgo testing framework - Gomega assertion library - ndp library to help with NDP Co-authored-by: Aidan Obley Co-authored-by: Gabriel Rosenhouse --- Makefile | 5 +- cmd/kube-vip-kubeadm.go | 2 +- go.mod | 7 +- go.sum | 77 ++----- pkg/cluster/clusterLeader.go | 30 ++- pkg/detector/interfaces.go | 2 +- pkg/vip/address.go | 14 +- pkg/vip/ndp.go | 66 ++++++ pkg/vip/util.go | 33 ++- testing/e2e/README.md | 26 +++ testing/e2e/e2e_suite_test.go | 61 ++++++ testing/e2e/e2e_test.go | 377 +++++++++++++++++++++++++++++++++ testing/e2e/kube-vip.yaml.tmpl | 41 ++++ 13 files changed, 664 insertions(+), 77 deletions(-) create mode 100644 pkg/vip/ndp.go create mode 100644 testing/e2e/README.md create mode 100644 testing/e2e/e2e_suite_test.go create mode 100644 testing/e2e/e2e_test.go create mode 100644 testing/e2e/kube-vip.yaml.tmpl diff --git a/Makefile b/Makefile index b6e2b5f2..828cf328 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ LDFLAGS=-ldflags "-s -w -X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -extld DOCKERTAG ?= $(VERSION) REPOSITORY = plndr -.PHONY: all build clean install uninstall fmt simplify check run +.PHONY: all build clean install uninstall fmt simplify check run e2e-tests all: check install @@ -97,4 +97,5 @@ manifests: @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster --provider-config /etc/cloud-sa/cloud-sa.json > ./docs/manifests/$(VERSION)/kube-vip-bgp-em-ds.yaml @-rm ./kube-vip - +e2e-tests: + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -v -p testing/e2e diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index c31880be..842ca0b2 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -143,7 +143,7 @@ func autoGenLocalPeer() (*kubevip.RaftPeer, error) { for _, address := range addrs { // check the address type and if it is not a loopback the display it if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { - if ipnet.IP.To4() != nil { + if ipnet.IP.To16() != nil { a = ipnet.IP.String() break } diff --git a/go.mod b/go.mod index e69d1b54..4642d65b 100644 --- a/go.mod +++ b/go.mod @@ -28,11 +28,13 @@ require ( github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef github.com/magiconair/properties v1.8.3 // indirect github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/onsi/ginkgo v1.11.0 + github.com/onsi/gomega v1.7.0 github.com/osrg/gobgp v2.0.0+incompatible github.com/packethost/packngo v0.5.1 - github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.4.0 github.com/sirupsen/logrus v1.6.0 @@ -55,8 +57,9 @@ require ( k8s.io/apimachinery v0.19.2 k8s.io/client-go v0.19.0 k8s.io/klog v1.0.0 - k8s.io/klog/v2 v2.3.0 // indirect + k8s.io/klog/v2 v2.3.0 k8s.io/utils v0.0.0-20200912215256-4140de9c8800 // indirect + sigs.k8s.io/kind v0.10.0 ) replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 diff --git a/go.sum b/go.sum index 1ce57d97..a36df3f0 100644 --- a/go.sum +++ b/go.sum @@ -57,10 +57,11 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alessio/shellescape v1.2.2 h1:8LnL+ncxhWT2TR00dfJRT25JWWrhkMZXneHVWnetDZg= +github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= github.com/armon/go-metrics v0.3.4 h1:Xqf+7f2Vhl9tsqDYmXhnXInUdcrtgpRNpIA15/uldSc= github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= @@ -95,7 +96,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20171119141306-ac7624ea8da3/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= @@ -120,12 +120,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= +github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -140,7 +140,6 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE= github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= @@ -153,9 +152,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -171,7 +168,6 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71 github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= @@ -187,23 +183,18 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY= github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= @@ -217,13 +208,11 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1 h1:A8Yhf6EtqTv9RMsU6MQTyrtV1TjWlR6xU9BsZIwuTCM= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= @@ -241,37 +230,30 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.1 h1:9PZfAcVEvez4yhLH2TBU64/h/z4xlFI80cWXRrxuKuM= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.2.0 h1:l6UW37iCXwZkZoAbEYnptSHVE/cQ5bOTPYG5W3vf9+8= github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo= github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -294,6 +276,7 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -304,7 +287,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131 h1:2bjzgZk4GiWAFkj15/SkmxIO30u69RyPiSS+F0d+Kzs= github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= @@ -313,13 +295,11 @@ github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef/go.mod h1:0L/S1RSG4wA github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -327,27 +307,25 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.3 h1:kJSsc6EXkBLgr3SphHk9w5mtjn0bjlR4JYEXKrJ45rQ= github.com/magiconair/properties v1.8.3/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b h1:8Oryv4wHvBHAxi9Swzu1zyN4BFrJKvv5pOnN0scSTw8= +github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= +github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= @@ -360,7 +338,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -391,7 +368,6 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.0.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -436,7 +412,6 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -448,12 +423,10 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v0.0.0-20170217164146-9be650865eab/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8= github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -461,7 +434,6 @@ github.com/spf13/cobra v0.0.0-20170731170427-b26b538f6930/go.mod h1:1l0Ry5zgKvJa github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v0.0.0-20170523133247-0efa5202c046/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -471,7 +443,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -481,7 +452,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -494,7 +464,6 @@ github.com/vishvananda/netlink v0.0.0-20170802012344-a95659537721/go.mod h1:+SR5 github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20170707011535-86bef332bfc3/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= @@ -503,6 +472,8 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= +gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -514,16 +485,13 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a h1:y6sBfNd1b9Wy08a6K1Z1DZc4aXABUN5TKjkYhz7UKmo= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -548,7 +516,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -557,7 +524,6 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -591,16 +557,14 @@ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -636,7 +600,6 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -656,22 +619,20 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= @@ -723,7 +684,6 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -748,7 +708,6 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -757,7 +716,6 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -780,7 +738,6 @@ google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -791,13 +748,11 @@ google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0/go.mod h1:FWY/as6D google.golang.org/grpc v1.5.1/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= @@ -814,13 +769,11 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -829,7 +782,6 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10= gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -842,7 +794,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -868,7 +819,6 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.3.0 h1:WmkrnW7fdrm0/DMClc+HIxtftvxVIPAhlVwMQo5yLco= k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= @@ -880,9 +830,10 @@ k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/kind v0.10.0 h1:Tm+QITIqdRd+efLOsxZHMAfLnr5K4e3/RH8MePspEXs= +sigs.k8s.io/kind v0.10.0/go.mod h1:fb32zUw7ewC47bPwLnwhf47wd/vADtv3c38KP7sjIlo= sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 863acd51..ac9cd666 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -279,16 +279,38 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if c.EnableARP == true { ctxArp, cancelArp = context.WithCancel(context.Background()) + ipString := cluster.Network.IP() + + var ndp *vip.NdpResponder + if vip.IsIPv6(ipString) { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } + } + go func(ctx context.Context) { + if ndp != nil { + defer ndp.Close() + } + for { select { case <-ctx.Done(): // if cancel() execute return default: - // Gratuitous ARP, will broadcast to new MAC <-> IP - err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) + if vip.IsIPv4(ipString) { + // Gratuitous ARP, will broadcast to new MAC <-> IP + err := vip.ARPSendGratuitous(ipString, c.Interface) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } } } time.Sleep(3 * time.Second) diff --git a/pkg/detector/interfaces.go b/pkg/detector/interfaces.go index d04e112a..00b29d69 100644 --- a/pkg/detector/interfaces.go +++ b/pkg/detector/interfaces.go @@ -22,7 +22,7 @@ func FindIPAddress(addrName string) (string, string, error) { } for _, a := range addrs { if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { - if ipnet.IP.To4() != nil { + if ipnet.IP.To16() != nil { address = ipnet.IP.String() // If we're not searching for a specific adapter return the first one if addrName == "" { diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 78dcce1d..fb3dfe94 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -37,6 +37,14 @@ type network struct { isDDNS bool } +func netlinkParse(addr string) (*netlink.Addr, error) { + mask, err := GetFullMask(addr) + if err != nil { + return nil, err + } + return netlink.ParseAddr(addr + mask) +} + // NewConfig will attempt to provide an interface to the kernel network configuration func NewConfig(address string, iface string, isDDNS bool) (Network, error) { result := &network{} @@ -48,7 +56,7 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { result.link = link if IsIP(address) { - result.address, err = netlink.ParseAddr(address + "/32") + result.address, err = netlinkParse(address) if err != nil { return result, errors.Wrapf(err, "could not parse address '%s'", address) } @@ -75,7 +83,7 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { } // we're able to resolve store this as the initial IP - if result.address, err = netlink.ParseAddr(ip + "/32"); err != nil { + if result.address, err = netlinkParse(ip); err != nil { return result, err } // set ValidLft so that the VIP expires if the DNS entry is updated, otherwise it'll be refreshed by the DNS prober @@ -140,7 +148,7 @@ func (configurator *network) SetIP(ip string) error { configurator.mu.Lock() defer configurator.mu.Unlock() - addr, err := netlink.ParseAddr(ip + "/32") + addr, err := netlinkParse(ip) if err != nil { return err } diff --git a/pkg/vip/ndp.go b/pkg/vip/ndp.go new file mode 100644 index 00000000..f0b52b64 --- /dev/null +++ b/pkg/vip/ndp.go @@ -0,0 +1,66 @@ +package vip + +import ( + "fmt" + "net" + + "github.com/mdlayher/ndp" + + log "github.com/sirupsen/logrus" +) + +type NdpResponder struct { + intf string + hardwareAddr net.HardwareAddr + conn *ndp.Conn +} + +func NewNDPResponder(ifaceName string) (*NdpResponder, error) { + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + return nil, fmt.Errorf("failed to get interface %q: %v", ifaceName, err) + } + + // Use link-local address as the source IPv6 address for NDP communications. + conn, _, err := ndp.Dial(iface, ndp.LinkLocal) + if err != nil { + return nil, fmt.Errorf("creating NDP responder for %q: %s", iface.Name, err) + } + + ret := &NdpResponder{ + intf: iface.Name, + hardwareAddr: iface.HardwareAddr, + conn: conn, + } + return ret, nil +} + +func (n *NdpResponder) Close() error { + return n.conn.Close() +} + +func (n *NdpResponder) SendGratuitous(address string) error { + ip := net.ParseIP(address) + if ip == nil { + return fmt.Errorf("failed to parse address %s", ip) + } + + log.Infof("Broadcasting NDP update for %s (%s) via %s", address, n.hardwareAddr, n.intf) + return n.advertise(net.IPv6linklocalallnodes, ip, true) +} + +func (n *NdpResponder) advertise(dst, target net.IP, gratuitous bool) error { + m := &ndp.NeighborAdvertisement{ + Solicited: !gratuitous, + Override: gratuitous, // Should clients replace existing cache entries + TargetAddress: target, + Options: []ndp.Option{ + &ndp.LinkLayerAddress{ + Direction: ndp.Target, + Addr: n.hardwareAddr, + }, + }, + } + log.Infof("ndp: %v", m) + return n.conn.WriteTo(m, nil, dst) +} diff --git a/pkg/vip/util.go b/pkg/vip/util.go index fd8c010e..fa391afa 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -1,9 +1,11 @@ package vip import ( - "github.com/pkg/errors" + "fmt" "net" "strings" + + "github.com/pkg/errors" ) // LookupHost resolves dnsName and return an IP or an error @@ -33,3 +35,32 @@ func getHostName(dnsName string) string { fields := strings.Split(dnsName, ".") return fields[0] } + +// IsIPv4 returns true only if address is a valid IPv4 address +func IsIPv4(address string) bool { + ip := net.ParseIP(address) + if ip == nil { + return false + } + return ip.To4() != nil +} + +// IsIPv6 returns true only if address is a valid IPv6 address +func IsIPv6(address string) bool { + ip := net.ParseIP(address) + if ip == nil { + return false + } + return ip.To4() == nil +} + +// GetFullMask returns /32 for an IPv4 address and /128 for an IPv6 address +func GetFullMask(address string) (string, error) { + if IsIPv4(address) { + return "/32", nil + } + if IsIPv6(address) { + return "/128", nil + } + return "", fmt.Errorf("failed to parse %s as either IPv4 or IPv6", address) +} diff --git a/testing/e2e/README.md b/testing/e2e/README.md new file mode 100644 index 00000000..ac739652 --- /dev/null +++ b/testing/e2e/README.md @@ -0,0 +1,26 @@ +# Running End To End Tests +Prerequisites: +* Tests must be run on a Linux OS +* Docker installed with IPv6 enabled [how to enable IPv6](https://docs.docker.com/config/daemon/ipv6/) + * You will need to restart your Docker engine after updating the config +* Target kube-vip Docker image exists locally. Either build the image locally + with `make dockerx86Local` or `docker pull` the image from a registry. + +Run the tests from the repo root: +``` +make e2e-tests +``` + +Note: To preserve the test cluster after a test run, run the following: +``` +make E2E_PRESERVE_CLUSTER=true e2e-tests +``` + +The E2E tests: +* Start a local kind cluster +* Load the local docker image into kind +* Test connectivity to the control plane using the VIP +* Kills the current leader + * This causes leader election to occur +* Attempts to connect to the control plane using the VIP + * The new leader will need send ndp advertisements before this can succeed within a timeout diff --git a/testing/e2e/e2e_suite_test.go b/testing/e2e/e2e_suite_test.go new file mode 100644 index 00000000..0efc2189 --- /dev/null +++ b/testing/e2e/e2e_suite_test.go @@ -0,0 +1,61 @@ +package e2e_test + +import ( + "fmt" + "os/exec" + "testing" + "time" + + kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/kind/pkg/cluster" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "E2E Suite") +} + +var _ = SynchronizedBeforeSuite(func() []byte { + ensureKindNetwork() + return []byte{} +}, func(_ []byte) {}) + +func ensureKindNetwork() { + By("checking if the Docker \"kind\" network exists") + cmd := exec.Command("docker", "inspect", "kind") + session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session).Should(gexec.Exit()) + if session.ExitCode() == 0 { + return + } + + By("Docker \"kind\" network was not found. Creating dummy Kind cluster to ensure creation") + clusterConfig := kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv6Family, + }, + } + + provider := cluster.NewProvider( + cluster.ProviderWithDocker(), + ) + dummyClusterName := fmt.Sprintf("dummy-cluster-%d", time.Now().Unix()) + Expect(provider.Create( + dummyClusterName, + cluster.CreateWithV1Alpha4Config(&clusterConfig), + )).To(Succeed()) + + By("deleting dummy Kind cluster") + Expect(provider.Delete(dummyClusterName, "")) + + By("checking if the Docker \"kind\" network was successfully created") + cmd = exec.Command("docker", "inspect", "kind") + session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session).Should(gexec.Exit(0)) +} diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go new file mode 100644 index 00000000..e2dad316 --- /dev/null +++ b/testing/e2e/e2e_test.go @@ -0,0 +1,377 @@ +package e2e_test + +import ( + "bufio" + "bytes" + "crypto/tls" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "text/template" + "time" + + "k8s.io/klog/v2" + "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/kind/pkg/cluster" + "sigs.k8s.io/kind/pkg/cmd" + load "sigs.k8s.io/kind/pkg/cmd/kind/load/docker-image" + "sigs.k8s.io/kind/pkg/log" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" +) + +type kubevipManifestValues struct { + ControlPlaneVIP string + ImagePath string +} + +var _ = Describe("kube-vip broadcast neighbor", func() { + var ( + logger log.Logger + imagePath string + kubeVIPManifestTemplate *template.Template + clusterName string + tempDirPath string + ) + + BeforeEach(func() { + klog.SetOutput(GinkgoWriter) + logger = TestLogger{} + + imagePath = os.Getenv("E2E_IMAGE_PATH") + + curDir, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + templatePath := filepath.Join(curDir, "kube-vip.yaml.tmpl") + + kubeVIPManifestTemplate, err = template.New("kube-vip.yaml.tmpl").ParseFiles(templatePath) + Expect(err).NotTo(HaveOccurred()) + + tempDirPath, err = ioutil.TempDir("", "kube-vip-test") + Expect(err).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + if os.Getenv("E2E_PRESERVE_CLUSTER") == "true" { + return + } + + provider := cluster.NewProvider( + cluster.ProviderWithLogger(logger), + cluster.ProviderWithDocker(), + ) + + Expect(provider.Delete(clusterName, "")).To(Succeed()) + + Expect(os.RemoveAll(tempDirPath)).To(Succeed()) + }) + + Describe("kube-vip IPv4 functionality", func() { + var ( + clusterConfig kindconfigv1alpha4.Cluster + ipv4VIP string + ) + + BeforeEach(func() { + clusterName = fmt.Sprintf("%s-ipv4", filepath.Base(tempDirPath)) + + clusterConfig = kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv4Family, + }, + Nodes: []kindconfigv1alpha4.Node{}, + } + + manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4.yaml") + + for i := 0; i < 3; i++ { + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ + ExtraMounts: []kindconfigv1alpha4.Mount{ + { + HostPath: manifestPath, + ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + }, + }, + }) + } + + manifestFile, err := os.Create(manifestPath) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile.Close() + + ipv4VIP = generateIPv4VIP() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile, kubevipManifestValues{ + ControlPlaneVIP: ipv4VIP, + ImagePath: imagePath, + })).To(Succeed()) + }) + + It("provides an IPv4 VIP address for the Kubernetes control plane nodes", func() { + By(withTimestamp("creating a kind cluster with multiple control plane nodes")) + createKindCluster(logger, &clusterConfig, clusterName) + + By(withTimestamp("loading local docker image to kind cluster")) + loadDockerImageToKind(logger, imagePath, clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv4 VIP")) + // Allow enough time for control plane nodes to load the docker image and + // use the default timeout for establishing a connection to the VIP + assertControlPlaneIsRoutable(ipv4VIP, time.Duration(0), 10*time.Second) + + By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) + killLeader(ipv4VIP, clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv4 VIP with little downtime")) + // Allow at most 20 seconds of downtime when polling the control plane nodes + assertControlPlaneIsRoutable(ipv4VIP, 1*time.Second, 20*time.Second) + }) + }) + + Describe("kube-vip IPv6 functionality", func() { + var ( + clusterConfig kindconfigv1alpha4.Cluster + ipv6VIP string + ) + + BeforeEach(func() { + clusterName = fmt.Sprintf("%s-ipv6", filepath.Base(tempDirPath)) + + clusterConfig = kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv6Family, + }, + Nodes: []kindconfigv1alpha4.Node{}, + } + + manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv6.yaml") + + for i := 0; i < 3; i++ { + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ + ExtraMounts: []kindconfigv1alpha4.Mount{ + { + HostPath: manifestPath, + ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + }, + }, + }) + } + + ipv6VIP = generateIPv6VIP() + + manifestFile, err := os.Create(manifestPath) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile.Close() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile, kubevipManifestValues{ + ControlPlaneVIP: ipv6VIP, + ImagePath: imagePath, + })).To(Succeed()) + }) + + It("provides an IPv6 VIP address for the Kubernetes control plane nodes", func() { + By(withTimestamp("creating a kind cluster with multiple control plane nodes")) + createKindCluster(logger, &clusterConfig, clusterName) + + By(withTimestamp("loading local docker image to kind cluster")) + loadDockerImageToKind(logger, imagePath, clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) + // Allow enough time for control plane nodes to load the docker image and + // use the default timeout for establishing a connection to the VIP + assertControlPlaneIsRoutable(ipv6VIP, time.Duration(0), 10*time.Second) + + By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) + killLeader(ipv6VIP, clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv6 VIP with little downtime")) + // Allow at most 20 seconds of downtime when polling the control plane nodes + assertControlPlaneIsRoutable(ipv6VIP, 1*time.Second, 20*time.Second) + }) + }) +}) + +func createKindCluster(logger log.Logger, config *v1alpha4.Cluster, clusterName string) { + provider := cluster.NewProvider( + cluster.ProviderWithLogger(logger), + cluster.ProviderWithDocker(), + ) + + Expect(provider.Create( + clusterName, + cluster.CreateWithV1Alpha4Config(config), + )).To(Succeed()) +} + +func loadDockerImageToKind(logger log.Logger, imagePath string, clusterName string) { + loadImageCmd := load.NewCommand(logger, cmd.StandardIOStreams()) + loadImageCmd.SetArgs([]string{"--name", clusterName, imagePath}) + Expect(loadImageCmd.Execute()).To(Succeed()) +} + +func assertControlPlaneIsRoutable(controlPlaneVIP string, transportTimeout, eventuallyTimeout time.Duration) { + if strings.Contains(controlPlaneVIP, ":") { + controlPlaneVIP = fmt.Sprintf("[%s]", controlPlaneVIP) + } + + transport := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{Transport: transport, Timeout: transportTimeout} + Eventually(func() int { + resp, _ := client.Get(fmt.Sprintf("https://%s:6443/livez", controlPlaneVIP)) + if resp == nil { + return -1 + } + return resp.StatusCode + }, eventuallyTimeout).Should(Equal(http.StatusOK), "Failed to connect to VIP") +} + +func killLeader(leaderIPAddr string, clusterName string) { + dockerControlPlaneContainerNames := []string{ + fmt.Sprintf("%s-control-plane", clusterName), + fmt.Sprintf("%s-control-plane2", clusterName), + fmt.Sprintf("%s-control-plane3", clusterName), + } + var leaderName string + for _, name := range dockerControlPlaneContainerNames { + cmdOut := new(bytes.Buffer) + cmd := exec.Command( + "docker", "exec", name, "ip", "addr", + ) + cmd.Stdout = cmdOut + + Eventually(cmd.Run).Should(Succeed()) + + if strings.Contains(cmdOut.String(), leaderIPAddr) { + leaderName = name + break + } + } + Expect(leaderName).ToNot(BeEmpty()) + + cmd := exec.Command( + "docker", "kill", leaderName, + ) + + session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session, "5s").Should(gexec.Exit(0)) +} + +func withTimestamp(text string) string { + return fmt.Sprintf("%s: %s", time.Now(), text) +} + +func getKindNetworkSubnetCIDRs() []string { + cmd := exec.Command( + "docker", "inspect", "kind", + "--format", `{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}`, + ) + cmdOut := new(bytes.Buffer) + cmd.Stdout = cmdOut + Expect(cmd.Run()).To(Succeed(), "The Docker \"kind\" network was not found.") + reader := bufio.NewReader(cmdOut) + + cidrs := []string{} + for { + line, readErr := reader.ReadString('\n') + if readErr != nil && readErr != io.EOF { + Expect(readErr).NotTo(HaveOccurred(), "Error finding subnet CIDRs in the Docker \"kind\" network") + } + + cidrs = append(cidrs, strings.TrimSpace(line)) + if readErr == io.EOF { + break + } + } + + return cidrs +} + +func generateIPv4VIP() string { + cidrs := getKindNetworkSubnetCIDRs() + + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + Expect(parseErr).NotTo(HaveOccurred()) + + if ip.To4() != nil { + mask := binary.BigEndian.Uint32(ipNet.Mask) + start := binary.BigEndian.Uint32(ipNet.IP) + end := (start & mask) | (^mask) + + chosenVIP := make([]byte, 4) + binary.BigEndian.PutUint32(chosenVIP, end-5) + return net.IP(chosenVIP).String() + } + } + Fail("Could not find any IPv4 CIDRs in the Docker \"kind\" network") + return "" +} + +func generateIPv6VIP() string { + cidrs := getKindNetworkSubnetCIDRs() + + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + Expect(parseErr).NotTo(HaveOccurred()) + + if ip.To4() == nil { + lowerMask := binary.BigEndian.Uint64(ipNet.Mask[8:]) + lowerStart := binary.BigEndian.Uint64(ipNet.IP[8:]) + lowerEnd := (lowerStart & lowerMask) | (^lowerMask) + + chosenVIP := make([]byte, 16) + // Copy upper half into chosenVIP + copy(chosenVIP, ipNet.IP[0:8]) + // Copy lower half into chosenVIP + binary.BigEndian.PutUint64(chosenVIP[8:], lowerEnd-5) + return net.IP(chosenVIP).String() + } + } + Fail("Could not find any IPv6 CIDRs in the Docker \"kind\" network") + return "" +} + +type TestLogger struct{} + +func (t TestLogger) Warnf(format string, args ...interface{}) { + klog.Warningf(format, args...) +} + +func (t TestLogger) Warn(message string) { + klog.Warning(message) +} + +func (t TestLogger) Error(message string) { + klog.Error(message) +} + +func (t TestLogger) Errorf(format string, args ...interface{}) { + klog.Errorf(format, args...) +} + +func (t TestLogger) V(level log.Level) log.InfoLogger { + return TestInfoLogger{Verbose: klog.V(klog.Level(level))} +} + +type TestInfoLogger struct { + klog.Verbose +} + +func (t TestInfoLogger) Info(message string) { + t.Verbose.Info(message) +} diff --git a/testing/e2e/kube-vip.yaml.tmpl b/testing/e2e/kube-vip.yaml.tmpl new file mode 100644 index 00000000..a8c77b32 --- /dev/null +++ b/testing/e2e/kube-vip.yaml.tmpl @@ -0,0 +1,41 @@ +--- +apiVersion: v1 +kind: Pod +metadata: + name: kube-vip + namespace: kube-system +spec: + containers: + - name: kube-vip + args: + - start + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: vip_leaderelection + value: "true" + - name: address + value: "{{ .ControlPlaneVIP }}" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + image: "{{ .ImagePath }}" + imagePullPolicy: Never + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig From 3cf9702077abab13ad7e592f6db9939c18b37863 Mon Sep 17 00:00:00 2001 From: "Diogenes S. Jesus" Date: Tue, 13 Apr 2021 14:46:59 +0200 Subject: [PATCH 091/542] change word expended to expanded "expend" => "spend" "expand" => "become/make larger" --- docs/architecture/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index e76eafbe..1d6465d3 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -5,7 +5,7 @@ This section covers two parts of the architecture: 1. The technical capabilities of `kube-vip` 2. The components to build a load-balancing service within [Kubernetes](https://kubernetes.io) -The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expended to provide the same functionality for applications within a Kubernetes cluster. +The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expanded to provide the same functionality for applications within a Kubernetes cluster. Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). From 7c4d919cfc260f847e50ca42acad8abc91547837 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 15 Apr 2021 15:33:58 +0300 Subject: [PATCH 092/542] fix: unassign IPs correctly for Equinix Metal IP assignment href returned from the API looks like: ``` /metal/v1/ips/97972920-f00b-453f-be1e-31eb53c19e38 ``` It should be cleaned up to contain ID only, removing `/ips/` leads to broken requests like: ``` 2021/04/15 12:03:41 [DEBUG] DELETE https://api.equinix.com/metal/v1/ips//metal/v197972920-f00b-453f-be1e-31eb53c19e38 ``` Signed-off-by: Andrey Smirnov --- pkg/packet/eip.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index 8017dd8d..901eb19a 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -2,7 +2,7 @@ package packet import ( "fmt" - "strings" + "path" "github.com/packethost/packngo" "github.com/plunder-app/kube-vip/pkg/kubevip" @@ -26,7 +26,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { log.Infof("Found EIP ->%s ID -> %s\n", ip.Address, ip.ID) // If attachements already exist then remove them if len(ip.Assignments) != 0 { - hrefID := strings.Replace(ip.Assignments[0].Href, "/ips/", "", -1) + hrefID := path.Base(ip.Assignments[0].Href) c.DeviceIPs.Unassign(hrefID) } } From e304614f3561bdf041bd6b393841380591112996 Mon Sep 17 00:00:00 2001 From: Vasileios Anagnostopoulos Date: Sat, 17 Apr 2021 00:18:25 +0200 Subject: [PATCH 093/542] Adding the release actions --- .github/workflows/main.yaml | 43 ++++++++++++++++++++++++++++++++++ .github/workflows/release.yaml | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 .github/workflows/main.yaml create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 00000000..7bdce92f --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,43 @@ +name: Publish the latest dev image + +on: + push: + branches: + - 'master' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Prepare Names + id: prep + run: | + DOCKER_IMAGE=plndr/kube-vip + VERSION=$(echo ${GITHUB_SHA} | cut -c1-8) + TAGS="${DOCKER_IMAGE}:${VERSION}" + TAGS="$TAGS,${DOCKER_IMAGE}:nightly" + echo ::set-output name=tags::${TAGS} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push main branch + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm/v7,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.prep.outputs.tags }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..e24ef4f9 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,42 @@ +name: Publish Releases to Docker Hub + +on: + push: + tags: + - '*' +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Prepare Names + id: prep + run: | + DOCKER_IMAGE=plndr/kube-vip + VERSION=${GITHUB_REF#refs/tags/} + TAGS="${DOCKER_IMAGE}:${VERSION}" + TAGS="$TAGS,${DOCKER_IMAGE}:latest" + echo ::set-output name=tags::${TAGS} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push main branch + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm/v7,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.prep.outputs.tags }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} From f1553b2bcd4c352017f270023c63c3f383fca275 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 19 Apr 2021 13:51:38 +0100 Subject: [PATCH 094/542] Adds Password support --- pkg/manager/watcher.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index cbea9231..b345a4b5 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -139,12 +139,12 @@ func (sm *Manager) annotationsWatcher() error { // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added, watch.Modified: - // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") } + // BGP Local configuration nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] if nodeASN != "" { u64, err := strconv.ParseUint(nodeASN, 10, 32) @@ -155,12 +155,22 @@ func (sm *Manager) annotationsWatcher() error { } else { continue } + srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] if srcIP != "" { sm.config.BGPConfig.RouterID = srcIP } else { continue } + + // Peer configuration + + bgpPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] + if bgpPassword != "" { + sm.config.BGPPeerConfig.Password = bgpPassword + } else { + continue + } peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] if peerASN != "" { u64, err := strconv.ParseUint(peerASN, 10, 32) @@ -192,7 +202,7 @@ func (sm *Manager) annotationsWatcher() error { case watch.Deleted: node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + return fmt.Errorf("Unable to parse Kubernetes Node from Kubernetes watcher") } log.Infof("Node [%s] has been deleted", node.Name) @@ -200,7 +210,7 @@ func (sm *Manager) annotationsWatcher() error { case watch.Bookmark: // Un-used case watch.Error: - log.Error("Error attempting to watch Kubernetes services") + log.Error("Error attempting to watch Kubernetes Nodes") // This round trip allows us to handle unstructured status errObject := apierrors.FromObject(event.Object) From e1d3ee24ea169e3ad8d32af7045b0c8604755b3e Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 19 Apr 2021 13:55:38 +0100 Subject: [PATCH 095/542] base64 decoding --- pkg/manager/watcher.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index b345a4b5..9ace9920 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -2,6 +2,7 @@ package manager import ( "context" + "encoding/base64" "fmt" "os" "strconv" @@ -165,9 +166,14 @@ func (sm *Manager) annotationsWatcher() error { // Peer configuration - bgpPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] - if bgpPassword != "" { - sm.config.BGPPeerConfig.Password = bgpPassword + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] + if base64BGPPassword != "" { + // Decode base64 encoded string + decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) + if err != nil { + return err + } + sm.config.BGPPeerConfig.Password = string(decodedPassword) } else { continue } From 9fdf8026ddff2c3dddb28a87f362d414a78fbf0e Mon Sep 17 00:00:00 2001 From: Gabe Rosenhouse Date: Mon, 19 Apr 2021 21:47:58 +0000 Subject: [PATCH 096/542] run e2e tests in CI --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1dc40704..24b65bb5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,3 +23,5 @@ jobs: run: make dockerx86Action - name: Manifest generate run: ./testing/testing.sh + - name: e2e tests + run: DOCKERTAG=action make e2e-tests From 00572acbc157f69f5129248303f0a14eda03c764 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 20 Apr 2021 11:04:52 +0100 Subject: [PATCH 097/542] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index aa82eaf5..9d87f5a3 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ The idea behind `kube-vip` is a small self-contained Highly-Available option for Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). +- VIP addresses can be both IPv4 or IPv6 - Control Plane with ARP (Layer 2) or BGP (Layer 3) - Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) - Control Plane HA with kubeadm (static Pods) From 239ff56dfa08c3dd16710cc5443010b0a645b64b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 20 Apr 2021 15:25:32 +0100 Subject: [PATCH 098/542] Fixes interface on networking restart --- Makefile | 2 +- pkg/cluster/clusterLeader.go | 13 +++++++- pkg/cluster/singleNode.go | 62 +++++++++++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 828cf328..003646fa 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.3.3 +VERSION := 0.3.4 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index ac9cd666..8ca64640 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -295,12 +295,23 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } for { + + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + err = cluster.Network.AddIP() + log.Warnf("%v", err) + } + select { case <-ctx.Done(): // if cancel() execute return default: if vip.IsIPv4(ipString) { - // Gratuitous ARP, will broadcast to new MAC <-> IP + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address err := vip.ARPSendGratuitous(ipString, c.Interface) if err != nil { log.Warnf("%v", err) diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 8cccdec4..43b8212a 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -1,7 +1,9 @@ package cluster import ( + "context" "fmt" + "time" log "github.com/sirupsen/logrus" @@ -110,6 +112,11 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // Start a kube-vip loadbalancer service log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) + // use a Go context so we can tell the arp loop code when we + // want to step down + ctxArp, cancelArp := context.WithCancel(context.Background()) + defer cancelArp() + cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) @@ -124,11 +131,55 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } if c.EnableARP == true { - // Gratuitous ARP, will broadcast to new MAC <-> IP - err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) + ctxArp, cancelArp = context.WithCancel(context.Background()) + + ipString := cluster.Network.IP() + + var ndp *vip.NdpResponder + if vip.IsIPv6(ipString) { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } } + go func(ctx context.Context) { + if ndp != nil { + defer ndp.Close() + } + + for { + + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + err = cluster.Network.AddIP() + log.Warnf("%v", err) + } + + select { + case <-ctx.Done(): // if cancel() execute + return + default: + if vip.IsIPv4(ipString) { + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address + err := vip.ARPSendGratuitous(ipString, c.Interface) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } + } + } + time.Sleep(3 * time.Second) + } + }(ctxArp) } if c.EnableBGP { @@ -151,6 +202,9 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser if err != nil { log.Warnf("%v", err) } + // Stop the Arp context if it is running + cancelArp() + close(cluster.completed) return } From 49b77ab303b3c16ec959107d731e650550e9d8f2 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 21 Apr 2021 19:31:40 +0100 Subject: [PATCH 099/542] Error fixes --- pkg/cluster/clusterLeader.go | 5 ++++- pkg/cluster/singleNode.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 8ca64640..fa0d4f1f 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -302,8 +302,11 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe log.Warnf("%v", err) } if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) err = cluster.Network.AddIP() - log.Warnf("%v", err) + if err != nil { + log.Warnf("%v", err) + } } select { diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 43b8212a..70e57311 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -155,8 +155,11 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser log.Warnf("%v", err) } if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) err = cluster.Network.AddIP() - log.Warnf("%v", err) + if err != nil { + log.Warnf("%v", err) + } } select { From eaebadd6683c3407c74a099c2ddec3e3c9063fea Mon Sep 17 00:00:00 2001 From: Franciosi Date: Mon, 26 Apr 2021 15:54:46 -0300 Subject: [PATCH 100/542] Small Typo Improves in README.md Small typo improvements --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9d87f5a3..21f32b08 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The idea behind `kube-vip` is a small self-contained Highly-Available option for - Virtualisation - Pretty much anywhere else :) -**NOTE** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io) +**NOTE:** All documentation of both usage and architecture are now available at [https://kube-vip.io](https://kube-vip.io). ## Features @@ -42,7 +42,7 @@ The purpose of `kube-vip` is to simplify the building of HA Kubernetes clusters, **VIP**: - [Keepalived](https://www.keepalived.org/) -- [Ucarp](https://ucarp.wordpress.com/) +- [UCARP](https://ucarp.wordpress.com/) - Hardware Load-balancer (functionality differs per vendor) @@ -55,4 +55,4 @@ All of these would require a separate level of configuration and in some infrast ## Troubleshooting and Feedback -Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/) +Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/). From 927ddf74fbc82ec19ee26e927c7d6c9a3cac2ebb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 7 May 2021 15:55:25 +0100 Subject: [PATCH 101/542] Swap DHCP to a pkg with better licenses --- cmd/kube-vip.go | 2 +- go.mod | 82 +++--- go.sum | 482 ++++++++++++++++++++++++------- pkg/cluster/singleNode.go | 4 +- pkg/manager/manager.go | 14 +- pkg/manager/prom.go | 2 +- pkg/manager/services.go | 132 +-------- pkg/manager/services_dhcp.go | 199 +++++++++++++ pkg/service/manager.go | 148 ++-------- pkg/service/manager_arp.go | 2 +- pkg/service/manager_bgp.go | 7 +- pkg/service/prom.go | 8 + pkg/service/services.go | 259 ++++++----------- pkg/service/services.txt | 159 +++++++++++ pkg/service/services_dhcp.go | 211 ++++++++++++++ pkg/service/watcher.go | 134 +++++---- pkg/vip/ddns.go | 7 +- pkg/vip/dhcp.go | 535 +++++++++++++++++++++++++++++++++++ 18 files changed, 1741 insertions(+), 646 deletions(-) create mode 100644 pkg/manager/services_dhcp.go create mode 100644 pkg/service/prom.go create mode 100644 pkg/service/services.txt create mode 100644 pkg/service/services_dhcp.go create mode 100644 pkg/vip/dhcp.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index e3533c7e..91b8a7cb 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -238,7 +238,7 @@ var kubeVipManager = &cobra.Command{ log.Fatalf("%v", err) } - prometheus.MustRegister(mgr.PromethesCollector()...) + prometheus.MustRegister(mgr.PrometheusCollector()...) // Start the service manager, this will watch the config Map and construct kube-vip services for it err = mgr.Start() diff --git a/go.mod b/go.mod index 4642d65b..cba9314b 100644 --- a/go.mod +++ b/go.mod @@ -3,63 +3,69 @@ module github.com/plunder-app/kube-vip go 1.14 require ( - github.com/armon/go-metrics v0.3.4 // indirect + github.com/armon/go-metrics v0.3.8 // indirect + github.com/containernetworking/cni v0.8.1 + github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c + github.com/d2g/dhcp4client v1.0.0 github.com/davecgh/go-spew v1.1.1 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/digineo/go-dhclient v1.0.2 - github.com/eapache/queue v1.1.0 // indirect - github.com/fatih/color v1.9.0 // indirect + github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 - github.com/go-logr/logr v0.2.1 // indirect - github.com/golang/protobuf v1.4.2 - github.com/google/go-cmp v0.5.2 // indirect + github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.18 - github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.5.1 // indirect - github.com/hashicorp/go-hclog v0.14.1 // indirect - github.com/hashicorp/go-immutable-radix v1.2.0 // indirect + github.com/google/gopacket v1.1.19 + github.com/google/uuid v1.2.0 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/hashicorp/go-hclog v0.16.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-msgpack v1.1.5 // indirect - github.com/hashicorp/go-retryablehttp v0.6.7 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/raft v1.1.2 - github.com/imdario/mergo v0.3.11 // indirect + github.com/hashicorp/raft v1.3.1 + github.com/imdario/mergo v0.3.12 // indirect + github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9 + github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7 // indirect + github.com/json-iterator/go v1.1.11 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect - github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef - github.com/magiconair/properties v1.8.3 // indirect - github.com/mattn/go-colorable v0.1.7 // indirect + github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 + github.com/magiconair/properties v1.8.5 // indirect github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 - github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect - github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.7.0 github.com/osrg/gobgp v2.0.0+incompatible - github.com/packethost/packngo v0.5.1 + github.com/packethost/packngo v0.13.0 + github.com/pelletier/go-toml v1.9.0 // indirect github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.4.0 - github.com/sirupsen/logrus v1.6.0 - github.com/spf13/afero v1.4.0 // indirect + github.com/prometheus/client_golang v1.10.0 + github.com/prometheus/common v0.23.0 // indirect + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.0.0 + github.com/spf13/cobra v1.1.3 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 // indirect github.com/vishvananda/netlink v1.1.0 - github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect - golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect - golang.org/x/net v0.0.0-20201021035429-f5854403a974 - golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect - golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 - golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect - google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0 // indirect - google.golang.org/grpc v1.32.0 // indirect - gopkg.in/ini.v1 v1.61.0 // indirect - k8s.io/api v0.19.2 - k8s.io/apimachinery v0.19.2 - k8s.io/client-go v0.19.0 + github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect + golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect + golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 + golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect + golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 + golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 // indirect + google.golang.org/grpc v1.37.0 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/api v0.21.0 + k8s.io/apimachinery v0.21.0 + k8s.io/client-go v0.21.0 k8s.io/klog v1.0.0 - k8s.io/klog/v2 v2.3.0 - k8s.io/utils v0.0.0-20200912215256-4140de9c8800 // indirect + k8s.io/klog/v2 v2.8.0 + k8s.io/utils v0.0.0-20210305010621-2afb4311ab10 // indirect sigs.k8s.io/kind v0.10.0 + sigs.k8s.io/structured-merge-diff/v4 v4.1.1 // indirect ) replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 diff --git a/go.sum b/go.sum index a36df3f0..ab66b77c 100644 --- a/go.sum +++ b/go.sum @@ -6,7 +6,6 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -33,46 +32,58 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alessio/shellescape v1.2.2 h1:8LnL+ncxhWT2TR00dfJRT25JWWrhkMZXneHVWnetDZg= github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-metrics v0.3.4 h1:Xqf+7f2Vhl9tsqDYmXhnXInUdcrtgpRNpIA15/uldSc= -github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.8 h1:oOxq3KPj0WhCuy50EhzwiyMyG2ovRQZpZLXQuOh2a/M= +github.com/armon/go-metrics v0.3.8/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -81,18 +92,35 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU= +github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0 h1:suYBsYZIkSlUMEz4TAYCczKf62IA2UWC+O8+KtdOhCo= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -107,24 +135,37 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.0.2/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -137,22 +178,36 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE= -github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -178,8 +233,12 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -189,15 +248,17 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -208,50 +269,56 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/gnostic v0.5.1 h1:A8Yhf6EtqTv9RMsU6MQTyrtV1TjWlR6xU9BsZIwuTCM= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU= -github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.0 h1:uCeOEwSWGMwhJUdpUjk+1cVKIEfGu2/1nFXukimi2MU= +github.com/hashicorp/go-hclog v0.16.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.2.0 h1:l6UW37iCXwZkZoAbEYnptSHVE/cQ5bOTPYG5W3vf9+8= -github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo= -github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -263,72 +330,120 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c= -github.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= +github.com/hashicorp/raft v1.3.1 h1:zDT8ke8y2aP4wf9zPTB2uSIeavJ3Hx/ceY4jxI2JxuY= +github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9 h1:T+Czi1NGxrbx8enhcdUFPVYTpGd6DPDxrKptDXRgD8I= +github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI= github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= +github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7 h1:0pS4NUf9WPvydLWHx2VHafjEyfN8vQrAxl/n3Kt2K9c= +github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7/go.mod h1:+fPVEwpdpYDhPa086y6yIAwUno3cBJZw15Fds43LDRA= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= -github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef h1:hYYYR5sSbR211XTKlIERN7I7xYU1D47eft2ooDg0Dtg= -github.com/kamhlos/upnp v0.0.0-20171112074648-2713e75d9aef/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= +github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= +github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.3 h1:kJSsc6EXkBLgr3SphHk9w5mtjn0bjlR4JYEXKrJ45rQ= -github.com/magiconair/properties v1.8.3/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= +github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= +github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -339,8 +454,9 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -349,152 +465,229 @@ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyTzf1c5VubkPi+Q83O9oBCNgA= github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= -github.com/packethost/packngo v0.5.1 h1:y+jWcMnyArP3hVZRsBkAXTLhokuqdYg6JUmkshX2SMk= -github.com/packethost/packngo v0.5.1/go.mod h1:aRxUEV1TprXVcWr35v8tNYgZMjv7FHaInXx224vF2fc= +github.com/packethost/packngo v0.13.0 h1:VIeDY/Uju53v8LAKxiqTrfR9jkpX5PhWdnQC0h3aUU8= +github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.0.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= +github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlPDGM= +github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v0.0.0-20170217164146-9be650865eab/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8= -github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.0-20170731170427-b26b538f6930/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v0.0.0-20170523133247-0efa5202c046/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= +github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v0.0.0-20170802012344-a95659537721/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20170707011535-86bef332bfc3/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= +golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -517,6 +710,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -533,6 +727,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -545,7 +740,10 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -561,15 +759,24 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -578,6 +785,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -585,26 +794,32 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -620,24 +835,52 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -652,6 +895,7 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -659,6 +903,8 @@ golang.org/x/tools v0.0.0-20190826182127-07722704da13/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -667,6 +913,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -682,14 +929,18 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -707,18 +958,21 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -743,14 +997,19 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0 h1:uslsjIdqvZYANxSBQjTI47vZfwMaTN3mLELkMnMIY/A= -google.golang.org/genproto v0.0.0-20200917134801-bb4cff56e0d0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 h1:0pBp6vCQyvmttnWa4c74n/y2U7bAQeIUVyVvZpb7Fyo= +google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/grpc v1.5.1/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -759,8 +1018,9 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -770,24 +1030,30 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10= -gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170721122051-25c4ec802a7d/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -795,10 +1061,14 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -807,33 +1077,37 @@ honnef.co/go/tools v0.0.0-20191022112108-ee025456fe28/go.mod h1:YZLKf07TTEX58hla honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= -k8s.io/api v0.19.2 h1:q+/krnHWKsL7OBZg/rxnycsl9569Pud76UJ77MvKXms= -k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= -k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc= +k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= +k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/client-go v0.19.0 h1:1+0E0zfWFIWeyRhQYWzimJOyAk2UT7TiARaLNwJCf7k= -k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= +k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= +k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= +k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= +k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.3.0 h1:WmkrnW7fdrm0/DMClc+HIxtftvxVIPAhlVwMQo5yLco= -k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20200912215256-4140de9c8800 h1:9ZNvfPvVIEsp/T1ez4GQuzCcCTEQWhovSofhqR73A6g= -k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210305010621-2afb4311ab10 h1:u5rPykqiCpL+LBfjRkXvnK71gOgIdmq3eHUEkPrbeTI= +k8s.io/utils v0.0.0-20210305010621-2afb4311ab10/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kind v0.10.0 h1:Tm+QITIqdRd+efLOsxZHMAfLnr5K4e3/RH8MePspEXs= sigs.k8s.io/kind v0.10.0/go.mod h1:fb32zUw7ewC47bPwLnwhf47wd/vADtv3c38KP7sjIlo= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.1 h1:nYqY2A6oy37sKLYuSBXuQhbj4JVclzJK13BOIvJG5XU= +sigs.k8s.io/structured-merge-diff/v4 v4.1.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 70e57311..2528a76a 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -120,6 +120,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) + err := cluster.Network.DeleteIP() if err != nil { log.Warnf("Attempted to clean existing VIP => %v", err) @@ -148,7 +149,6 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } for { - // Ensure the address exists on the interface before attempting to ARP set, err := cluster.Network.IsSet() if err != nil { @@ -200,7 +200,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser select { case <-cluster.stop: log.Info("[LOADBALANCER] Stopping load balancers") - log.Info("[VIP] Releasing the Virtual IP") + log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIPCIDR) err = cluster.Network.DeleteIP() if err != nil { log.Warnf("%v", err) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 89ba964b..00468ab4 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -9,11 +9,11 @@ import ( "strings" "syscall" - dhclient "github.com/digineo/go-dhclient" "github.com/kamhlos/upnp" "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" @@ -49,12 +49,6 @@ type Manager struct { countServiceWatchEvent *prometheus.CounterVec } -type dhcpService struct { - // dhcpClient (used DHCP for the vip) - dhcpClient *dhclient.Client - dhcpInterface string -} - // Instance defines an instance of everything needed to manage a vip type Instance struct { // Virtual IP / Load Balancer configuration @@ -63,8 +57,10 @@ type Instance struct { // cluster instance cluster cluster.Cluster - // Custom settings - dhcp *dhcpService + // Service uses DHCP + isDHCP bool + dhcpInterface string + lease *vip.DHCPLease // Kubernetes service mapping Vip string diff --git a/pkg/manager/prom.go b/pkg/manager/prom.go index b22de320..be3c0014 100644 --- a/pkg/manager/prom.go +++ b/pkg/manager/prom.go @@ -2,6 +2,6 @@ package manager import "github.com/prometheus/client_golang/prometheus" -func (sm *Manager) PromethesCollector() []prometheus.Collector { +func (sm *Manager) PrometheusCollector() []prometheus.Collector { return []prometheus.Collector{sm.countServiceWatchEvent} } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 685973b6..7a538543 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -3,10 +3,8 @@ package manager import ( "context" "fmt" - "net" "strings" - dhclient "github.com/digineo/go-dhclient" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" @@ -39,12 +37,13 @@ func (sm *Manager) deleteService(uid string) error { } else { // Flip the found when we match found = true - if sm.serviceInstances[x].dhcp != nil { - sm.serviceInstances[x].dhcp.dhcpClient.Stop() - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcp.dhcpInterface) + if sm.serviceInstances[x].isDHCP == true { + sm.serviceInstances[x].lease.Stop() + macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + return fmt.Errorf("Error finding VIP Interface, for deleting DHCP Link : %v", err) } + netlink.LinkDel(macvlan) } if sm.serviceInstances[x].vipConfig.EnableBGP { @@ -104,128 +103,11 @@ func (sm *Manager) syncServices(service *v1.Service) error { // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP if newServiceAddress == "0.0.0.0" { - - parent, err := netlink.LinkByName(sm.config.Interface) + err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) - } - - // Create macvlan - - // Generate name from UID - interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) - - // 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) - - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} - - err = netlink.LinkAdd(mac) - if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) - } - - err = netlink.LinkSetUp(mac) - if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) - } - iface, err = net.InterfaceByName(interfaceName) - if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) - } - } else { - log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) - - } - - client := dhclient.Client{ - Iface: iface, - OnBound: func(lease *dhclient.Lease) { - - // Set VIP to Address from lease - newVip.VIP = lease.FixedAddress.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, service.Name, newServiceUID) - - // // Generate Load Balancer config - // newLB := kubevip.LoadBalancer{ - // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - // Port: s.Services[x].Port, - // Type: s.Services[x].Type, - // BindToVip: true, - // } - - // // Add Load Balancer Configuration - // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - //return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - //return err - } - newService.cluster = *c - - // Begin watching this service - // TODO - we may need this - // go sm.serviceWatcher(&newService, sm.config.Namespace) - - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) - - // Update the service - // ns, err := returnNameSpace() - // if err != nil { - // log.Errorf("Error finding Namespace") - // return - // } - // dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.ServiceName, metav1.GetOptions{}) - // if err != nil { - // log.Errorf("Error finding Service [%s] : %v", newService.ServiceName, err) - // return - // } - - // Update the service with DHCP information - service.Spec.LoadBalancerIP = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(service.Namespace).Update(context.TODO(), service, metav1.UpdateOptions{}) - log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return - } - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return - } - sm.upnpMap(newService) - - }, - } - - newService.dhcp = &dhcpService{ - dhcpClient: &client, - dhcpInterface: interfaceName, + return err } - - // Start the DHCP Client - newService.dhcp.dhcpClient.Start() - - // Change the interface name to our new DHCP macvlan interface - newVip.Interface = interfaceName - log.Infof("DHCP Interface and Client is up and active [%s]", interfaceName) return nil - } log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceName, newService.UID) diff --git a/pkg/manager/services_dhcp.go b/pkg/manager/services_dhcp.go new file mode 100644 index 00000000..0144b78f --- /dev/null +++ b/pkg/manager/services_dhcp.go @@ -0,0 +1,199 @@ +package manager + +import ( + "context" + "fmt" + "net" + + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/dhcpv6/client6" + "github.com/insomniacslk/dhcp/netboot" + "github.com/vishvananda/netlink" +) + +func dhclient6(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { + if attempts < 1 { + attempts = 1 + } + llAddr, err := dhcpv6.GetLinkLocalAddr(ifname) + if err != nil { + return nil, err + } + laddr := net.UDPAddr{ + IP: llAddr, + Port: dhcpv6.DefaultClientPort, + Zone: ifname, + } + raddr := net.UDPAddr{ + IP: dhcpv6.AllDHCPRelayAgentsAndServers, + Port: dhcpv6.DefaultServerPort, + Zone: ifname, + } + c := client6.NewClient() + c.LocalAddr = &laddr + c.RemoteAddr = &raddr + var conv []dhcpv6.DHCPv6 + for attempt := 0; attempt < attempts; attempt++ { + log.Printf("Attempt %d of %d", attempt+1, attempts) + conv, err = c.Exchange(ifname, dhcpv6.WithNetboot) + if err != nil && attempt < attempts { + log.Printf("Error: %v", err) + continue + } + break + } + if verbose { + for _, m := range conv { + log.Print(m.Summary()) + } + } + if err != nil { + return nil, err + } + // extract the network configuration + netconf, err := netboot.ConversationToNetconf(conv) + return netconf, err +} + +func dhclient4(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { + if attempts < 1 { + attempts = 1 + } + client := client4.NewClient() + var ( + conv []*dhcpv4.DHCPv4 + err error + ) + for attempt := 0; attempt < attempts; attempt++ { + log.Printf("Attempt %d of %d", attempt+1, attempts) + conv, err = client.Exchange(ifname) + if err != nil && attempt < attempts { + log.Printf("Error: %v", err) + continue + } + break + } + if verbose { + for _, m := range conv { + log.Print(m.Summary()) + } + } + if err != nil { + return nil, err + } + // extract the network configuration + netconf, err := netboot.ConversationToNetconfv4(conv) + return netconf, err +} + +func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { + parent, err := netlink.LinkByName(sm.config.Interface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + + // Create macvlan + + // Generate name from UID + interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) + + // Check if the interface doesn't exist first + _, err = net.InterfaceByName(interfaceName) + if err != nil { + log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) + + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_DEFAULT} + + err = netlink.LinkAdd(mac) + if err != nil { + return fmt.Errorf("Could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) + } + _, err = net.InterfaceByName(interfaceName) + if err != nil { + return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + } + + newService.lease, err = vip.AcquireLease(newServiceUID[0:8], interfaceName, nil) + + if err != nil { + return err + } + + ipNet, err := newService.lease.IPNet() + newVip.VIP = ipNet.IP.String() + newVip.Interface = interfaceName + + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + + // Create Add configuration to the new service + newService.vipConfig = *newVip + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return err + } + newService.cluster = *c + + // Set that DHCP is enabled + newService.isDHCP = true + // Set the name of the interface so that it can be removed on Service deletion + newService.dhcpInterface = interfaceName + // Add new service to manager configuration + service.Spec.LoadBalancerIP = newVip.VIP + log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) + sm.serviceInstances = append(sm.serviceInstances, *newService) + + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + sm.upnpMap(*newService) + return nil +} diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 29800f91..d0de0d8b 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -1,32 +1,23 @@ package service import ( - "context" - "encoding/json" "fmt" "io/ioutil" "os" "path/filepath" "strings" - "github.com/davecgh/go-spew/spew" "github.com/kamhlos/upnp" + "github.com/prometheus/client_golang/prometheus" - dhclient "github.com/digineo/go-dhclient" "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" 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" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" - watchtools "k8s.io/client-go/tools/watch" ) const plunderLock = "plunder-lock" @@ -36,38 +27,6 @@ var OutSideCluster bool var signalChan chan os.Signal -type plndrServices struct { - Services []service `json:"services"` -} - -type dhcpService struct { - // dhcpClient (used DHCP for the vip) - dhcpClient *dhclient.Client - dhcpInterface string -} - -type serviceInstance struct { - // Virtual IP / Load Balancer configuration - vipConfig kubevip.Config - // Kubernetes service mapping - service service - // cluster instance - cluster cluster.Cluster - - // Custom settings - dhcp *dhcpService -} - -// TODO - call from a package (duplicated struct in the cloud-provider code) -type service struct { - Vip string `json:"vip"` - Port int `json:"port"` - UID string `json:"uid"` - Type string `json:"type"` - - ServiceName string `json:"serviceName"` -} - // Manager degines the manager of the load-balancing services type Manager struct { clientSet *kubernetes.Clientset @@ -75,12 +34,41 @@ type Manager struct { config *kubevip.Config // Keeps track of all running instances - serviceInstances []serviceInstance + serviceInstances []Instance // Additional functionality upnp *upnp.Upnp + //BGP Manager, this is a singleton that manages all BGP advertisements bgpServer *bgp.Server + + // This channel is used to signal a shutdown + signalChan chan os.Signal + + // This is a promethues counter used to count the number of events received + // from the service watcher + countServiceWatchEvent *prometheus.CounterVec +} + +// Instance defines an instance of everything needed to manage a vip +type Instance struct { + // Virtual IP / Load Balancer configuration + vipConfig kubevip.Config + + // cluster instance + cluster cluster.Cluster + + // Service uses DHCP + isDHCP bool + dhcpInterface string + + // Kubernetes service mapping + Vip string + Port int32 + UID string + Type string + + ServiceName string } // NewManager will create a new managing object @@ -145,77 +133,3 @@ func returnNameSpace() (string, error) { } return "", fmt.Errorf("Unable to find Namespace") } - -// The watcher will watch config maps for new services being created -func (sm *Manager) watcher(ctx context.Context, ns string) { - // Build a options structure to defined what we're looking for - listOptions := metav1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", sm.configMap), - } - - // Watch function - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) - }, - }) - - if err != nil { - log.Errorf("error creating watcher: %s", err.Error()) - ctx.Done() - } - - ch := rw.ResultChan() - defer rw.Stop() - log.Infof("Beginning watching Kubernetes configMap [%s]", sm.configMap) - - var svcs plndrServices - - go func() { - for event := range ch { - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - log.Debugf("ConfigMap [%s] has been Created or modified", sm.configMap) - cm, ok := event.Object.(*v1.ConfigMap) - if !ok { - log.Errorf("Unable to parse ConfigMap from watcher") - break - } - data := cm.Data["plndr-services"] - json.Unmarshal([]byte(data), &svcs) - log.Debugf("Found %d services defined in ConfigMap", len(svcs.Services)) - - err = sm.syncServices(&svcs) - if err != nil { - log.Errorf("%v", err) - } - case watch.Deleted: - log.Debugf("ConfigMap [%s] has been Deleted", sm.configMap) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Infoln("err") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - - default: - } - } - }() - - <-signalChan -} diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index 87db51cc..a2f05349 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -112,7 +112,7 @@ func (sm *Manager) startARP() error { RetryPeriod: 1 * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - sm.watcher(ctx, ns) + sm.servicesWatcher(ctx) }, OnStoppedLeading: func() { // we can do cleanup here diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index d3d82f5e..c5b332ea 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -14,13 +14,10 @@ import ( // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) startBGP() error { - ns, err := returnNameSpace() - if err != nil { - return err - } // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client + var err error if sm.config.EnableMetal { packetClient, err = packngo.NewClient() if err != nil { @@ -74,7 +71,7 @@ func (sm *Manager) startBGP() error { cancel() }() - sm.watcher(ctx, ns) + sm.servicesWatcher(ctx) log.Infof("Shutting down Kube-Vip") diff --git a/pkg/service/prom.go b/pkg/service/prom.go new file mode 100644 index 00000000..2b316691 --- /dev/null +++ b/pkg/service/prom.go @@ -0,0 +1,8 @@ +package service + +import "github.com/prometheus/client_golang/prometheus" + +//PrometheusCollector - required for statistics // TODO - improve monitoring +func (sm *Manager) PrometheusCollector() []prometheus.Collector { + return []prometheus.Collector{sm.countServiceWatchEvent} +} diff --git a/pkg/service/services.go b/pkg/service/services.go index 7337133e..6810ab6f 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -3,21 +3,20 @@ package service import ( "context" "fmt" - "net" "strings" - dhclient "github.com/digineo/go-dhclient" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func (sm *Manager) stopService(uid string) error { found := false for x := range sm.serviceInstances { - if sm.serviceInstances[x].service.UID == uid { + if sm.serviceInstances[x].UID == uid { found = true sm.serviceInstances[x].cluster.Stop() } @@ -29,20 +28,19 @@ func (sm *Manager) stopService(uid string) error { } func (sm *Manager) deleteService(uid string) error { - var updatedInstances []serviceInstance + var updatedInstances []Instance found := false for x := range sm.serviceInstances { // Add the running services to the new array - if sm.serviceInstances[x].service.UID != uid { + if sm.serviceInstances[x].UID != uid { updatedInstances = append(updatedInstances, sm.serviceInstances[x]) } else { // Flip the found when we match found = true - if sm.serviceInstances[x].dhcp != nil { - sm.serviceInstances[x].dhcp.dhcpClient.Stop() - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcp.dhcpInterface) + if sm.serviceInstances[x].isDHCP == true { + macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + return fmt.Errorf("Error finding VIP Interface, for deleting DHCP Link : %v", err) } netlink.LinkDel(macvlan) } @@ -61,209 +59,112 @@ func (sm *Manager) deleteService(uid string) error { // Update the service array sm.serviceInstances = updatedInstances - log.Debugf("Removed [%s] from manager, [%d] services remain", uid, len(sm.serviceInstances)) + log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances)) return nil } -func (sm *Manager) syncServices(s *plndrServices) error { +func (sm *Manager) syncServices(service *v1.Service) error { log.Debugf("[STARTING] Service Sync") // Iterate through the synchronising services - for x := range s.Services { - foundInstance := false - for y := range sm.serviceInstances { - if s.Services[x].UID == sm.serviceInstances[y].service.UID { - // We have found this instance in the manager and we can update it - foundInstance = true - } - } + foundInstance := false + newServiceAddress := service.Spec.LoadBalancerIP + newServiceUID := string(service.UID) - // Generate new Virtual IP configuration - newVip := kubevip.Config{ - VIP: s.Services[x].Vip, - Interface: sm.config.Interface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + // We have found this instance in the manager, we can determine if it needs updating + foundInstance = true } - // This instance wasn't found, we need to add it to the manager - if foundInstance == false { - // Create new service - var newService serviceInstance - - // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP - if s.Services[x].Vip == "0.0.0.0" { - - parent, err := netlink.LinkByName(sm.config.Interface) - if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) - } - - // Create macvlan - - // Generate name from UID - interfaceName := fmt.Sprintf("vip-%s", s.Services[x].UID[0:8]) - - // 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) - - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} - - err = netlink.LinkAdd(mac) - if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) - } - - err = netlink.LinkSetUp(mac) - if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) - } - iface, err = net.InterfaceByName(interfaceName) - if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) - } - } else { - log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) - - } - - client := dhclient.Client{ - Iface: iface, - OnBound: func(lease *dhclient.Lease) { - - // Set VIP to Address from lease - newVip.VIP = lease.FixedAddress.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, s.Services[x].ServiceName, s.Services[x].UID) - - // // Generate Load Balancer configu - // newLB := kubevip.LoadBalancer{ - // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - // Port: s.Services[x].Port, - // Type: s.Services[x].Type, - // BindToVip: true, - // } - - // // Add Load Balancer Configuration - // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = newVip - newService.service = s.Services[x] - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) - //return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.service.ServiceName, newService.service.UID) - //return err - } - newService.cluster = *c - - // Begin watching this service - go sm.newWatcher(&newService) - - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) - - // Update the service - ns, err := returnNameSpace() - if err != nil { - log.Errorf("Error finding Namespace") - return - } - dhcpService, err := sm.clientSet.CoreV1().Services(ns).Get(context.TODO(), newService.service.ServiceName, metav1.GetOptions{}) - if err != nil { - log.Errorf("Error finding Service [%s] : %v", newService.service.ServiceName, err) - return - } - dhcpService.Spec.LoadBalancerIP = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(ns).Update(context.TODO(), dhcpService, metav1.UpdateOptions{}) - log.Infof("Updating service [%s], with load balancer address [%s]", updatedService.Name, updatedService.Spec.LoadBalancerIP) - if err != nil { - log.Errorf("Error updating Service [%s] : %v", newService.service.ServiceName, err) - return - } - - sm.upnpMap(newService.service) - - }, - } - - newService.dhcp = &dhcpService{ - dhcpClient: &client, - dhcpInterface: interfaceName, - } - - // Start the DHCP Client - newService.dhcp.dhcpClient.Start() + } - // Change the interface name to our new DHCP macvlan interface - newVip.Interface = interfaceName - log.Infof("DHCP Interface and Client is up and active [%s]", interfaceName) - return nil + // Generate new Virtual IP configuration + newVip := kubevip.Config{ + VIP: newServiceAddress, //TODO support more than one vip? + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, + } + // This instance wasn't found, we need to add it to the manager + if foundInstance == false { + // Create new service + var newService Instance + newService.UID = newServiceUID + newService.Vip = newServiceAddress + newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types + newService.Port = service.Spec.Ports[0].Port + newService.ServiceName = service.Name + + // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP + if newServiceAddress == "0.0.0.0" { + err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) + if err != nil { + return err } + return nil + } - log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) + log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceName, newService.UID) - // Generate Load Balancer config - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - Port: s.Services[x].Port, - Type: s.Services[x].Type, - BindToVip: true, - } + // Generate Load Balancer config + newLB := kubevip.LoadBalancer{ + Name: fmt.Sprintf("%s-load-balancer", newService.ServiceName), + Port: int(newService.Port), + Type: newService.Type, + BindToVip: true, + } - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + // Add Load Balancer Configuration + newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - // Create Add configuration to the new service - newService.vipConfig = newVip - newService.service = s.Services[x] + // Create Add configuration to the new service + newService.vipConfig = newVip - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) + return err + } - sm.upnpMap(s.Services[x]) + sm.upnpMap(newService) - newService.cluster = *c + newService.cluster = *c - // Begin watching this service - go sm.newWatcher(&newService) + // Begin watching this service + // TODO - we may need this + // go sm.serviceWatcher(&newService, sm.config.Namespace) - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) + // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it + service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) } + sm.serviceInstances = append(sm.serviceInstances, newService) } + log.Debugf("[COMPLETE] Service Sync") return nil } -func (sm *Manager) upnpMap(s service) { +func (sm *Manager) upnpMap(s Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() if sm.upnp != nil { log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) - if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { log.Infof("Service should be accessible externally on port [%d]", s.Port) } else { sm.upnp.Reclaim() diff --git a/pkg/service/services.txt b/pkg/service/services.txt new file mode 100644 index 00000000..7d9ce524 --- /dev/null +++ b/pkg/service/services.txt @@ -0,0 +1,159 @@ +package service + +import ( + "fmt" + "strings" + + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" +) + +func (sm *Manager) stopService(uid string) error { + found := false + for x := range sm.serviceInstances { + if sm.serviceInstances[x].service.UID == uid { + found = true + sm.serviceInstances[x].cluster.Stop() + } + } + if found == false { + return fmt.Errorf("Unable to find/stop service [%s]", uid) + } + return nil +} + +func (sm *Manager) deleteService(uid string) error { + var updatedInstances []serviceInstance + found := false + for x := range sm.serviceInstances { + // Add the running services to the new array + if sm.serviceInstances[x].service.UID != uid { + updatedInstances = append(updatedInstances, sm.serviceInstances[x]) + } else { + // Flip the found when we match + found = true + if sm.serviceInstances[x].dhcp != nil { + sm.serviceInstances[x].dhcp.dhcpClient.Stop() + macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcp.dhcpInterface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + netlink.LinkDel(macvlan) + } + if sm.serviceInstances[x].vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) + err := sm.bgpServer.DelHost(cidrVip) + return err + } + } + } + // If we've been through all services and not found the correct one then error + if found == false { + return fmt.Errorf("Unable to find/stop service [%s]", uid) + } + + // Update the service array + sm.serviceInstances = updatedInstances + + log.Debugf("Removed [%s] from manager, [%d] services remain", uid, len(sm.serviceInstances)) + + return nil +} + +func (sm *Manager) syncServices(s *plndrServices) error { + log.Debugf("[STARTING] Service Sync") + // Iterate through the synchronising services + for x := range s.Services { + foundInstance := false + for y := range sm.serviceInstances { + if s.Services[x].UID == sm.serviceInstances[y].service.UID { + // We have found this instance in the manager and we can update it + foundInstance = true + } + } + + // Generate new Virtual IP configuration + newVip := kubevip.Config{ + VIP: s.Services[x].Vip, + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, + } + + // This instance wasn't found, we need to add it to the manager + if foundInstance == false { + // Create new service + var newService serviceInstance + + // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP + if s.Services[x].Vip == "0.0.0.0" { + + err := sm.createDHCPService(s.Services[x].UID, &newVip, newService, service) + if err != nil { + return err + } + + } + log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) + + // Generate Load Balancer config + newLB := kubevip.LoadBalancer{ + Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + Port: s.Services[x].Port, + Type: s.Services[x].Type, + BindToVip: true, + } + + // Add Load Balancer Configuration + newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + + // Create Add configuration to the new service + newService.vipConfig = newVip + newService.service = s.Services[x] + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) + return err + } + + sm.upnpMap(s.Services[x]) + + newService.cluster = *c + + // Begin watching this service + go sm.newWatcher(&newService) + + // Add new service to manager configuration + sm.serviceInstances = append(sm.serviceInstances, newService) + } + } + log.Debugf("[COMPLETE] Service Sync") + + return nil +} + +func (sm *Manager) upnpMap(s service) { + // If upnp is enabled then update the gateway/router with the address + // TODO - work out if we need to mapping.Reclaim() + if sm.upnp != nil { + + log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) + if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + log.Infof("Service should be accessible externally on port [%d]", s.Port) + } else { + sm.upnp.Reclaim() + log.Errorf("Unable to map port to gateway [%s]", err.Error()) + } + } +} diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go new file mode 100644 index 00000000..13c020e7 --- /dev/null +++ b/pkg/service/services_dhcp.go @@ -0,0 +1,211 @@ +package service + +import ( + "context" + "fmt" + "net" + + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/client4" + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/dhcpv6/client6" + "github.com/insomniacslk/dhcp/netboot" + "github.com/vishvananda/netlink" +) + +func dhclient6(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { + if attempts < 1 { + attempts = 1 + } + llAddr, err := dhcpv6.GetLinkLocalAddr(ifname) + if err != nil { + return nil, err + } + laddr := net.UDPAddr{ + IP: llAddr, + Port: dhcpv6.DefaultClientPort, + Zone: ifname, + } + raddr := net.UDPAddr{ + IP: dhcpv6.AllDHCPRelayAgentsAndServers, + Port: dhcpv6.DefaultServerPort, + Zone: ifname, + } + c := client6.NewClient() + c.LocalAddr = &laddr + c.RemoteAddr = &raddr + var conv []dhcpv6.DHCPv6 + for attempt := 0; attempt < attempts; attempt++ { + log.Printf("Attempt %d of %d", attempt+1, attempts) + conv, err = c.Exchange(ifname, dhcpv6.WithNetboot) + if err != nil && attempt < attempts { + log.Printf("Error: %v", err) + continue + } + break + } + if verbose { + for _, m := range conv { + log.Print(m.Summary()) + } + } + if err != nil { + return nil, err + } + // extract the network configuration + netconf, err := netboot.ConversationToNetconf(conv) + return netconf, err +} + +func dhclient4(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { + if attempts < 1 { + attempts = 1 + } + client := client4.NewClient() + var ( + conv []*dhcpv4.DHCPv4 + err error + ) + for attempt := 0; attempt < attempts; attempt++ { + log.Printf("Attempt %d of %d", attempt+1, attempts) + conv, err = client.Exchange(ifname) + if err != nil && attempt < attempts { + log.Printf("Error: %v", err) + continue + } + break + } + if verbose { + for _, m := range conv { + log.Print(m.Summary()) + } + } + if err != nil { + return nil, err + } + // extract the network configuration + netconf, err := netboot.ConversationToNetconfv4(conv) + return netconf, err +} + +func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { + parent, err := netlink.LinkByName(sm.config.Interface) + if err != nil { + return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) + } + + // Create macvlan + + // Generate name from UID + interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) + + // Check if the interface doesn't exist first + _, err = net.InterfaceByName(interfaceName) + if err != nil { + log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) + + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + + err = netlink.LinkAdd(mac) + if err != nil { + return fmt.Errorf("Could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) + } + _, err = net.InterfaceByName(interfaceName) + if err != nil { + return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + } + var bootconf *netboot.BootConf + + bootconf, err = dhclient4(interfaceName, 5, false) + if err != nil { + return err + } + err = netboot.ConfigureInterface(interfaceName, &bootconf.NetConf) + if err != nil { + return err + } + + newVip.VIP = bootconf.Addresses[0].IPNet.IP.String() + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + + // // Generate Load Balancer config + // newLB := kubevip.LoadBalancer{ + // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), + // Port: s.Services[x].Port, + // Type: s.Services[x].Type, + // BindToVip: true, + // } + + // // Add Load Balancer Configuration + // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + + // Create Add configuration to the new service + newService.vipConfig = *newVip + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return err + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return err + } + newService.cluster = *c + + // Set that DHCP is enabled + newService.isDHCP = true + // Set the name of the interface so that it can be removed on Service deletion + newService.dhcpInterface = interfaceName + + // Add new service to manager configuration + service.Spec.LoadBalancerIP = newVip.VIP + log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) + sm.serviceInstances = append(sm.serviceInstances, *newService) + + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + return retryErr + } + + sm.upnpMap(*newService) + return nil +} diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index a3e7f67a..db0aca05 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -15,65 +15,105 @@ import ( watchtools "k8s.io/client-go/tools/watch" ) -// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +func rebuildEndpoints(eps v1.Endpoints) []kubevip.BackEnd { + var addresses []string + var ports []int32 -func (sm *Manager) newWatcher(s *serviceInstance) error { - // Build a options structure to defined what we're looking for - listOptions := metav1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", s.service.ServiceName), + for x := range eps.Subsets { + // Loop over addresses + for y := range eps.Subsets[x].Addresses { + addresses = append(addresses, eps.Subsets[x].Addresses[y].IP) + } + for y := range eps.Subsets[x].Ports { + ports = append(ports, eps.Subsets[x].Ports[y].Port) + } } - ns, err := returnNameSpace() - if err != nil { - return err + var newBackend []kubevip.BackEnd + + // Build endpoints + for x := range addresses { + for y := range ports { + // Print out Backends if debug logging is enabled + if log.GetLevel() == log.DebugLevel { + fmt.Printf("-> Address: %s:%d \n", addresses[x], ports[y]) + } + newBackend = append(newBackend, kubevip.BackEnd{ + Address: addresses[x], + Port: int(ports[y]), + }) + } } + return newBackend +} + +// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +func (sm *Manager) servicesWatcher(ctx context.Context) error { // Watch function + // Use a restartable watcher, as this should help in the event of etcd or timeout issues rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), listOptions) + return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) }, }) if err != nil { - return fmt.Errorf("error creating watcher: %s", err.Error()) + return fmt.Errorf("error creating services watcher: %s", err.Error()) } - + go func() { + <-sm.signalChan + // Cancel the context + rw.Stop() + }() ch := rw.ResultChan() - defer rw.Stop() - log.Infof("Beginning watching Kubernetes Endpoints for service [%s]", s.service.ServiceName) + //defer rw.Stop() + log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { + //sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added, watch.Modified: // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - // ep, ok := event.Object.(*v1.Endpoints) - // if !ok { - // return fmt.Errorf("Unable to parse Endpoints from watcher") - // } - // s.vipConfig.LoadBalancers[0].Backends = rebuildEndpoints(*ep) - - // log.Debugf("Load-Balancer updated with [%d] backends", len(s.vipConfig.LoadBalancers[0].Backends)) + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + if svc.Spec.LoadBalancerIP == "" { + log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) + } else { + log.Infof("Service [%s] has been addded/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + err = sm.syncServices(svc) + if err != nil { + log.Error(err) + } + } case watch.Deleted: - log.Debugf("Endpoints for service [%s] have been Deleted", s.service.ServiceName) - log.Infof("Service [%s] has been deleted, stopping VIP", s.service.ServiceName) - // Stopping the service from running - sm.stopService(s.service.UID) - // Remove this service from the list of services we manage - sm.deleteService(s.service.UID) - return nil + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + err = sm.stopService(string(svc.UID)) + if err != nil { + log.Error(err) + } + err = sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) + } + log.Infof("Service [%s] has been deleted", svc.Name) + case watch.Bookmark: // Un-used case watch.Error: - log.Infoln("err") + log.Error("Error attempting to watch Kubernetes services") // This round trip allows us to handle unstructured status errObject := apierrors.FromObject(event.Object) statusErr, ok := errObject.(*apierrors.StatusError) if !ok { - log.Fatalf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - // Retry unknown errors - //return false, 0 + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + } status := statusErr.ErrStatus @@ -81,36 +121,6 @@ func (sm *Manager) newWatcher(s *serviceInstance) error { default: } } + log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } - -func rebuildEndpoints(eps v1.Endpoints) []kubevip.BackEnd { - var addresses []string - var ports []int32 - - for x := range eps.Subsets { - // Loop over addresses - for y := range eps.Subsets[x].Addresses { - addresses = append(addresses, eps.Subsets[x].Addresses[y].IP) - } - for y := range eps.Subsets[x].Ports { - ports = append(ports, eps.Subsets[x].Ports[y].Port) - } - } - var newBackend []kubevip.BackEnd - - // Build endpoints - for x := range addresses { - for y := range ports { - // Print out Backends if debug logging is enabled - if log.GetLevel() == log.DebugLevel { - fmt.Printf("-> Address: %s:%d \n", addresses[x], ports[y]) - } - newBackend = append(newBackend, kubevip.BackEnd{ - Address: addresses[x], - Port: int(ports[y]), - }) - } - } - return newBackend -} diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 788f67f7..373c0b4d 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -5,7 +5,8 @@ import ( "net" "time" - dhclient "github.com/digineo/go-dhclient" + "github.com/d2g/dhcp4" + "github.com/digineo/go-dhclient" "github.com/google/gopacket/layers" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -42,7 +43,8 @@ func (ddns *ddnsManager) Start() (string, error) { // channel to wait for IP ipCh := make(chan string) - + //var options dhcp4.Option + AcquireLease(ddns.network.DDNSHostName(), interfaceName, dhcp4.Options{}) client := dhclient.Client{ // send host name, not current os.Hostname, but configured name from user Hostname: ddns.network.DDNSHostName(), @@ -51,6 +53,7 @@ func (ddns *ddnsManager) Start() (string, error) { ipCh <- lease.FixedAddress.String() }, } + //options[DHCPOptHostname] = []byte(client.Hostname) // add default request param for _, param := range dhclient.DefaultParamsRequestList { diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go new file mode 100644 index 00000000..1947b191 --- /dev/null +++ b/pkg/vip/dhcp.go @@ -0,0 +1,535 @@ +package vip + +import ( + "encoding/binary" + "fmt" + "log" + "math/rand" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/containernetworking/cni/pkg/types" + "github.com/d2g/dhcp4" + "github.com/d2g/dhcp4client" + "github.com/pkg/errors" + "github.com/vishvananda/netlink" +) + +// DHCPOpt represents a DHCP option or parameter from RFC-2132 +type DHCPOpt byte + +// Constants for the DHCPOpt options. +const ( + DHCPOptPad DHCPOpt = 0 + DHCPOptSubnetMask DHCPOpt = 1 // 4, net.IP + DHCPOptTimeOffset DHCPOpt = 2 // 4, int32 (signed seconds from UTC) + DHCPOptRouter DHCPOpt = 3 // n*4, [n]net.IP + DHCPOptTimeServer DHCPOpt = 4 // n*4, [n]net.IP + DHCPOptNameServer DHCPOpt = 5 // n*4, [n]net.IP + DHCPOptDNS DHCPOpt = 6 // n*4, [n]net.IP + DHCPOptLogServer DHCPOpt = 7 // n*4, [n]net.IP + DHCPOptCookieServer DHCPOpt = 8 // n*4, [n]net.IP + DHCPOptLPRServer DHCPOpt = 9 // n*4, [n]net.IP + DHCPOptImpressServer DHCPOpt = 10 // n*4, [n]net.IP + DHCPOptResLocServer DHCPOpt = 11 // n*4, [n]net.IP + DHCPOptHostname DHCPOpt = 12 // n, string + DHCPOptBootfileSize DHCPOpt = 13 // 2, uint16 + DHCPOptMeritDumpFile DHCPOpt = 14 // >1, string + DHCPOptDomainName DHCPOpt = 15 // n, string + DHCPOptSwapServer DHCPOpt = 16 // n*4, [n]net.IP + DHCPOptRootPath DHCPOpt = 17 // n, string + DHCPOptExtensionsPath DHCPOpt = 18 // n, string + DHCPOptIPForwarding DHCPOpt = 19 // 1, bool + DHCPOptSourceRouting DHCPOpt = 20 // 1, bool + DHCPOptPolicyFilter DHCPOpt = 21 // 8*n, [n]{net.IP/net.IP} + DHCPOptDatagramMTU DHCPOpt = 22 // 2, uint16 + DHCPOptDefaultTTL DHCPOpt = 23 // 1, byte + DHCPOptPathMTUAgingTimeout DHCPOpt = 24 // 4, uint32 + DHCPOptPathPlateuTableOption DHCPOpt = 25 // 2*n, []uint16 + DHCPOptInterfaceMTU DHCPOpt = 26 // 2, uint16 + DHCPOptAllSubsLocal DHCPOpt = 27 // 1, bool + DHCPOptBroadcastAddr DHCPOpt = 28 // 4, net.IP + DHCPOptMaskDiscovery DHCPOpt = 29 // 1, bool + DHCPOptMaskSupplier DHCPOpt = 30 // 1, bool + DHCPOptRouterDiscovery DHCPOpt = 31 // 1, bool + DHCPOptSolicitAddr DHCPOpt = 32 // 4, net.IP + DHCPOptStaticRoute DHCPOpt = 33 // n*8, [n]{net.IP/net.IP} -- note the 2nd is router not mask + DHCPOptARPTrailers DHCPOpt = 34 // 1, bool + DHCPOptARPTimeout DHCPOpt = 35 // 4, uint32 + DHCPOptEthernetEncap DHCPOpt = 36 // 1, bool + DHCPOptTCPTTL DHCPOpt = 37 // 1, byte + DHCPOptTCPKeepAliveInt DHCPOpt = 38 // 4, uint32 + DHCPOptTCPKeepAliveGarbage DHCPOpt = 39 // 1, bool + DHCPOptNISDomain DHCPOpt = 40 // n, string + DHCPOptNISServers DHCPOpt = 41 // 4*n, [n]net.IP + DHCPOptNTPServers DHCPOpt = 42 // 4*n, [n]net.IP + DHCPOptVendorOption DHCPOpt = 43 // n, [n]byte // may be encapsulated. + DHCPOptNetBIOSTCPNS DHCPOpt = 44 // 4*n, [n]net.IP + DHCPOptNetBIOSTCPDDS DHCPOpt = 45 // 4*n, [n]net.IP + DHCPOptNETBIOSTCPNodeType DHCPOpt = 46 // 1, magic byte + DHCPOptNetBIOSTCPScope DHCPOpt = 47 // n, string + DHCPOptXFontServer DHCPOpt = 48 // n, string + DHCPOptXDisplayManager DHCPOpt = 49 // n, string + DHCPOptRequestIP DHCPOpt = 50 // 4, net.IP + DHCPOptLeaseTime DHCPOpt = 51 // 4, uint32 + DHCPOptExtOptions DHCPOpt = 52 // 1, 1/2/3 + DHCPOptMessageType DHCPOpt = 53 // 1, 1-7 + DHCPOptServerID DHCPOpt = 54 // 4, net.IP + DHCPOptParamsRequest DHCPOpt = 55 // n, []byte + DHCPOptMessage DHCPOpt = 56 // n, 3 + DHCPOptMaxMessageSize DHCPOpt = 57 // 2, uint16 + DHCPOptT1 DHCPOpt = 58 // 4, uint32 + DHCPOptT2 DHCPOpt = 59 // 4, uint32 + DHCPOptClassID DHCPOpt = 60 // n, []byte + DHCPOptClientID DHCPOpt = 61 // n >= 2, []byte + DHCPOptDomainSearch DHCPOpt = 119 // n, string + DHCPOptSIPServers DHCPOpt = 120 // n, url + DHCPOptClasslessStaticRoute DHCPOpt = 121 // + DHCPOptEnd DHCPOpt = 255 +) + +// RFC 2131 suggests using exponential backoff, starting with 4sec +// and randomized to +/- 1sec +const resendDelay0 = 4 * time.Second +const resendDelayMax = 32 * time.Second +const resendCount = 3 + +var errNoMoreTries = errors.New("no more tries") + +const ( + leaseStateBound = iota + leaseStateRenewing + leaseStateRebinding +) + +// This implementation uses 1 OS thread per lease. This is because +// all the network operations have to be done in network namespace +// of the interface. This can be improved by switching to the proper +// namespace for network ops and using fewer threads. However, this +// needs to be done carefully as dhcp4client ops are blocking. + +// DHCPLease is the actual lease from a DHCP server +type DHCPLease struct { + clientID string + ack *dhcp4.Packet + opts dhcp4.Options + link netlink.Link + renewalTime time.Time + rebindingTime time.Time + expireTime time.Time + stopping uint32 + stop chan struct{} + wg sync.WaitGroup +} + +// AcquireLease gets an DHCP lease and then maintains it in the background +// by periodically renewing it. The acquired lease can be released by +// calling DHCPLease.Stop() +func AcquireLease(clientID, ifName string, opts dhcp4.Options) (*DHCPLease, error) { + errCh := make(chan error, 1) + l := &DHCPLease{ + clientID: clientID, + stop: make(chan struct{}), + } + + log.Printf("%v: acquiring lease", clientID) + + l.wg.Add(1) + go func() error { + defer l.wg.Done() + + link, err := netlink.LinkByName(ifName) + if err != nil { + errCh <- fmt.Errorf("error looking up %q: %v", ifName, err) + } + + l.link = link + + if err = l.acquire(); err != nil { + errCh <- err + } + + log.Printf("%v: lease acquired, expiration is %v", l.clientID, l.expireTime) + + errCh <- nil + + l.maintain() + return nil + + }() + + if err := <-errCh; err != nil { + return nil, err + } + + return l, nil +} + +// Stop terminates the background task that maintains the lease +// and issues a DHCP Release +func (l *DHCPLease) Stop() { + if atomic.CompareAndSwapUint32(&l.stopping, 0, 1) { + close(l.stop) + } + l.wg.Wait() +} + +func (l *DHCPLease) acquire() error { + c, err := newDHCPClient(l.link) + if err != nil { + return err + } + defer c.Close() + + if (l.link.Attrs().Flags & net.FlagUp) != net.FlagUp { + log.Printf("Link %q down. Attempting to set up", l.link.Attrs().Name) + if err = netlink.LinkSetUp(l.link); err != nil { + return err + } + } + + pkt, err := backoffRetry(func() (*dhcp4.Packet, error) { + ok, ack, err := c.Request() + switch { + case err != nil: + return nil, err + case !ok: + return nil, fmt.Errorf("DHCP server NACK'd own offer") + default: + return &ack, nil + } + }) + if err != nil { + return err + } + + return l.commit(pkt) +} + +func (l *DHCPLease) commit(ack *dhcp4.Packet) error { + opts := ack.ParseOptions() + + leaseTime, err := parseLeaseTime(opts) + if err != nil { + return err + } + + rebindingTime, err := parseRebindingTime(opts) + if err != nil || rebindingTime > leaseTime { + // Per RFC 2131 Section 4.4.5, it should default to 85% of lease time + rebindingTime = leaseTime * 85 / 100 + } + + renewalTime, err := parseRenewalTime(opts) + if err != nil || renewalTime > rebindingTime { + // Per RFC 2131 Section 4.4.5, it should default to 50% of lease time + renewalTime = leaseTime / 2 + } + + now := time.Now() + l.expireTime = now.Add(leaseTime) + l.renewalTime = now.Add(renewalTime) + l.rebindingTime = now.Add(rebindingTime) + l.ack = ack + l.opts = opts + + return nil +} + +func (l *DHCPLease) maintain() { + state := leaseStateBound + + for { + var sleepDur time.Duration + + switch state { + case leaseStateBound: + sleepDur = l.renewalTime.Sub(time.Now()) + if sleepDur <= 0 { + log.Printf("%v: renewing lease", l.clientID) + state = leaseStateRenewing + continue + } + + case leaseStateRenewing: + if err := l.renew(); err != nil { + log.Printf("%v: %v", l.clientID, err) + + if time.Now().After(l.rebindingTime) { + log.Printf("%v: renawal time expired, rebinding", l.clientID) + state = leaseStateRebinding + } + } else { + log.Printf("%v: lease renewed, expiration is %v", l.clientID, l.expireTime) + state = leaseStateBound + } + + case leaseStateRebinding: + if err := l.acquire(); err != nil { + log.Printf("%v: %v", l.clientID, err) + + if time.Now().After(l.expireTime) { + log.Printf("%v: lease expired, bringing interface DOWN", l.clientID) + l.downIface() + return + } + } else { + log.Printf("%v: lease rebound, expiration is %v", l.clientID, l.expireTime) + state = leaseStateBound + } + } + + select { + case <-time.After(sleepDur): + + case <-l.stop: + if err := l.release(); err != nil { + log.Printf("%v: failed to release DHCP lease: %v", l.clientID, err) + } + return + } + } +} + +func (l *DHCPLease) downIface() { + if err := netlink.LinkSetDown(l.link); err != nil { + log.Printf("%v: failed to bring %v interface DOWN: %v", l.clientID, l.link.Attrs().Name, err) + } +} + +func (l *DHCPLease) renew() error { + c, err := newDHCPClient(l.link) + if err != nil { + return err + } + defer c.Close() + + pkt, err := backoffRetry(func() (*dhcp4.Packet, error) { + ok, ack, err := c.Renew(*l.ack) + switch { + case err != nil: + return nil, err + case !ok: + return nil, fmt.Errorf("DHCP server did not renew lease") + default: + return &ack, nil + } + }) + if err != nil { + return err + } + + l.commit(pkt) + return nil +} + +func (l *DHCPLease) release() error { + log.Printf("%v: releasing lease", l.clientID) + + c, err := newDHCPClient(l.link) + if err != nil { + return err + } + defer c.Close() + + if err = c.Release(*l.ack); err != nil { + return fmt.Errorf("failed to send DHCPRELEASE") + } + + return nil +} + +func (l *DHCPLease) IPNet() (*net.IPNet, error) { + mask := parseSubnetMask(l.opts) + if mask == nil { + return nil, fmt.Errorf("DHCP option Subnet Mask not found in DHCPACK") + } + + return &net.IPNet{ + IP: l.ack.YIAddr(), + Mask: mask, + }, nil +} + +func (l *DHCPLease) Gateway() net.IP { + return parseRouter(l.opts) +} + +func (l *DHCPLease) Routes() []*types.Route { + routes := []*types.Route{} + + // RFC 3442 states that if Classless Static Routes (option 121) + // exist, we ignore Static Routes (option 33) and the Router/Gateway. + opt121_routes := parseCIDRRoutes(l.opts) + if len(opt121_routes) > 0 { + return append(routes, opt121_routes...) + } + + // Append Static Routes + routes = append(routes, parseRoutes(l.opts)...) + + // The CNI spec says even if there is a gateway specified, we must + // add a default route in the routes section. + if gw := l.Gateway(); gw != nil { + _, defaultRoute, _ := net.ParseCIDR("0.0.0.0/0") + routes = append(routes, &types.Route{Dst: *defaultRoute, GW: gw}) + } + + return routes +} + +// jitter returns a random value within [-span, span) range +func jitter(span time.Duration) time.Duration { + return time.Duration(float64(span) * (2.0*rand.Float64() - 1.0)) +} + +func backoffRetry(f func() (*dhcp4.Packet, error)) (*dhcp4.Packet, error) { + var baseDelay time.Duration = resendDelay0 + + for i := 0; i < resendCount; i++ { + pkt, err := f() + if err == nil { + return pkt, nil + } + + log.Print(err) + + time.Sleep(baseDelay + jitter(time.Second)) + + if baseDelay < resendDelayMax { + baseDelay *= 2 + } + } + + return nil, errNoMoreTries +} + +func newDHCPClient(link netlink.Link) (*dhcp4client.Client, error) { + pktsock, err := dhcp4client.NewPacketSock(link.Attrs().Index) + if err != nil { + return nil, err + } + + return dhcp4client.New( + dhcp4client.HardwareAddr(link.Attrs().HardwareAddr), + dhcp4client.Timeout(5*time.Second), + dhcp4client.Broadcast(false), + dhcp4client.Connection(pktsock), + ) +} + +func parseRouter(opts dhcp4.Options) net.IP { + if opts, ok := opts[dhcp4.OptionRouter]; ok { + if len(opts) == 4 { + return net.IP(opts) + } + } + return nil +} + +func classfulSubnet(sn net.IP) net.IPNet { + return net.IPNet{ + IP: sn, + Mask: sn.DefaultMask(), + } +} + +func parseRoutes(opts dhcp4.Options) []*types.Route { + // StaticRoutes format: pairs of: + // Dest = 4 bytes; Classful IP subnet + // Router = 4 bytes; IP address of router + + routes := []*types.Route{} + if opt, ok := opts[dhcp4.OptionStaticRoute]; ok { + for len(opt) >= 8 { + sn := opt[0:4] + r := opt[4:8] + rt := &types.Route{ + Dst: classfulSubnet(sn), + GW: r, + } + routes = append(routes, rt) + opt = opt[8:] + } + } + + return routes +} + +func parseCIDRRoutes(opts dhcp4.Options) []*types.Route { + // See RFC4332 for format (http://tools.ietf.org/html/rfc3442) + + routes := []*types.Route{} + if opt, ok := opts[dhcp4.OptionClasslessRouteFormat]; ok { + for len(opt) >= 5 { + width := int(opt[0]) + if width > 32 { + // error: can't have more than /32 + return nil + } + // network bits are compacted to avoid zeros + octets := 0 + if width > 0 { + octets = (width-1)/8 + 1 + } + + if len(opt) < 1+octets+4 { + // error: too short + return nil + } + + sn := make([]byte, 4) + copy(sn, opt[1:octets+1]) + + gw := net.IP(opt[octets+1 : octets+5]) + + rt := &types.Route{ + Dst: net.IPNet{ + IP: net.IP(sn), + Mask: net.CIDRMask(width, 32), + }, + GW: gw, + } + routes = append(routes, rt) + + opt = opt[octets+5:] + } + } + return routes +} + +func parseSubnetMask(opts dhcp4.Options) net.IPMask { + mask, ok := opts[dhcp4.OptionSubnetMask] + if !ok { + return nil + } + + return net.IPMask(mask) +} + +func parseDuration(opts dhcp4.Options, code dhcp4.OptionCode, optName string) (time.Duration, error) { + val, ok := opts[code] + if !ok { + return 0, fmt.Errorf("option %v not found", optName) + } + if len(val) != 4 { + return 0, fmt.Errorf("option %v is not 4 bytes", optName) + } + + secs := binary.BigEndian.Uint32(val) + return time.Duration(secs) * time.Second, nil +} + +func parseLeaseTime(opts dhcp4.Options) (time.Duration, error) { + return parseDuration(opts, dhcp4.OptionIPAddressLeaseTime, "LeaseTime") +} + +func parseRenewalTime(opts dhcp4.Options) (time.Duration, error) { + return parseDuration(opts, dhcp4.OptionRenewalTimeValue, "RenewalTime") +} + +func parseRebindingTime(opts dhcp4.Options) (time.Duration, error) { + return parseDuration(opts, dhcp4.OptionRebindingTimeValue, "RebindingTime") +} From f69d0b77f695f9db18fb3c9611ddb3231eb7d531 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 13 May 2021 14:02:38 +0100 Subject: [PATCH 102/542] Complete re-write of dhcp --- go.mod | 12 +- go.sum | 79 +---- pkg/cluster/singleNode.go | 3 +- pkg/manager/manager.go | 2 +- pkg/manager/services.go | 9 +- pkg/manager/services_dhcp.go | 216 +++++-------- pkg/manager/watcher.go | 6 +- pkg/service/manager.go | 2 + pkg/service/services.txt | 159 ---------- pkg/service/services_dhcp.go | 220 +++++--------- pkg/vip/ddns.go | 29 +- pkg/vip/dhcp.go | 569 +++++------------------------------ pkg/vip/dhcp_internals.go | 206 +++++++++++++ 13 files changed, 458 insertions(+), 1054 deletions(-) delete mode 100644 pkg/service/services.txt create mode 100644 pkg/vip/dhcp_internals.go diff --git a/go.mod b/go.mod index cba9314b..49e3cea7 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,8 @@ go 1.14 require ( github.com/armon/go-metrics v0.3.8 // indirect - github.com/containernetworking/cni v0.8.1 - github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c - github.com/d2g/dhcp4client v1.0.0 github.com/davecgh/go-spew v1.1.1 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/digineo/go-dhclient v1.0.2 github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 @@ -23,14 +19,13 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/raft v1.3.1 github.com/imdario/mergo v0.3.12 // indirect - github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9 - github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7 // indirect + github.com/jpillora/backoff v1.0.0 github.com/json-iterator/go v1.1.11 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/magiconair/properties v1.8.5 // indirect github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 - github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect + github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.7.0 @@ -40,13 +35,14 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.10.0 github.com/prometheus/common v0.23.0 // indirect + github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 // indirect - github.com/vishvananda/netlink v1.1.0 + github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 diff --git a/go.sum b/go.sum index ab66b77c..4e5eb98e 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU= -github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -102,8 +100,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= -github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -117,10 +113,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c h1:Xo2rK1pzOm0jO6abTPIQwbAmqBIOj132otexc1mmzFc= -github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= -github.com/d2g/dhcp4client v1.0.0 h1:suYBsYZIkSlUMEz4TAYCczKf62IA2UWC+O8+KtdOhCo= -github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -129,8 +121,6 @@ github.com/dgryski/go-farm v0.0.0-20171119141306-ac7624ea8da3/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digineo/go-dhclient v1.0.2 h1:69ZRY+AZnAx+BjO7UWTYWCGgnxW6oBOGwJXgciuLSEU= -github.com/digineo/go-dhclient v1.0.2/go.mod h1:DPvyqGEW8irJvp2lrnGfQWpjj6VidXX9STLBTfNing4= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= @@ -157,15 +147,12 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= @@ -256,7 +243,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -336,7 +322,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -344,25 +329,12 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9 h1:T+Czi1NGxrbx8enhcdUFPVYTpGd6DPDxrKptDXRgD8I= -github.com/insomniacslk/dhcp v0.0.0-20210428091707-95b2ff6905c9/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI= github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= -github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= -github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= -github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= -github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= -github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7 h1:0pS4NUf9WPvydLWHx2VHafjEyfN8vQrAxl/n3Kt2K9c= -github.com/jsimonetti/rtnetlink v0.0.0-20210409061457-9561dc9288a7/go.mod h1:+fPVEwpdpYDhPa086y6yIAwUno3cBJZw15Fds43LDRA= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -391,8 +363,6 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -422,26 +392,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= -github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= -github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= -github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= -github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= -github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= -github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= -github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= -github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= -github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= -github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191004140158-e1402808046b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -568,6 +520,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5 h1:/kzTBQ20DbbhSNaBXiFEk2gPrGhY26kajwC1ro/Vlh8= +github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5/go.mod h1:FwstIpm6vX98QgtR8KEwZcVjiRn2WP76LjXAHj84fK0= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -621,7 +575,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -635,14 +588,12 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= -github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v0.0.0-20170802012344-a95659537721/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 h1:IlMBmSoCDZ9UY3OehFgvKSIgMNnU1vbAD4Fl+y2Rbis= +github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066/go.mod h1:FSQhuTO7eHT34mPzX+B04SUAjiqLxtXs1et0S6l9k4k= github.com/vishvananda/netns v0.0.0-20170707011535-86bef332bfc3/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= @@ -742,8 +693,6 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -759,12 +708,7 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -798,16 +742,12 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -822,6 +762,7 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -841,17 +782,9 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 2528a76a..69307fbf 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -120,7 +120,6 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) - err := cluster.Network.DeleteIP() if err != nil { log.Warnf("Attempted to clean existing VIP => %v", err) @@ -200,7 +199,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser select { case <-cluster.stop: log.Info("[LOADBALANCER] Stopping load balancers") - log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIPCIDR) + log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) err = cluster.Network.DeleteIP() if err != nil { log.Warnf("%v", err) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 00468ab4..fe15b1f0 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -60,7 +60,7 @@ type Instance struct { // Service uses DHCP isDHCP bool dhcpInterface string - lease *vip.DHCPLease + dhcpClient *vip.DHCPClient // Kubernetes service mapping Vip string diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 7a538543..37973719 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "sync" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" @@ -38,7 +39,7 @@ func (sm *Manager) deleteService(uid string) error { // Flip the found when we match found = true if sm.serviceInstances[x].isDHCP == true { - sm.serviceInstances[x].lease.Stop() + sm.serviceInstances[x].dhcpClient.Stop() macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) if err != nil { return fmt.Errorf("Error finding VIP Interface, for deleting DHCP Link : %v", err) @@ -66,7 +67,10 @@ func (sm *Manager) deleteService(uid string) error { return nil } -func (sm *Manager) syncServices(service *v1.Service) error { +func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { + + defer wg.Done() + log.Debugf("[STARTING] Service Sync") // Iterate through the synchronising services foundInstance := false @@ -103,6 +107,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP if newServiceAddress == "0.0.0.0" { + err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) if err != nil { return err diff --git a/pkg/manager/services_dhcp.go b/pkg/manager/services_dhcp.go index 0144b78f..2461cc5b 100644 --- a/pkg/manager/services_dhcp.go +++ b/pkg/manager/services_dhcp.go @@ -13,102 +13,20 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/insomniacslk/dhcp/dhcpv4" - "github.com/insomniacslk/dhcp/dhcpv4/client4" - "github.com/insomniacslk/dhcp/dhcpv6" - "github.com/insomniacslk/dhcp/dhcpv6/client6" - "github.com/insomniacslk/dhcp/netboot" "github.com/vishvananda/netlink" ) -func dhclient6(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { - if attempts < 1 { - attempts = 1 - } - llAddr, err := dhcpv6.GetLinkLocalAddr(ifname) - if err != nil { - return nil, err - } - laddr := net.UDPAddr{ - IP: llAddr, - Port: dhcpv6.DefaultClientPort, - Zone: ifname, - } - raddr := net.UDPAddr{ - IP: dhcpv6.AllDHCPRelayAgentsAndServers, - Port: dhcpv6.DefaultServerPort, - Zone: ifname, - } - c := client6.NewClient() - c.LocalAddr = &laddr - c.RemoteAddr = &raddr - var conv []dhcpv6.DHCPv6 - for attempt := 0; attempt < attempts; attempt++ { - log.Printf("Attempt %d of %d", attempt+1, attempts) - conv, err = c.Exchange(ifname, dhcpv6.WithNetboot) - if err != nil && attempt < attempts { - log.Printf("Error: %v", err) - continue - } - break - } - if verbose { - for _, m := range conv { - log.Print(m.Summary()) - } - } - if err != nil { - return nil, err - } - // extract the network configuration - netconf, err := netboot.ConversationToNetconf(conv) - return netconf, err -} - -func dhclient4(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { - if attempts < 1 { - attempts = 1 - } - client := client4.NewClient() - var ( - conv []*dhcpv4.DHCPv4 - err error - ) - for attempt := 0; attempt < attempts; attempt++ { - log.Printf("Attempt %d of %d", attempt+1, attempts) - conv, err = client.Exchange(ifname) - if err != nil && attempt < attempts { - log.Printf("Error: %v", err) - continue - } - break - } - if verbose { - for _, m := range conv { - log.Print(m.Summary()) - } - } - if err != nil { - return nil, err - } - // extract the network configuration - netconf, err := netboot.ConversationToNetconfv4(conv) - return netconf, err -} - func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { parent, err := netlink.LinkByName(sm.config.Interface) if err != nil { return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) } - // Create macvlan - // Generate name from UID interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) // Check if the interface doesn't exist first - _, err = net.InterfaceByName(interfaceName) + iface, err := net.InterfaceByName(interfaceName) if err != nil { log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) @@ -123,7 +41,7 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi if err != nil { return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) } - _, err = net.InterfaceByName(interfaceName) + iface, err = net.InterfaceByName(interfaceName) if err != nil { return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) } @@ -131,69 +49,91 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) } - newService.lease, err = vip.AcquireLease(newServiceUID[0:8], interfaceName, nil) - - if err != nil { - return err + client := vip.DHCPClient{ + Interface: iface, + OnBound: func(lease *vip.Lease) { + newVip.VIP = lease.ClientIP + + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + + // Create Add configuration to the new service + newService.vipConfig = *newVip + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + newService.cluster = *c + + // Add new service to manager configuration + service.Spec.LoadBalancerIP = newVip.VIP + log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) + //sm.serviceInstances = append(sm.serviceInstances, *newService) + + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + } + // Find an update our array + + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + sm.serviceInstances[x] = *newService + } + } + sm.upnpMap(*newService) + }, } - - ipNet, err := newService.lease.IPNet() - newVip.VIP = ipNet.IP.String() - newVip.Interface = interfaceName - - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - - // Create Add configuration to the new service - newService.vipConfig = *newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return err - } - newService.cluster = *c - // Set that DHCP is enabled newService.isDHCP = true // Set the name of the interface so that it can be removed on Service deletion newService.dhcpInterface = interfaceName - // Add new service to manager configuration - service.Spec.LoadBalancerIP = newVip.VIP - log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) + // Add the client so that we can call it's stop function + newService.dhcpClient = &client + sm.serviceInstances = append(sm.serviceInstances, *newService) - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } + go client.Start() - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) + // newService.lease, err = vip.AcquireLease(newServiceUID[0:8], interfaceName, nil) + // if err != nil { + // return err + // } - if retryErr != nil { - return retryErr - } + // ipNet, err := newService.lease.IPNet() + // if err != nil { + // return err + // } + // newVip.VIP = ipNet.IP.String() + // newVip.Interface = interfaceName - sm.upnpMap(*newService) return nil } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 9ace9920..8f634e90 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -7,6 +7,7 @@ import ( "os" "strconv" "strings" + "sync" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -25,6 +26,7 @@ import ( // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context) error { // Watch function + var wg sync.WaitGroup // Use a restartable watcher, as this should help in the event of etcd or timeout issues rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ @@ -59,10 +61,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) } else { log.Infof("Service [%s] has been addded/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) - err = sm.syncServices(svc) + wg.Add(1) + err = sm.syncServices(svc, &wg) if err != nil { log.Error(err) } + wg.Wait() } case watch.Deleted: svc, ok := event.Object.(*v1.Service) diff --git a/pkg/service/manager.go b/pkg/service/manager.go index d0de0d8b..b4a40023 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -13,6 +13,7 @@ import ( "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" @@ -61,6 +62,7 @@ type Instance struct { // Service uses DHCP isDHCP bool dhcpInterface string + dhcpClient *vip.DHCPClient // Kubernetes service mapping Vip string diff --git a/pkg/service/services.txt b/pkg/service/services.txt deleted file mode 100644 index 7d9ce524..00000000 --- a/pkg/service/services.txt +++ /dev/null @@ -1,159 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" -) - -func (sm *Manager) stopService(uid string) error { - found := false - for x := range sm.serviceInstances { - if sm.serviceInstances[x].service.UID == uid { - found = true - sm.serviceInstances[x].cluster.Stop() - } - } - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) - } - return nil -} - -func (sm *Manager) deleteService(uid string) error { - var updatedInstances []serviceInstance - found := false - for x := range sm.serviceInstances { - // Add the running services to the new array - if sm.serviceInstances[x].service.UID != uid { - updatedInstances = append(updatedInstances, sm.serviceInstances[x]) - } else { - // Flip the found when we match - found = true - if sm.serviceInstances[x].dhcp != nil { - sm.serviceInstances[x].dhcp.dhcpClient.Stop() - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcp.dhcpInterface) - if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) - } - netlink.LinkDel(macvlan) - } - if sm.serviceInstances[x].vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) - err := sm.bgpServer.DelHost(cidrVip) - return err - } - } - } - // If we've been through all services and not found the correct one then error - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) - } - - // Update the service array - sm.serviceInstances = updatedInstances - - log.Debugf("Removed [%s] from manager, [%d] services remain", uid, len(sm.serviceInstances)) - - return nil -} - -func (sm *Manager) syncServices(s *plndrServices) error { - log.Debugf("[STARTING] Service Sync") - // Iterate through the synchronising services - for x := range s.Services { - foundInstance := false - for y := range sm.serviceInstances { - if s.Services[x].UID == sm.serviceInstances[y].service.UID { - // We have found this instance in the manager and we can update it - foundInstance = true - } - } - - // Generate new Virtual IP configuration - newVip := kubevip.Config{ - VIP: s.Services[x].Vip, - Interface: sm.config.Interface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, - } - - // This instance wasn't found, we need to add it to the manager - if foundInstance == false { - // Create new service - var newService serviceInstance - - // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP - if s.Services[x].Vip == "0.0.0.0" { - - err := sm.createDHCPService(s.Services[x].UID, &newVip, newService, service) - if err != nil { - return err - } - - } - log.Infof("New VIP [%s] for [%s/%s] ", s.Services[x].Vip, s.Services[x].ServiceName, s.Services[x].UID) - - // Generate Load Balancer config - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - Port: s.Services[x].Port, - Type: s.Services[x].Type, - BindToVip: true, - } - - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = newVip - newService.service = s.Services[x] - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", s.Services[x].ServiceName, s.Services[x].UID) - return err - } - - sm.upnpMap(s.Services[x]) - - newService.cluster = *c - - // Begin watching this service - go sm.newWatcher(&newService) - - // Add new service to manager configuration - sm.serviceInstances = append(sm.serviceInstances, newService) - } - } - log.Debugf("[COMPLETE] Service Sync") - - return nil -} - -func (sm *Manager) upnpMap(s service) { - // If upnp is enabled then update the gateway/router with the address - // TODO - work out if we need to mapping.Reclaim() - if sm.upnp != nil { - - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) - if err := sm.upnp.AddPortMapping(s.Port, s.Port, 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { - log.Infof("Service should be accessible externally on port [%d]", s.Port) - } else { - sm.upnp.Reclaim() - log.Errorf("Unable to map port to gateway [%s]", err.Error()) - } - } -} diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index 13c020e7..290d5b12 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -7,94 +7,15 @@ import ( "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/insomniacslk/dhcp/dhcpv4" - "github.com/insomniacslk/dhcp/dhcpv4/client4" - "github.com/insomniacslk/dhcp/dhcpv6" - "github.com/insomniacslk/dhcp/dhcpv6/client6" - "github.com/insomniacslk/dhcp/netboot" "github.com/vishvananda/netlink" ) -func dhclient6(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { - if attempts < 1 { - attempts = 1 - } - llAddr, err := dhcpv6.GetLinkLocalAddr(ifname) - if err != nil { - return nil, err - } - laddr := net.UDPAddr{ - IP: llAddr, - Port: dhcpv6.DefaultClientPort, - Zone: ifname, - } - raddr := net.UDPAddr{ - IP: dhcpv6.AllDHCPRelayAgentsAndServers, - Port: dhcpv6.DefaultServerPort, - Zone: ifname, - } - c := client6.NewClient() - c.LocalAddr = &laddr - c.RemoteAddr = &raddr - var conv []dhcpv6.DHCPv6 - for attempt := 0; attempt < attempts; attempt++ { - log.Printf("Attempt %d of %d", attempt+1, attempts) - conv, err = c.Exchange(ifname, dhcpv6.WithNetboot) - if err != nil && attempt < attempts { - log.Printf("Error: %v", err) - continue - } - break - } - if verbose { - for _, m := range conv { - log.Print(m.Summary()) - } - } - if err != nil { - return nil, err - } - // extract the network configuration - netconf, err := netboot.ConversationToNetconf(conv) - return netconf, err -} - -func dhclient4(ifname string, attempts int, verbose bool) (*netboot.BootConf, error) { - if attempts < 1 { - attempts = 1 - } - client := client4.NewClient() - var ( - conv []*dhcpv4.DHCPv4 - err error - ) - for attempt := 0; attempt < attempts; attempt++ { - log.Printf("Attempt %d of %d", attempt+1, attempts) - conv, err = client.Exchange(ifname) - if err != nil && attempt < attempts { - log.Printf("Error: %v", err) - continue - } - break - } - if verbose { - for _, m := range conv { - log.Print(m.Summary()) - } - } - if err != nil { - return nil, err - } - // extract the network configuration - netconf, err := netboot.ConversationToNetconfv4(conv) - return netconf, err -} - func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { parent, err := netlink.LinkByName(sm.config.Interface) if err != nil { @@ -107,11 +28,11 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) // Check if the interface doesn't exist first - _, err = net.InterfaceByName(interfaceName) + iface, err := net.InterfaceByName(interfaceName) if err != nil { log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_BRIDGE} + mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_DEFAULT} err = netlink.LinkAdd(mac) if err != nil { @@ -122,90 +43,87 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi if err != nil { return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) } - _, err = net.InterfaceByName(interfaceName) + iface, err = net.InterfaceByName(interfaceName) if err != nil { return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) } } else { log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) } - var bootconf *netboot.BootConf - bootconf, err = dhclient4(interfaceName, 5, false) - if err != nil { - return err - } - err = netboot.ConfigureInterface(interfaceName, &bootconf.NetConf) - if err != nil { - return err - } - - newVip.VIP = bootconf.Addresses[0].IPNet.IP.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - - // // Generate Load Balancer config - // newLB := kubevip.LoadBalancer{ - // Name: fmt.Sprintf("%s-load-balancer", s.Services[x].ServiceName), - // Port: s.Services[x].Port, - // Type: s.Services[x].Type, - // BindToVip: true, - // } - - // // Add Load Balancer Configuration - // newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = *newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return err + client := vip.DHCPClient{ + Interface: iface, + OnBound: func(lease *vip.Lease) { + newVip.VIP = lease.ClientIP + + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + + // Create Add configuration to the new service + newService.vipConfig = *newVip + + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + newService.cluster = *c + + // Add new service to manager configuration + service.Spec.LoadBalancerIP = newVip.VIP + log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) + //sm.serviceInstances = append(sm.serviceInstances, *newService) + + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + } + // Find an update our array + + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + sm.serviceInstances[x] = *newService + } + } + sm.upnpMap(*newService) + }, } - newService.cluster = *c - // Set that DHCP is enabled newService.isDHCP = true // Set the name of the interface so that it can be removed on Service deletion newService.dhcpInterface = interfaceName + // Add the client so that we can call it's stop function + newService.dhcpClient = &client - // Add new service to manager configuration - service.Spec.LoadBalancerIP = newVip.VIP - log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) sm.serviceInstances = append(sm.serviceInstances, *newService) - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - return retryErr - } + go client.Start() - sm.upnpMap(*newService) return nil } diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 373c0b4d..11920ce3 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -5,9 +5,6 @@ import ( "net" "time" - "github.com/d2g/dhcp4" - "github.com/digineo/go-dhclient" - "github.com/google/gopacket/layers" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) @@ -43,29 +40,15 @@ func (ddns *ddnsManager) Start() (string, error) { // channel to wait for IP ipCh := make(chan string) - //var options dhcp4.Option - AcquireLease(ddns.network.DDNSHostName(), interfaceName, dhcp4.Options{}) - client := dhclient.Client{ + + client := DHCPClient{ // send host name, not current os.Hostname, but configured name from user - Hostname: ddns.network.DDNSHostName(), - Iface: iface, - OnBound: func(lease *dhclient.Lease) { - ipCh <- lease.FixedAddress.String() + Hostname: ddns.network.DDNSHostName(), + Interface: iface, + OnBound: func(lease *Lease) { + ipCh <- lease.ClientIP }, } - //options[DHCPOptHostname] = []byte(client.Hostname) - - // add default request param - for _, param := range dhclient.DefaultParamsRequestList { - client.AddParamRequest(param) - } - // send hostname to get IP for this specific name - client.AddOption(layers.DHCPOptHostname, []byte(client.Hostname)) - // use clientID so different leaders will use same ID to get same IP - client.AddOption(layers.DHCPOptClientID, []byte(client.Hostname)) - - log.Info("start dhcp client for ddns") - client.Start() log.Info("waiting for ip from dhcp") ip, timeout := "", time.After(1*time.Minute) diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index 1947b191..d447a089 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -1,535 +1,112 @@ package vip import ( - "encoding/binary" - "fmt" - "log" - "math/rand" "net" "sync" - "sync/atomic" "time" - "github.com/containernetworking/cni/pkg/types" - "github.com/d2g/dhcp4" - "github.com/d2g/dhcp4client" - "github.com/pkg/errors" - "github.com/vishvananda/netlink" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/jpillora/backoff" + log "github.com/sirupsen/logrus" ) -// DHCPOpt represents a DHCP option or parameter from RFC-2132 -type DHCPOpt byte +// Callback is a function called on certain events +type Callback func(*Lease) -// Constants for the DHCPOpt options. -const ( - DHCPOptPad DHCPOpt = 0 - DHCPOptSubnetMask DHCPOpt = 1 // 4, net.IP - DHCPOptTimeOffset DHCPOpt = 2 // 4, int32 (signed seconds from UTC) - DHCPOptRouter DHCPOpt = 3 // n*4, [n]net.IP - DHCPOptTimeServer DHCPOpt = 4 // n*4, [n]net.IP - DHCPOptNameServer DHCPOpt = 5 // n*4, [n]net.IP - DHCPOptDNS DHCPOpt = 6 // n*4, [n]net.IP - DHCPOptLogServer DHCPOpt = 7 // n*4, [n]net.IP - DHCPOptCookieServer DHCPOpt = 8 // n*4, [n]net.IP - DHCPOptLPRServer DHCPOpt = 9 // n*4, [n]net.IP - DHCPOptImpressServer DHCPOpt = 10 // n*4, [n]net.IP - DHCPOptResLocServer DHCPOpt = 11 // n*4, [n]net.IP - DHCPOptHostname DHCPOpt = 12 // n, string - DHCPOptBootfileSize DHCPOpt = 13 // 2, uint16 - DHCPOptMeritDumpFile DHCPOpt = 14 // >1, string - DHCPOptDomainName DHCPOpt = 15 // n, string - DHCPOptSwapServer DHCPOpt = 16 // n*4, [n]net.IP - DHCPOptRootPath DHCPOpt = 17 // n, string - DHCPOptExtensionsPath DHCPOpt = 18 // n, string - DHCPOptIPForwarding DHCPOpt = 19 // 1, bool - DHCPOptSourceRouting DHCPOpt = 20 // 1, bool - DHCPOptPolicyFilter DHCPOpt = 21 // 8*n, [n]{net.IP/net.IP} - DHCPOptDatagramMTU DHCPOpt = 22 // 2, uint16 - DHCPOptDefaultTTL DHCPOpt = 23 // 1, byte - DHCPOptPathMTUAgingTimeout DHCPOpt = 24 // 4, uint32 - DHCPOptPathPlateuTableOption DHCPOpt = 25 // 2*n, []uint16 - DHCPOptInterfaceMTU DHCPOpt = 26 // 2, uint16 - DHCPOptAllSubsLocal DHCPOpt = 27 // 1, bool - DHCPOptBroadcastAddr DHCPOpt = 28 // 4, net.IP - DHCPOptMaskDiscovery DHCPOpt = 29 // 1, bool - DHCPOptMaskSupplier DHCPOpt = 30 // 1, bool - DHCPOptRouterDiscovery DHCPOpt = 31 // 1, bool - DHCPOptSolicitAddr DHCPOpt = 32 // 4, net.IP - DHCPOptStaticRoute DHCPOpt = 33 // n*8, [n]{net.IP/net.IP} -- note the 2nd is router not mask - DHCPOptARPTrailers DHCPOpt = 34 // 1, bool - DHCPOptARPTimeout DHCPOpt = 35 // 4, uint32 - DHCPOptEthernetEncap DHCPOpt = 36 // 1, bool - DHCPOptTCPTTL DHCPOpt = 37 // 1, byte - DHCPOptTCPKeepAliveInt DHCPOpt = 38 // 4, uint32 - DHCPOptTCPKeepAliveGarbage DHCPOpt = 39 // 1, bool - DHCPOptNISDomain DHCPOpt = 40 // n, string - DHCPOptNISServers DHCPOpt = 41 // 4*n, [n]net.IP - DHCPOptNTPServers DHCPOpt = 42 // 4*n, [n]net.IP - DHCPOptVendorOption DHCPOpt = 43 // n, [n]byte // may be encapsulated. - DHCPOptNetBIOSTCPNS DHCPOpt = 44 // 4*n, [n]net.IP - DHCPOptNetBIOSTCPDDS DHCPOpt = 45 // 4*n, [n]net.IP - DHCPOptNETBIOSTCPNodeType DHCPOpt = 46 // 1, magic byte - DHCPOptNetBIOSTCPScope DHCPOpt = 47 // n, string - DHCPOptXFontServer DHCPOpt = 48 // n, string - DHCPOptXDisplayManager DHCPOpt = 49 // n, string - DHCPOptRequestIP DHCPOpt = 50 // 4, net.IP - DHCPOptLeaseTime DHCPOpt = 51 // 4, uint32 - DHCPOptExtOptions DHCPOpt = 52 // 1, 1/2/3 - DHCPOptMessageType DHCPOpt = 53 // 1, 1-7 - DHCPOptServerID DHCPOpt = 54 // 4, net.IP - DHCPOptParamsRequest DHCPOpt = 55 // n, []byte - DHCPOptMessage DHCPOpt = 56 // n, 3 - DHCPOptMaxMessageSize DHCPOpt = 57 // 2, uint16 - DHCPOptT1 DHCPOpt = 58 // 4, uint32 - DHCPOptT2 DHCPOpt = 59 // 4, uint32 - DHCPOptClassID DHCPOpt = 60 // n, []byte - DHCPOptClientID DHCPOpt = 61 // n >= 2, []byte - DHCPOptDomainSearch DHCPOpt = 119 // n, string - DHCPOptSIPServers DHCPOpt = 120 // n, url - DHCPOptClasslessStaticRoute DHCPOpt = 121 // - DHCPOptEnd DHCPOpt = 255 -) - -// RFC 2131 suggests using exponential backoff, starting with 4sec -// and randomized to +/- 1sec -const resendDelay0 = 4 * time.Second -const resendDelayMax = 32 * time.Second -const resendCount = 3 - -var errNoMoreTries = errors.New("no more tries") - -const ( - leaseStateBound = iota - leaseStateRenewing - leaseStateRebinding -) - -// This implementation uses 1 OS thread per lease. This is because -// all the network operations have to be done in network namespace -// of the interface. This can be improved by switching to the proper -// namespace for network ops and using fewer threads. However, this -// needs to be done carefully as dhcp4client ops are blocking. - -// DHCPLease is the actual lease from a DHCP server -type DHCPLease struct { - clientID string - ack *dhcp4.Packet - opts dhcp4.Options - link netlink.Link - renewalTime time.Time - rebindingTime time.Time - expireTime time.Time - stopping uint32 - stop chan struct{} - wg sync.WaitGroup +// Lease is +type Lease struct { + RenewAfter time.Time + ClientIP string + SubnetMask string + Router string + DNS []string } -// AcquireLease gets an DHCP lease and then maintains it in the background -// by periodically renewing it. The acquired lease can be released by -// calling DHCPLease.Stop() -func AcquireLease(clientID, ifName string, opts dhcp4.Options) (*DHCPLease, error) { - errCh := make(chan error, 1) - l := &DHCPLease{ - clientID: clientID, - stop: make(chan struct{}), - } - - log.Printf("%v: acquiring lease", clientID) - - l.wg.Add(1) - go func() error { - defer l.wg.Done() - - link, err := netlink.LinkByName(ifName) - if err != nil { - errCh <- fmt.Errorf("error looking up %q: %v", ifName, err) - } - - l.link = link - - if err = l.acquire(); err != nil { - errCh <- err - } - - log.Printf("%v: lease acquired, expiration is %v", l.clientID, l.expireTime) - - errCh <- nil - - l.maintain() - return nil +//DHCPClient is +type DHCPClient struct { + Interface *net.Interface // e.g. net.InterfaceByName("eth0") + HWAddr net.HardwareAddr + Hostname string + Lease Lease - }() + err error + once sync.Once + onceErr error + connection net.PacketConn + hardwareAddr net.HardwareAddr + timeNow func() time.Time + generateXID func() uint32 + stop chan struct{} - if err := <-errCh; err != nil { - return nil, err - } + // last DHCPACK packet for renewal/release + Ack *layers.DHCPv4 - return l, nil + OnBound Callback // On renew or rebound } -// Stop terminates the background task that maintains the lease -// and issues a DHCP Release -func (l *DHCPLease) Stop() { - if atomic.CompareAndSwapUint32(&l.stopping, 0, 1) { - close(l.stop) - } - l.wg.Wait() -} - -func (l *DHCPLease) acquire() error { - c, err := newDHCPClient(l.link) - if err != nil { - return err - } - defer c.Close() - - if (l.link.Attrs().Flags & net.FlagUp) != net.FlagUp { - log.Printf("Link %q down. Attempting to set up", l.link.Attrs().Name) - if err = netlink.LinkSetUp(l.link); err != nil { - return err - } - } - - pkt, err := backoffRetry(func() (*dhcp4.Packet, error) { - ok, ack, err := c.Request() - switch { - case err != nil: - return nil, err - case !ok: - return nil, fmt.Errorf("DHCP server NACK'd own offer") - default: - return &ack, nil - } - }) - if err != nil { - return err - } - - return l.commit(pkt) +// Err returns any errors from the DHCP client +func (c *DHCPClient) Err() error { + return c.err } -func (l *DHCPLease) commit(ack *dhcp4.Packet) error { - opts := ack.ParseOptions() +// Start will begin the DHCP client +func (c *DHCPClient) Start() error { - leaseTime, err := parseLeaseTime(opts) - if err != nil { - return err - } - - rebindingTime, err := parseRebindingTime(opts) - if err != nil || rebindingTime > leaseTime { - // Per RFC 2131 Section 4.4.5, it should default to 85% of lease time - rebindingTime = leaseTime * 85 / 100 + var ack *layers.DHCPv4 + pkt := gopacket.NewPacket(nil, layers.LayerTypeDHCPv4, gopacket.DecodeOptions{}) + if dhcp, ok := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4); ok { + ack = dhcp } + // Set ack packet + c.Ack = ack + // Get Hardware address + c.HWAddr = c.Interface.HardwareAddr + // Create a channel for notifications + c.stop = make(chan struct{}) - renewalTime, err := parseRenewalTime(opts) - if err != nil || renewalTime > rebindingTime { - // Per RFC 2131 Section 4.4.5, it should default to 50% of lease time - renewalTime = leaseTime / 2 + // Configure the backoff + backoff := backoff.Backoff{ + Factor: 2, + Jitter: true, + Min: 10 * time.Second, + Max: 1 * time.Minute, } - - now := time.Now() - l.expireTime = now.Add(leaseTime) - l.renewalTime = now.Add(renewalTime) - l.rebindingTime = now.Add(rebindingTime) - l.ack = ack - l.opts = opts - - return nil -} - -func (l *DHCPLease) maintain() { - state := leaseStateBound - + // Start renew loop for { - var sleepDur time.Duration - - switch state { - case leaseStateBound: - sleepDur = l.renewalTime.Sub(time.Now()) - if sleepDur <= 0 { - log.Printf("%v: renewing lease", l.clientID) - state = leaseStateRenewing + for c.obtainOrRenew() { + if err := c.Err(); err != nil { + dur := backoff.Duration() + log.Printf("Temporary error: %v (waiting %v)", err, dur) + time.Sleep(dur) continue - } - - case leaseStateRenewing: - if err := l.renew(); err != nil { - log.Printf("%v: %v", l.clientID, err) - - if time.Now().After(l.rebindingTime) { - log.Printf("%v: renawal time expired, rebinding", l.clientID) - state = leaseStateRebinding - } } else { - log.Printf("%v: lease renewed, expiration is %v", l.clientID, l.expireTime) - state = leaseStateBound + backoff.Reset() + break } - case leaseStateRebinding: - if err := l.acquire(); err != nil { - log.Printf("%v: %v", l.clientID, err) - - if time.Now().After(l.expireTime) { - log.Printf("%v: lease expired, bringing interface DOWN", l.clientID) - l.downIface() - return - } - } else { - log.Printf("%v: lease rebound, expiration is %v", l.clientID, l.expireTime) - state = leaseStateBound - } } - select { - case <-time.After(sleepDur): - - case <-l.stop: - if err := l.release(); err != nil { - log.Printf("%v: failed to release DHCP lease: %v", l.clientID, err) - } - return - } - } -} - -func (l *DHCPLease) downIface() { - if err := netlink.LinkSetDown(l.link); err != nil { - log.Printf("%v: failed to bring %v interface DOWN: %v", l.clientID, l.link.Attrs().Name, err) - } -} - -func (l *DHCPLease) renew() error { - c, err := newDHCPClient(l.link) - if err != nil { - return err - } - defer c.Close() - - pkt, err := backoffRetry(func() (*dhcp4.Packet, error) { - ok, ack, err := c.Renew(*l.ack) - switch { - case err != nil: - return nil, err - case !ok: - return nil, fmt.Errorf("DHCP server did not renew lease") - default: - return &ack, nil + // call the handler + if cb := c.OnBound; cb != nil { + cb(&c.Lease) } - }) - if err != nil { - return err - } - - l.commit(pkt) - return nil -} - -func (l *DHCPLease) release() error { - log.Printf("%v: releasing lease", l.clientID) - - c, err := newDHCPClient(l.link) - if err != nil { - return err - } - defer c.Close() - - if err = c.Release(*l.ack); err != nil { - return fmt.Errorf("failed to send DHCPRELEASE") - } - - return nil -} - -func (l *DHCPLease) IPNet() (*net.IPNet, error) { - mask := parseSubnetMask(l.opts) - if mask == nil { - return nil, fmt.Errorf("DHCP option Subnet Mask not found in DHCPACK") - } - - return &net.IPNet{ - IP: l.ack.YIAddr(), - Mask: mask, - }, nil -} - -func (l *DHCPLease) Gateway() net.IP { - return parseRouter(l.opts) -} - -func (l *DHCPLease) Routes() []*types.Route { - routes := []*types.Route{} - - // RFC 3442 states that if Classless Static Routes (option 121) - // exist, we ignore Static Routes (option 33) and the Router/Gateway. - opt121_routes := parseCIDRRoutes(l.opts) - if len(opt121_routes) > 0 { - return append(routes, opt121_routes...) - } - - // Append Static Routes - routes = append(routes, parseRoutes(l.opts)...) - - // The CNI spec says even if there is a gateway specified, we must - // add a default route in the routes section. - if gw := l.Gateway(); gw != nil { - _, defaultRoute, _ := net.ParseCIDR("0.0.0.0/0") - routes = append(routes, &types.Route{Dst: *defaultRoute, GW: gw}) - } - - return routes -} - -// jitter returns a random value within [-span, span) range -func jitter(span time.Duration) time.Duration { - return time.Duration(float64(span) * (2.0*rand.Float64() - 1.0)) -} - -func backoffRetry(f func() (*dhcp4.Packet, error)) (*dhcp4.Packet, error) { - var baseDelay time.Duration = resendDelay0 - - for i := 0; i < resendCount; i++ { - pkt, err := f() - if err == nil { - return pkt, nil - } - - log.Print(err) - - time.Sleep(baseDelay + jitter(time.Second)) - - if baseDelay < resendDelayMax { - baseDelay *= 2 + select { + case <-c.stop: + return c.err + case <-time.After(time.Until(c.Lease.RenewAfter)): + // remove lease and request a new one + continue } } - - return nil, errNoMoreTries } -func newDHCPClient(link netlink.Link) (*dhcp4client.Client, error) { - pktsock, err := dhcp4client.NewPacketSock(link.Attrs().Index) +// Stop will stop the DHCP client +func (c *DHCPClient) Stop() error { + err := c.release() if err != nil { - return nil, err - } - - return dhcp4client.New( - dhcp4client.HardwareAddr(link.Attrs().HardwareAddr), - dhcp4client.Timeout(5*time.Second), - dhcp4client.Broadcast(false), - dhcp4client.Connection(pktsock), - ) -} - -func parseRouter(opts dhcp4.Options) net.IP { - if opts, ok := opts[dhcp4.OptionRouter]; ok { - if len(opts) == 4 { - return net.IP(opts) - } + log.Errorf("Unable ro return lease: %v", err) } + close(c.stop) return nil } - -func classfulSubnet(sn net.IP) net.IPNet { - return net.IPNet{ - IP: sn, - Mask: sn.DefaultMask(), - } -} - -func parseRoutes(opts dhcp4.Options) []*types.Route { - // StaticRoutes format: pairs of: - // Dest = 4 bytes; Classful IP subnet - // Router = 4 bytes; IP address of router - - routes := []*types.Route{} - if opt, ok := opts[dhcp4.OptionStaticRoute]; ok { - for len(opt) >= 8 { - sn := opt[0:4] - r := opt[4:8] - rt := &types.Route{ - Dst: classfulSubnet(sn), - GW: r, - } - routes = append(routes, rt) - opt = opt[8:] - } - } - - return routes -} - -func parseCIDRRoutes(opts dhcp4.Options) []*types.Route { - // See RFC4332 for format (http://tools.ietf.org/html/rfc3442) - - routes := []*types.Route{} - if opt, ok := opts[dhcp4.OptionClasslessRouteFormat]; ok { - for len(opt) >= 5 { - width := int(opt[0]) - if width > 32 { - // error: can't have more than /32 - return nil - } - // network bits are compacted to avoid zeros - octets := 0 - if width > 0 { - octets = (width-1)/8 + 1 - } - - if len(opt) < 1+octets+4 { - // error: too short - return nil - } - - sn := make([]byte, 4) - copy(sn, opt[1:octets+1]) - - gw := net.IP(opt[octets+1 : octets+5]) - - rt := &types.Route{ - Dst: net.IPNet{ - IP: net.IP(sn), - Mask: net.CIDRMask(width, 32), - }, - GW: gw, - } - routes = append(routes, rt) - - opt = opt[octets+5:] - } - } - return routes -} - -func parseSubnetMask(opts dhcp4.Options) net.IPMask { - mask, ok := opts[dhcp4.OptionSubnetMask] - if !ok { - return nil - } - - return net.IPMask(mask) -} - -func parseDuration(opts dhcp4.Options, code dhcp4.OptionCode, optName string) (time.Duration, error) { - val, ok := opts[code] - if !ok { - return 0, fmt.Errorf("option %v not found", optName) - } - if len(val) != 4 { - return 0, fmt.Errorf("option %v is not 4 bytes", optName) - } - - secs := binary.BigEndian.Uint32(val) - return time.Duration(secs) * time.Second, nil -} - -func parseLeaseTime(opts dhcp4.Options) (time.Duration, error) { - return parseDuration(opts, dhcp4.OptionIPAddressLeaseTime, "LeaseTime") -} - -func parseRenewalTime(opts dhcp4.Options) (time.Duration, error) { - return parseDuration(opts, dhcp4.OptionRenewalTimeValue, "RenewalTime") -} - -func parseRebindingTime(opts dhcp4.Options) (time.Duration, error) { - return parseDuration(opts, dhcp4.OptionRebindingTimeValue, "RebindingTime") -} diff --git a/pkg/vip/dhcp_internals.go b/pkg/vip/dhcp_internals.go new file mode 100644 index 00000000..aa2e7e41 --- /dev/null +++ b/pkg/vip/dhcp_internals.go @@ -0,0 +1,206 @@ +package vip + +import ( + "bytes" + "fmt" + "syscall" + "time" + + "github.com/google/gopacket/layers" + "github.com/mdlayher/raw" + "github.com/pkg/errors" + "github.com/rtr7/dhcp4" + "golang.org/x/sys/unix" +) + +func (c *DHCPClient) release() error { + release := c.packet(c.generateXID(), append([]layers.DHCPOption{ + dhcp4.MessageTypeOpt(layers.DHCPMsgTypeRelease), + }, serverID(c.Ack)...)) + release.ClientIP = c.Ack.YourClientIP + if err := dhcp4.Write(c.connection, release); err != nil { + return err + } + + c.Ack = nil + return nil +} + +func serverID(pkt *layers.DHCPv4) []layers.DHCPOption { + for _, o := range pkt.Options { + if o.Type == layers.DHCPOptServerID { + return []layers.DHCPOption{o} + } + } + return nil +} + +func (c *DHCPClient) packet(xid uint32, opts []layers.DHCPOption) *layers.DHCPv4 { + return &layers.DHCPv4{ + Operation: layers.DHCPOpRequest, + HardwareType: layers.LinkTypeEthernet, + HardwareLen: uint8(len(layers.EthernetBroadcast)), + HardwareOpts: 0, // clients set this to zero (used by relay agents) + Xid: xid, + Secs: 0, // TODO: fill in? + Flags: 0, // we can receive IP packets via unicast + ClientHWAddr: c.hardwareAddr, + ServerName: nil, + File: nil, + Options: opts, + } +} + +var errNAK = errors.New("received DHCPNAK") + +// ObtainOrRenew returns false when encountering a permanent error. +func (c *DHCPClient) obtainOrRenew() bool { + c.once.Do(func() { + if c.timeNow == nil { + c.timeNow = time.Now + } + if c.connection == nil && c.Interface != nil { + conn, err := raw.ListenPacket(c.Interface, syscall.ETH_P_IP, &raw.Config{ + LinuxSockDGRAM: true, + }) + if err != nil { + c.onceErr = err + return + } + c.connection = conn + } + if c.connection == nil && c.Interface == nil { + c.onceErr = fmt.Errorf("c.Interface is nil") + return + } + if c.hardwareAddr == nil && c.HWAddr != nil { + c.hardwareAddr = c.HWAddr + } + if c.hardwareAddr == nil { + c.hardwareAddr = c.Interface.HardwareAddr + } + if c.generateXID == nil { + c.generateXID = dhcp4.XIDGenerator(c.hardwareAddr) + } + if c.Hostname == "" { + var utsname unix.Utsname + if err := unix.Uname(&utsname); err != nil { + c.onceErr = err + return + } + c.Hostname = string(utsname.Nodename[:bytes.IndexByte(utsname.Nodename[:], 0)]) + } + }) + if c.onceErr != nil { + c.err = c.onceErr + return false // permanent error + } + c.err = nil // clear previous error + ack, err := c.dhcpRequest() + if err != nil { + if errno, ok := err.(syscall.Errno); ok && errno == syscall.EAGAIN { + c.err = fmt.Errorf("DHCP: timeout (server(s) unreachable)") + return true // temporary error + } + if err == errNAK { + c.Ack = nil // start over at DHCPDISCOVER + } + c.err = fmt.Errorf("DHCP: %v", err) + return true // temporary error + } + c.Ack = ack + c.Lease.ClientIP = ack.YourClientIP.String() + lease := dhcp4.LeaseFromACK(ack) + if mask := lease.Netmask; len(mask) > 0 { + c.Lease.SubnetMask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) + } + if len(lease.Router) > 0 { + c.Lease.Router = lease.Router.String() + } + if len(lease.DNS) > 0 { + c.Lease.DNS = make([]string, len(lease.DNS)) + for idx, ip := range lease.DNS { + c.Lease.DNS[idx] = ip.String() + } + } + c.Lease.RenewAfter = c.timeNow().Add(lease.RenewalTime) + return true +} + +func (c *DHCPClient) dhcpRequest() (*layers.DHCPv4, error) { + var last *layers.DHCPv4 + + if c.Ack != nil { + last = c.Ack + } else { + discover := c.packet(c.generateXID(), []layers.DHCPOption{ + dhcp4.MessageTypeOpt(layers.DHCPMsgTypeDiscover), + dhcp4.HostnameOpt(c.Hostname), + dhcp4.ClientIDOpt(layers.LinkTypeEthernet, c.hardwareAddr), + dhcp4.ParamsRequestOpt( + layers.DHCPOptDNS, + layers.DHCPOptRouter, + layers.DHCPOptSubnetMask), + }) + if err := dhcp4.Write(c.connection, discover); err != nil { + return nil, err + } + + // Look for DHCPOFFER packet (described in RFC2131 4.3.1): + c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)) + for { + offer, err := dhcp4.Read(c.connection) + if err != nil { + return nil, err + } + if offer == nil { + continue // not a DHCPv4 packet + } + if offer.Xid != discover.Xid { + continue // broadcast reply for different DHCP transaction + } + if !dhcp4.HasMessageType(offer.Options, layers.DHCPMsgTypeOffer) { + continue + } + last = offer + break + } + } + + // Build a DHCPREQUEST packet: + request := c.packet(last.Xid, append([]layers.DHCPOption{ + dhcp4.MessageTypeOpt(layers.DHCPMsgTypeRequest), + dhcp4.RequestIPOpt(last.YourClientIP), + dhcp4.HostnameOpt(c.Hostname), + dhcp4.ClientIDOpt(layers.LinkTypeEthernet, c.hardwareAddr), + dhcp4.ParamsRequestOpt( + layers.DHCPOptDNS, + layers.DHCPOptRouter, + layers.DHCPOptSubnetMask), + }, serverID(last)...)) + if err := dhcp4.Write(c.connection, request); err != nil { + return nil, err + } + + c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)) + for { + // Look for DHCPACK packet (described in RFC2131 4.3.1): + ack, err := dhcp4.Read(c.connection) + if err != nil { + return nil, err + } + if ack == nil { + continue // not a DHCPv4 packet + } + if ack.Xid != request.Xid { + continue // broadcast reply for different DHCP transaction + } + if !dhcp4.HasMessageType(ack.Options, layers.DHCPMsgTypeAck) { + if dhcp4.HasMessageType(ack.Options, layers.DHCPMsgTypeNak) { + return nil, errNAK + } + continue + } + return ack, nil + } +} From 5545471391e28bfabfac7dc0ab5d495b39b106d5 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 13 May 2021 17:10:44 +0100 Subject: [PATCH 103/542] Fixes DDNS --- cmd/kube-vip-manifests.go | 4 ++-- cmd/kube-vip.go | 1 + pkg/kubevip/config_generator.go | 4 ++++ pkg/manager/manager_arp.go | 21 +++++++++++++++++++++ pkg/manager/manager_bgp.go | 20 ++++++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 96288eb1..4de46932 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -49,7 +49,7 @@ var kubeManifestPod = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "") { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && initConfig.DDNS == false) { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } @@ -75,7 +75,7 @@ var kubeManifestDaemon = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "") { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && initConfig.DDNS == false) { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 91b8a7cb..270c311b 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -73,6 +73,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 7643b0d6..821e20d2 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -470,6 +470,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: cpNamespace, Value: c.Namespace, }, + { + Name: vipDdns, + Value: strconv.FormatBool(c.DDNS), + }, } newEnvironment = append(newEnvironment, cp...) } diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 1feaeabb..576117a3 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -9,6 +9,7 @@ import ( "github.com/kamhlos/upnp" "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection" @@ -26,6 +27,11 @@ func (sm *Manager) startARP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + // use a Go context so we can tell the dns loop code when we + // want to step down + ctxDNS, cancelDNS := context.WithCancel(context.Background()) + defer cancelDNS() + // Shutdown function that will wait on this signal, unless we call it ourselves go func() { <-sm.signalChan @@ -43,6 +49,21 @@ func (sm *Manager) startARP() error { return err } + // setup ddns first + // for first time, need to wait until IP is allocated from DHCP + if cpCluster.Network.IsDDNS() { + if err := cpCluster.StartDDNS(ctxDNS); err != nil { + log.Error(err) + } + } + + // start the dns updater if address is dns + if cpCluster.Network.IsDNS() { + log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) + ipUpdater := vip.NewIPUpdater(cpCluster.Network) + ipUpdater.Run(ctxDNS) + } + clusterManager := &cluster.Manager{ KubernetesClient: sm.clientSet, } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 03b6ad99..da3c0838 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -9,6 +9,7 @@ import ( "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/packet" + "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" ) @@ -57,6 +58,11 @@ func (sm *Manager) startBGP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + // use a Go context so we can tell the dns loop code when we + // want to step down + ctxDNS, cancelDNS := context.WithCancel(context.Background()) + defer cancelDNS() + // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { if sm.bgpServer != nil { @@ -81,6 +87,20 @@ func (sm *Manager) startBGP() error { if err != nil { return err } + // setup ddns first + // for first time, need to wait until IP is allocated from DHCP + if cpCluster.Network.IsDDNS() { + if err := cpCluster.StartDDNS(ctxDNS); err != nil { + log.Error(err) + } + } + + // start the dns updater if address is dns + if cpCluster.Network.IsDNS() { + log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) + ipUpdater := vip.NewIPUpdater(cpCluster.Network) + ipUpdater.Run(ctxDNS) + } go func() { err = cpCluster.StartLoadBalancerService(sm.config, sm.bgpServer) if err != nil { From 1efc24d712337a632c6dac2f007c7b38d24c611c Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 14 May 2021 09:39:45 +0100 Subject: [PATCH 104/542] Create ROADMAP.md --- ROADMAP.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 00000000..d83a539e --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,35 @@ +# Kube-Vip Roadmap + +This document outlines the roadmap for the **kube-vip** project and only covers the technologies within this particular project, other projects that augment or provide additional functionality (such as cloud-providers) may have their own roadmaps in future. The functionality for **kube-vip** has grown either been developed organically or through real-world needs, and this is the first attempt to put into words a plan for the future of **kube-vip** and will additional evolve over time. This means that items listed or detailed here are not neccessarily set in stone and the roadmap can grow/shrink as the project matures. We definitely welcome suggestions and ideas from everyone about the roadmap and **kube-vip** features. Reach us through Issues, Slack or email @kube-vip.io. + +## Release methodology + +The **kube-vip** project attempts to follow a tick-tock release cycle, this typically means that one release will come **packed** with new features where the following release will come with fixes, code sanitation and performane enhancements. + +## Roadmap + +The **kube-vip** project offers two main areas of functionality: + +- HA Kubernetes clusters through a control-plane VIP +- Kubernetes `service type:LoadBalancer` + +Whilst both of these functions share underlying technologies and code they will have slightly differening roadmaps. + +### HA Kubernetes Control Plane + +- **Re-implememt LoadBalancing** - due to a previous request the HTTP loadbalancing was removed leaving just HA for the control plane. This functionality will be re-implemented either through the original round-robin HTTP requests or utilising IPVS. +- **Utilise the Kubernetes API to determine additional Control Plane members** - Once a single node cluster is running **kube-vip** could use the API to determine the additional members, at this time a Cluster-API provider needs to drop a static manifest per CP node. +- **Re-evaluate raft** - **kube-vip** is mainly designed to run within a Kubernetes cluster, however it's original design was a raft cluster external to Kubernetes. Unfortunately given some of the upgrade paths identified in things like CAPV moving to leaderElection within Kubernetes became a better idea. + +## Kubernetes `service type:LoadBalancer` + +- **`ARP` LeaderElection per loadBalancer** - Currently only one pod that is elected leader will field all traffic for a VIP.. extending this to generate a leaderElection token per service would allow services to proliferate across all pods across the cluster +- **Aligning of `service` and `manager`** - The move to allow hybrid (be both HA control plane and offer load-balancer services at the same time) introduced a duplicate code path.. these need to converge as it's currently confusing for contributors. + +## Global **Kube-Vip** items + +- **Improved metrics** - At this time the scaffolding for monitoring exists, however this needs drastically extending to provide greater observability to what is happening within **kube-vip** +- **Windows support** - The Go SDK didn't support the capability for low-levels sockets for ARP originally, this should be revisted. +- **Additional BGP features** : + - Communities + - BFD From 79f0fb9283c767eb174bb0ae31ab6d121cd6a995 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 14 May 2021 12:55:21 +0100 Subject: [PATCH 105/542] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 128 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..fe8c1ee4 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +conduct@kube-vip.io. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. From 94e8984ed1c5d53d5e4e89b3b2d37a7183d968e1 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 14 May 2021 14:07:37 +0100 Subject: [PATCH 106/542] Create CONTRIBUTING.md --- CONTRIBUTING.md | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..cdd706d7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,289 @@ +# Developer Guide + +Thank you for taking the time out to contribute to the **kube-vip** project! + +This guide will walk you through the process of making your first commit and how +to effectively get it merged upstream. + + +- [Getting Started](#getting-started) +- [Contribute](#contribute) + - [GitHub Workflow](#github-workflow) + - [Getting reviewers](#getting-reviewers) + - [Inclusive Naming](#inclusive-naming) + - [Building and testing your change](#building-and-testing-your-change) + - [Reverting a commit](#reverting-a-commit) + - [Sign-off Your Work](#sign-off-your-work) +- [Issue and PR Management](#issue-and-pr-management) + - [Filing An Issue](#filing-an-issue) + - [Issue Triage](#issue-triage) + + +## Getting Started + +To get started, let's ensure you have completed the following prerequisites for +contributing to project **kube-vip**: + +1. Read and observe the [code of conduct](CODE_OF_CONDUCT.md). +2. Check out the [Architecture documentation](https://kube-vip.io) for the **kube-vip** + architecture and design. +3. Set up your [development environment](docs/contributors/manual-installation.md) + +Now that you're setup, skip ahead to learn how to [contribute](#contribute). + +**Also**, A GitHub account will be required in order to submit code changes and +interact with the project. For committing any changes in **Github** it is required for +you to have a [github account](https://github.com/join). + +## Contribute + +There are multiple ways in which you can contribute, either by contributing +code in the form of new features or bug-fixes or non-code contributions like +helping with code reviews, triaging of bugs, documentation updates, filing +[new issues](#filing-an-issue) or writing blogs/manuals etc. + +### GitHub Workflow + +Developers work in their own forked copy of the repository and when ready, +submit pull requests to have their changes considered and merged into the +project's repository. + +1. Fork your own copy of the repository to your GitHub account by clicking on + `Fork` button on [kube-vip's GitHub repository](https://github.com/kube-vip/kube-vip). +2. Clone the forked repository on your local setup. + + ```bash + git clone https://github.com/$user/kube-vip + ``` + + Add a remote upstream to track upstream kube-vip repository. + + ```bash + git remote add upstream https://github.com/kube-vip/kube-vip + ``` + + Never push to upstream remote + + ```bash + git remote set-url --push upstream no_push + ``` + +3. Create a topic branch. + + ```bash + git checkout -b branchName + ``` + +4. Make changes and commit it locally. Make sure that your commit is + [signed](#sign-off-your-work). + + ```bash + git add + git commit -s + ``` + +5. Update the "Unreleased" section of the [CHANGELOG](CHANGELOG.md) for any + significant change that impacts users. +6. Keeping branch in sync with upstream. + + ```bash + git checkout branchName + git fetch upstream + git rebase upstream/main + ``` + +7. Push local branch to your forked repository. + + ```bash + git push -f $remoteBranchName branchName + ``` + +8. Create a Pull request on GitHub. + Visit your fork at `https://github.com/kube-vip/kube-vip` and click + `Compare & Pull Request` button next to your `remoteBranchName` branch. + +### Getting reviewers + +Once you have opened a Pull Request (PR), reviewers will be assigned to your +PR and they may provide review comments which you need to address. +Commit changes made in response to review comments to the same branch on your +fork. Once a PR is ready to merge, squash any *fix review feedback, typo* +and *merged* sorts of commits. + +To make it easier for reviewers to review your PR, consider the following: + +1. Follow the golang [coding conventions](https://github.com/golang/go/wiki/CodeReviewComments). +2. Format your code with `make golangci-fix`; if the [linters](ci/README.md) flag an issue that + cannot be fixed automatically, an error message will be displayed so you can address the issue. +3. Follow [git commit](https://chris.beams.io/posts/git-commit/) guidelines. +4. Follow [logging](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md) guidelines. + +If your PR fixes a bug or implements a new feature, add the appropriate test +cases to our [automated test suite](ci/README.md) to guarantee enough +coverage. A PR that makes significant code changes without contributing new test +cases will be flagged by reviewers and will not be accepted. + +### Inclusive Naming + +For symbol names and documentation, do not introduce new usage of harmful +language such as 'master / slave' (or 'slave' independent of 'master') and +'blacklist / whitelist'. For more information about what constitutes harmful +language and for a reference word replacement list, please refer to the +[Inclusive Naming Initiative](https://inclusivenaming.org/). + +We are committed to removing all harmful language from the project. If you +detect existing usage of harmful language in code or documentation, please +report the issue to us or open a Pull Request to address it directly. Thanks! + +### Building and testing your change + +To build the **kube-vip** Docker image together with all **kube-vip** bits, you can simply +do: + +1. Checkout your feature branch and `cd` into it. +2. Run `make dockerx86` + +The second step will compile the **kube-vip** code in a `golang` container, and build +a `Ubuntu 20.04` Docker image that includes all the generated binaries. [`Docker`](https://docs.docker.com/install) +must be installed on your local machine in advance. + +Alternatively, you can build the **kube-vip** code in your local Go environment. The +**kube-vip** project uses the [Go modules support](https://github.com/golang/go/wiki/Modules) which was introduced in Go 1.11. It +facilitates dependency tracking and no longer requires projects to live inside +the `$GOPATH`. + +To develop locally, you can follow these steps: + + 1. [Install Go 1.15](https://golang.org/doc/install) + 2. Checkout your feature branch and `cd` into it. + 3. To build all Go files and install them under `bin`, run `make bin` + 4. To run all Go unit tests, run `make test-unit` + 5. To build the **kube-vip** Ubuntu Docker image separately with the binaries generated in step 2, run `make ubuntu` + +### CI testing + +For more information about the tests we run as part of CI, please refer to +[ci/README.md](ci/README.md). + +### Reverting a commit + +1. Create a branch in your forked repo + + ```bash + git checkout -b revertName + ``` + +2. Sync the branch with upstream + + ```bash + git fetch upstream + git rebase upstream/main + ``` + +3. Create a revert based on the SHA of the commit. The commit needs to be + [signed](#sign-off-your-work). + + ```bash + git revert -s SHA + ``` + +4. Push this new commit. + + ```bash + git push $remoteRevertName revertName + ``` + +5. Create a Pull Request on GitHub. + Visit your fork at `https://github.com/kube-vip/kube-vip` and click + `Compare & Pull Request` button next to your `remoteRevertName` branch. + +### Sign-off Your Work + +It is recommended to sign your work when contributing to the **kube-vip** +repository. + +Git provides the `-s` command-line option to append the required line +automatically to the commit message: + +```bash +git commit -s -m 'This is my commit message' +``` + +For an existing commit, you can also use this option with `--amend`: + +```bash +git commit -s --amend +``` + +If more than one person works on something it's possible for more than one +person to sign-off on it. For example: + +```bash +Signed-off-by: Some Developer somedev@example.com +Signed-off-by: Another Developer anotherdev@example.com +``` + +We use the [DCO Github App](https://github.com/apps/dco) to enforce that all +commits in a Pull Request include the required `Signed-off-by` line. If this is +not the case, the app will report a failed status for the Pull Request and it +will be blocked from being merged. + +Compared to our earlier CLA, DCO tends to make the experience simpler for new +contributors. If you are contributing as an employee, there is no need for your +employer to sign anything; the DCO assumes you are authorized to submit +contributions (it's your responsibility to check with your employer). + +## Issue and PR Management + +We use labels and workflows (some manual, some automated with GitHub Actions) to +help us manage triage, prioritize, and track issue progress. For a detailed +discussion, see [docs/issue-management.md](docs/contributors/issue-management.md). + +### Filing An Issue + +Help is always appreciated. If you find something that needs fixing, please file +an issue [here](https://github.com/kube-vip/kube-vip/issues). Please ensure +that the issue is self explanatory and has enough information for an assignee to +get started. + +Before picking up a task, go through the existing +[issues](https://github.com/kube-vip/kube-vip/issues) and make sure that your +change is not already being worked on. If it does not exist, please create a new +issue and discuss it with other members. + +For simple contributions to **kube-vip**, please ensure that this minimum set of +labels are included on your issue: + +* **kind** -- common ones are `kind/feature`, `kind/support`, `kind/bug`, + `kind/documentation`, or `kind/design`. For an overview of the different types + of issues that can be submitted, see [Issue and PR + Kinds](#issue-and-pr-kinds). + The kind of issue will determine the issue workflow. +* **area** (optional) -- if you know the area the issue belongs in, you can assign it. + Otherwise, another community member will label the issue during triage. The + area label will identify the area of interest an issue or PR belongs in and + will ensure the appropriate reviewers shepherd the issue or PR through to its + closure. For an overview of areas, see the + [`docs/github-labels.md`](docs/contributors/github-labels.md). +* **size** (optional) -- if you have an idea of the size (lines of code, complexity, + effort) of the issue, you can label it using a [size label](#size). The size + can be updated during backlog grooming by contributors. This estimate is used + to guide the number of features selected for a milestone. + +All other labels will be assigned during issue triage. + +### Issue Triage + +Once an issue has been submitted, the CI (GitHub actions) or a human will +automatically review the submitted issue or PR to ensure that it has all relevant +information. If information is lacking or there is another problem with the +submitted issue, an appropriate `triage/` label will be applied. + +After an issue has been triaged, the maintainers can prioritize the issue with +an appropriate `priority/` label. + +Once an issue has been submitted, categorized, triaged, and prioritized it +is marked as `ready-to-work`. A ready-to-work issue should have labels +indicating assigned areas, prioritization, and should not have any remaining +triage labels. + From 2f0e1eec47243c5383856eaf0ca865f64b80c35b Mon Sep 17 00:00:00 2001 From: Taha Ozket Date: Sat, 15 May 2021 19:29:26 +0300 Subject: [PATCH 107/542] Update kube-vip.go typo fixed metalrojectID -> metalProjectID --- cmd/kube-vip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 270c311b..11259b56 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -89,7 +89,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableMetal, "metal", false, "This will use the Equinix Metal API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalAPIKey, "metalKey", "", "The API token for authenticating with the Equinix Metal API") kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProject, "metalProject", "", "The name of project already created within Equinix Metal") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProjectID, "metalrojectID", "", "The ID of project already created within Equinix Metal") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProjectID, "metalProjectID", "", "The ID of project already created within Equinix Metal") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // Load Balancer flags From a9286fd8c3af1adf296eae07048be30f3e4282a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=97=AA=D1=94=CE=BD=CE=B9=CE=B7=20=E1=97=B7=CF=85=D0=BD?= =?UTF-8?q?=CA=9F?= Date: Fri, 28 May 2021 07:59:22 -0400 Subject: [PATCH 108/542] feat: push images to ghcr --- .github/workflows/release.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e24ef4f9..894955ed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,8 +16,8 @@ jobs: run: | DOCKER_IMAGE=plndr/kube-vip VERSION=${GITHUB_REF#refs/tags/} - TAGS="${DOCKER_IMAGE}:${VERSION}" - TAGS="$TAGS,${DOCKER_IMAGE}:latest" + TAGS="${DOCKER_IMAGE}:${VERSION},ghcr.io/kube-vip/kube-vip:${VERSION}" + TAGS="$TAGS,${DOCKER_IMAGE}:latest,ghcr.io/kube-vip/kube-vip:latest" echo ::set-output name=tags::${TAGS} - name: Set up QEMU @@ -29,6 +29,12 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Github Packages + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push main branch uses: docker/build-push-action@v2 From aa39904040815d0d41efc11a1c085323e322f70f Mon Sep 17 00:00:00 2001 From: Sam McGeown Date: Thu, 17 Jun 2021 14:15:38 +0100 Subject: [PATCH 109/542] Update CCM controller manifest to match kube-vip-cloud-controller repository --- docs/manifests/controller.yaml | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/manifests/controller.yaml b/docs/manifests/controller.yaml index ba081c12..c5add884 100644 --- a/docs/manifests/controller.yaml +++ b/docs/manifests/controller.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: plunder-cloud-controller + name: kube-vip-cloud-controller namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 @@ -9,10 +9,13 @@ kind: ClusterRole metadata: annotations: rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:plunder-cloud-controller-role + name: system:kube-vip-cloud-controller-role rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update", "list", "put"] - apiGroups: [""] - resources: ["configmaps", "endpoints","events","services/status"] + resources: ["configmaps", "endpoints","events","services/status", "leases"] verbs: ["*"] - apiGroups: [""] resources: ["nodes", "services"] @@ -21,42 +24,42 @@ rules: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: system:plunder-cloud-controller-binding + name: system:kube-vip-cloud-controller-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: system:plunder-cloud-controller-role + name: system:kube-vip-cloud-controller-role subjects: - kind: ServiceAccount - name: plunder-cloud-controller + name: kube-vip-cloud-controller namespace: kube-system --- apiVersion: apps/v1 kind: StatefulSet metadata: - name: plndr-cloud-provider + name: kube-vip-cloud-provider namespace: kube-system spec: - serviceName: plndr-cloud-provider + serviceName: kube-vip-cloud-provider podManagementPolicy: OrderedReady replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: kube-vip - component: plndr-cloud-provider + component: kube-vip-cloud-provider template: metadata: labels: app: kube-vip - component: plndr-cloud-provider + component: kube-vip-cloud-provider spec: containers: - command: - - /plndr-cloud-provider - - --leader-elect-resource-name=plndr-cloud-controller - image: plndr/plndr-cloud-provider:0.1.5 - name: plndr-cloud-provider + - /kube-vip-cloud-provider + - --leader-elect-resource-name=kube-vip-cloud-controller + image: kubevip/kube-vip-cloud-provider:latest + name: kube-vip-cloud-provider imagePullPolicy: Always resources: {} dnsPolicy: ClusterFirst @@ -64,4 +67,4 @@ spec: schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 - serviceAccountName: plunder-cloud-controller \ No newline at end of file + serviceAccountName: kube-vip-cloud-controller From 98803b4d748f317033fd985d85aa25095862b3ba Mon Sep 17 00:00:00 2001 From: Sam McGeown Date: Thu, 17 Jun 2021 15:17:52 +0100 Subject: [PATCH 110/542] Update kube-vip services docs with latest kube-vip details --- docs/hybrid/services/index.md | 123 ++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 34 deletions(-) diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index 09045b46..f609b929 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -17,75 +17,95 @@ This section details the flow of events in order for `kube-vip` to advertise a K ## CCM -We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for exist CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. +We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. -The below instructions *should just work* on Kubernetes regardless of architecture, Linux as the Operating System is the only requirement. -## Using the Plunder Cloud Provider (CCM) +## Using the Kube-vip Cloud Provider -If you just want things to "work", then you can quickly install the "latest" components: +The below instructions *should just work* on Kubernetes regardless of architecture (Linux Operating System is the only requirement) - you can quickly install the "latest" components: -**Install the `plndr-cloud-provider` +**Install the `kube-vip-cloud-provider`** ``` -kubectl apply -f https://kube-vip.io/manifests/controller.yaml +$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml ``` -**Create the `cidr` for the `global` namespace** +It uses a `statefulSet` and can always be viewed with the following command: ``` -kubectl create configmap --namespace kube-system plndr --from-literal cidr-global=192.168.0.200/29 +kubectl describe pods -n kube-system kube-vip-cloud-provider-0 ``` -Creating services of `type: LoadBalancer` in the default namespace will now take addresses from the **global** cidr defined in the `configmap`. +**Create a global CIDR or IP Range** -**Additional namespaces** +Any `service` in any `namespace` can use an address from the global CIDR `cidr-global` or range `range-global` + +``` +kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29 +``` +or +``` +kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 +``` + +Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific -Edit the `configmap` and add in the cidr ranges for those namespaces, the key in the cidr should be `cidr-`, then ensure that `kube-vip` is deployed into that namespac -e with the above `apply` command with the `-n namespace` flag. ## The Detailed guide -### Deploy the `plndr-cloud-provider` +### Deploy the Kube-vip Cloud Provider -To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/controller.yaml`, specific versions should be found in the repository as detailed below: +**Install the `kube-vip-cloud-provider`** -From the GitHub repository [https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod](https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/p -od), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Githu -b will provide the url that can be applied directly with a `kubectl apply -f `. +``` +$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +``` The following output should appear when the manifest is applied: ``` -serviceaccount/plunder-cloud-controller created -clusterrole.rbac.authorization.k8s.io/system:plunder-cloud-controller-role created -clusterrolebinding.rbac.authorization.k8s.io/system:plunder-cloud-controller-binding created -pod/plndr-cloud-provider created +serviceaccount/kube-vip-cloud-controller created +clusterrole.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-role created +clusterrolebinding.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-binding created +statefulset.apps/kube-vip-cloud-provider created ``` -We can validate the cloud-provider by examining the pods: +We can validate the cloud provider by examining the pods and following the logs: -`kubectl logs -n kube-system plndr-cloud-provider-0 -f` +``` +kubectl describe pods -n kube-system kube-vip-cloud-provider-0 +kubectl logs -n kube-system kube-vip-cloud-provider-0 -f +``` -#### The `plndr-cloud-provider` `configmap` +### The Kube-vip Cloud Provider `configmap` -The `configmap` details a CIDR range *per* namespace, however as of (`kube-vip 0.2.1` and `plnder-cloud-provider 0.1.4`), there is now the option of having a **global** CIDR rang -e (`cidr-global)`. +To manage the IP address ranges for the load balancer instances the `kube-vip-cloud-provider` uses a `configmap` held in the `kube-system` namespace. IP address ranges can be configured using: +- IP address pools by CIDR +- IP ranges [start address - end address] +- Multiple pools by CIDR per namespace +- Multiple IP ranges per namespace (handles overlapping ranges) +- Setting of static addresses through --load-balancer-ip=x.x.x.x -To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within th -e `configmap` should be that the key is in the format `cidr-` and the value should be the cidr range. +To control which IP address range is used for which service the following rules are applied: +- Global address pools (`cidr-global` or `range-global`) are available for use by *any* `service` in *any* `namespace` +- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by `service` in the *specific* `namespace` +- Static IP addresses can be applied to a load balancer `service` using the `loadbalancerIP` setting, even outside of the assigned ranges Example Configmap: ``` +$ kubectl get configmap -n kube-system kubevip -o yaml + apiVersion: v1 kind: ConfigMap metadata: - name: plndr + name: kubevip namespace: kube-system data: - cidr-default: 192.168.0.200/29 - cidr-global: 192.168.0.210/29 + cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default namespace + range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development namespace + cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance namespace + cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any namespace ``` ### Expose a service @@ -96,20 +116,55 @@ We can now expose a service and once the cloud provider has provided an address kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx ``` +or via a `service` YAML definition + +``` +apiVersion: v1 +kind: Service +metadata: + name: nginx +spec: + ports: + - name: http + port: 80 + protocol: TCP + selector: + app: nginx + type: LoadBalancer + ``` + + We can also expose a specific address by specifying it on the command line: ``` kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 ``` +or including it in the `service` definition: + +``` +apiVersion: v1 +kind: Service +metadata: + name: nginx +spec: + ports: + - name: http + port: 80 + protocol: TCP + selector: + app: nginx + type: LoadBalancer + loadBalancerIP: "1.1.1.1" +``` + ### Using DHCP for Load Balancers (experimental) With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a Kubernetes service on the network. In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the -address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it wi -ll assign it as the VIP and update the Kubernetes service! +address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! ``` $ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc @@ -166,7 +221,7 @@ $ curl externalIP:32380 ... ``` -### Expose with Equinix Metal (using the `plndr-cloud-provider`) +### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! From 6e2495b9a104b7a6ed6ba51351d65965fdbeaa92 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 18 Jun 2021 14:13:29 +0100 Subject: [PATCH 111/542] Fixes manifest generation --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 003646fa..ed5284c0 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := 0.3.4 +VERSION := v0.3.5 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From b24723ea7a753dbc2cd19ade53b693f44ea85755 Mon Sep 17 00:00:00 2001 From: David McKay Date: Thu, 24 Jun 2021 16:28:25 +0100 Subject: [PATCH 112/542] fix: propagate errors when broadcasting BGP address fails --- pkg/bgp/hosts.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/bgp/hosts.go b/pkg/bgp/hosts.go index 5d78b3b9..8952d168 100644 --- a/pkg/bgp/hosts.go +++ b/pkg/bgp/hosts.go @@ -2,6 +2,7 @@ package bgp import ( "context" + "fmt" "net" api "github.com/osrg/gobgp/api" @@ -13,15 +14,20 @@ func (b *Server) AddHost(addr string) (err error) { if err != nil { return err } + p := b.getPath(ip) if p == nil { - return err + return fmt.Errorf("failed to get path for %v", ip) } _, err = b.s.AddPath(context.Background(), &api.AddPathRequest{ Path: p, }) + if err != nil { + return err + } + return } From 9273a7d9e401415dbcbd639f39cd5f9afe5c5bd2 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 5 Jul 2021 13:38:40 +0100 Subject: [PATCH 113/542] Fixes the hang on BGP password --- Dockerfile | 2 +- pkg/manager/watcher.go | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 74a9e456..e0bd4137 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.15-alpine as dev +FROM golang:1.16.5-alpine3.13 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 8f634e90..957245f5 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -109,7 +109,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { // present func (sm *Manager) annotationsWatcher() error { // Use a restartable watcher, as this should help in the event of etcd or timeout issues - log.Infoln("Kube-Vip is waiting for annotations to be present on this node") + log.Infof("Kube-Vip is waiting for annotation prefix [%s] to be present on this node", sm.config.Annotations) hostname, err := os.Hostname() if err != nil { return err @@ -168,19 +168,7 @@ func (sm *Manager) annotationsWatcher() error { continue } - // Peer configuration - - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] - if base64BGPPassword != "" { - // Decode base64 encoded string - decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) - if err != nil { - return err - } - sm.config.BGPPeerConfig.Password = string(decodedPassword) - } else { - continue - } + // Peer configuration [REQUIRED] peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] if peerASN != "" { u64, err := strconv.ParseUint(peerASN, 10, 32) @@ -205,7 +193,18 @@ func (sm *Manager) annotationsWatcher() error { } } - log.Debugf("%s / %d / %s / %d \n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) + // BGP Password, if it doesn't find a password don't "continue" [OPTIONAL] + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] + if base64BGPPassword != "" { + // Decode base64 encoded string + decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) + if err != nil { + return err + } + sm.config.BGPPeerConfig.Password = string(decodedPassword) + } + + log.Debugf("%s / %d / %s / %d /n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) rw.Stop() break From f19deede302beff1a373db47177ea29aa090c645 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 6 Jul 2021 13:12:48 +0100 Subject: [PATCH 114/542] Big docs re-org --- docs/Dockerfile | 5 + docs/flags/index.md | 84 +++++++++++ docs/index.md | 73 ++++++++++ docs/index/index.md | 27 ---- docs/install_daemonset/index.md | 140 ++++++++++++++++++ docs/install_static/index.md | 75 ++++++++++ docs/k3s | 61 ++++++++ docs/{index => }/kube-vip.png | Bin docs/usage/EquinixMetal/index.md | 99 +++++++++++++ docs/usage/k3s/index.md | 82 +++++++++++ docs/usage/on-prem/index.md | 237 +++++++++++++++++++++++++++++++ 11 files changed, 856 insertions(+), 27 deletions(-) create mode 100644 docs/Dockerfile create mode 100644 docs/flags/index.md create mode 100644 docs/index.md delete mode 100644 docs/index/index.md create mode 100644 docs/install_daemonset/index.md create mode 100644 docs/install_static/index.md create mode 100644 docs/k3s rename docs/{index => }/kube-vip.png (100%) create mode 100644 docs/usage/EquinixMetal/index.md create mode 100644 docs/usage/k3s/index.md create mode 100644 docs/usage/on-prem/index.md diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 00000000..fb92fcf1 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,5 @@ +FROM nginx:latest +RUN apt-get update; apt-get install -y nodejs npm; npm install -g markdown-styles; +COPY . /docs +WORKDIR /docs +RUN generate-md --layout github --input ./ --output /usr/share/nginx/html/ diff --git a/docs/flags/index.md b/docs/flags/index.md new file mode 100644 index 00000000..07a71383 --- /dev/null +++ b/docs/flags/index.md @@ -0,0 +1,84 @@ +# Kube-Vip Flag / Environment Variable reference + +## Flags + +These flags are typically used in manifest generation. + +| Category | Flag | Usage | Notes | +|--------------|------|-------|-------| +|**Mode** |||| +| |`--controlPlane`|Enables `kube-vip` control-plane functionality|| +| |`--services`|Enables `kube-vip` to watch services of type:LoadBalancer|| +|**Vip Config** |||| +| |`--arp`|Enables ARP brodcasts from Leader|| +| |`--bgp`|Enables BGP peering from `kube-vip`|| +| |`--vip`|``|(deprecated)| +| |`--address`|`` or ``|| +| |`--interface`|``|| +| |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| +|**Services**|||| +| |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| +|**Kubernetes**|||| +| |`--inCluster`|Defaults to looking inside the Pod for the token|| +| |`--taint`|Enables a taint, stopping control plane daemonset being on workers|| +|**LeaderElection**|||| +| |`--leaseDuration`|default 5|Seconds a lease is held for| +| |`--leaseRenewDuration`|default 3|Seconds a leader can attempt to renew the lease| +| |`--leaseRetry`|default 1|Number of times the leader will hold the lease for| +| |`--namespace`|"kube-vip"|The namespace where the lease will reside| +|**BGP**|||| +| |`--bgpRouterID`|``|Typically the address of the local node| +| |`--localAS`|default 65000|The AS we peer from| +| |`--bgppeers`|``|Comma seperate list of BGP peers| +| |`--peerAddress`|``|Address of a single BGP Peer| +| |`--peerAS`|default 65000|AS of a single BGP Peer| +| |`--peerPass`|""| Password to work with a single BGP Peer| +| |`--multiHop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| +| |`--annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| +|**Equinix Metal**|||(May be deprecated)| +| |`--metal`|Enables Equinix Metal API calls|| +| |`--metalKey`|Equinix Metal API token|| +| |`--metalProject`|Equinix Metal Project (Name)|| +| |`--metalProjectID`|Equinix Metal Project (UUID)|| +| |`--provider-config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| + +## Environment Variables + +These environment variables are usually part of a kube-vip manifest. + +More environment variables can be read through the `pkg/kubevip/config_envvar.go` file. + +| Category | Environment Variable | Usage | Notes | +|--------------|------|-------|-------| +|**Mode** |||| +| |`cp_enable`|Enables `kube-vip` control-plane functionality|| +| |`svc_enable`|Enables `kube-vip` to watch services of `type:LoadBalancer`|| +|**Vip Config** |||| +| |`vip_arp`|Enables ARP brodcasts from Leader|| +| |`bgp_enable`|Enables BGP peering from `kube-vip`|| +| |`vip_address`|``|(deprecated)| +| |`address`|`` or ``|| +| |`vip_interface`|``|| +| |`vip_leaderelection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| +|**Services**|||| +| |`vip_cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| +|**LeaderElection**|||| +| |`vip_leaseduration`|default 5|Seconds a lease is held for| +| |`vip_renewdeadline`|default 3|Seconds a leader can attempt to renew the lease| +| |`vip_retryperiod`|default 1|Number of times the leader will hold the lease for| +| |`cp_namespace`|"kube-vip"|The namespace where the lease will reside| +|**BGP**|||| +| |`bgp_routerid`|``|Typically the address of the local node| +| |`bgp_as`|default 65000|The AS we peer from| +| |`bgp_peers`|``|Comma seperate list of BGP peers| +| |`bgp_peeraddress`|``|Address of a single BGP Peer| +| |`bgp_peeras`|default 65000|AS of a single BGP Peer| +| |`bgp_peerpass`|""| Password to work with a single BGP Peer| +| |`bgp_multihop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| +| |`annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| +|**Equinix Metal**|||(May be deprecated)| +| |`vip_packet`|Enables Equinix Metal API calls|| +| |`PACKET_AUTH_TOKEN`|Equinix Metal API token|| +| |`vip_packetproject`|Equinix Metal Project (Name)|| +| |`vip_packetprojectid`|Equinix Metal Project (UUID)|| +| |`provider_config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..dcdbdd8f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,73 @@ +# Kube-vip + +![kube-vip.png](kube-vip.png) + +## Overview +Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services + +The idea behind `kube-vip` is a small self-contained Highly-Available option for all environments, especially: + +- Bare-Metal +- On-Prem +- Edge (ARM / Raspberry PI) +- Virtualisation +- Pretty much anywhere else :) + +## Features + +Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). + +- VIP addresses can be both IPv4 or IPv6 +- Control Plane with ARP (Layer 2) or BGP (Layer 3) +- Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) +- Control Plane HA with kubeadm (static Pods) +- Control Plane HA with K3s/and others (daemonsets) +- Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2) +- Service LoadBalancer using multiple nodes with BGP +- Service LoadBalancer address pools per namespace or global +- Service LoadBalancer address via (existing network DHCP) +- Service LoadBalancer address exposure to gateway via UPNP +- ... manifest generation, vendor API integrations and many nore... + +## Why? + +The "original" purpose of `kube-vip` was to simplify the building of HA Kubernetes clusters, which at this time can involve a few components and configurations that all need to be managed. This was blogged about in detail by [thebsdbox](https://twitter.com/thebsdbox/) here -> [https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing](https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing). As the project evolved it now can use those same technologies to provide load-balancing capabilities within a Kubernetes Cluster. + + +## Architecture + +The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) + +## Installation + +There are two main routes for deploying `kube-vip`, either through a [static pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [daemon set](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [k3s](https://k3s.io)). + +The infrastructure for our example HA Kubernetes cluster is as follows: + +| Node | Address | +|----------------|------------| +| VIP | 10.0.0.40 | +| controlPlane01 | 10.0.0.41 | +| controlPlane02 | 10.0.0.42 | +| controlPlane03 | 10.0.0.43 | +| worker01 | 10.0.0.44 | + +All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we only have one worker as we're going to use our controlPlanes in "hybrid" mode. + +- [Static Pod](/install_static) +- [Daemon Set](/install_daemonset) + +## Usage + +- [On-Prem with the kube-vip cloud controller](/usage/on-prem) +- [Equinix Metal](/usage/EquinixMetal) +- [k3s](/usage/k3s) + +## Flags/Environment Variables + +- [Flags and Environment variables](/flags/) + +## Links + +- The Kube-Vip Cloud Provider Repository -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) +- The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) \ No newline at end of file diff --git a/docs/index/index.md b/docs/index/index.md deleted file mode 100644 index d09a3d66..00000000 --- a/docs/index/index.md +++ /dev/null @@ -1,27 +0,0 @@ -# Kube-vip - -The **kube-vip** project provides High-Availability and load-balancing for both **inside** and **outside** a Kubernetes cluster - -![kube-vip.png](kube-vip.png) - -## Architecture - -The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) - - -## (New) Hybrid Control-plane HA and Kubernetes service `type=LoadBalancer` - -With the newest release of `kube-vip` the internal "manager" can handle the lifecycle of VIPs for both HA and for Kubernetes Load-Balancing. The main driver for this is being most effective for large nodes that can run control-plane components and run applications. The details for hybrid mode are [here](/hybrid/) - -## (Legacy) Control-plane load balancer - -The details are [here](/control-plane/) - -## (Legacy) Kubernetes service `"type: LoadBalancer"` - -The details are [here](/kubernetes/) - -## GitHub Repositories - -- The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) -- The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) \ No newline at end of file diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md new file mode 100644 index 00000000..1eb5d8a1 --- /dev/null +++ b/docs/install_daemonset/index.md @@ -0,0 +1,140 @@ +# Kube-Vip as a daemonset + +## Daemonset + +Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a daemonset for all control plane nodes. + +If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. + +## Kube-Vip as **HA**, **Load-Balancer** or both ` ¯\_(ツ)_/¯` + +When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. + +With both enabled `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. + +**Note about Daemonsets** + +Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. + +## Create the RBAC settings + +As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` + +## Generating a Manifest + +This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). + +**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `daemonset` and NOT `pod`. + +### Set configuration details + +`export VIP=192.168.0.40` + +`export INTERFACE=` + +### Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +#### containerd +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip"` + +#### Docker +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` + +### BGP Example + +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. + +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. + +**Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. + +**Note 2** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. + +`export INTERFACE=lo` + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --vip $VIP \ + --controlplane \ + --services \ + --inCluster \ + --taint \ + --bgp \ + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false +``` + +### Generated Manifest + +``` +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: lo + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: svc_enable + value: "true" + - name: bgp_enable + value: "true" + - name: bgp_peers + value: "192.168.0.10:65000::false,192.168.0.11:65000::false" + - name: vip_address + value: 192.168.0.40 + image: plndr/kube-vip:0.2.3 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + nodeSelector: + node-role.kubernetes.io/master: "true" + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + updateStrategy: {} +``` + +### Manifest Overview + +- `nodeSelector` - Ensures that this particular daemonset only runs on control plane nodes +- `serviceAccountName: kube-vip` - this specifies the user in the `rbac` that will give us the permissions to get/update services. +- `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) +- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. diff --git a/docs/install_static/index.md b/docs/install_static/index.md new file mode 100644 index 00000000..a1ba64e6 --- /dev/null +++ b/docs/install_static/index.md @@ -0,0 +1,75 @@ +# Kube-vip as a Static Pod + +## Static Pods + +Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. + +The sequence of events for this to work follows: +1. Generate a `kube-vip` manifest in the static pods manifest folder +2. Run `kubeadm init`, this generates the manifests for the control plane and wait to connect to the VIP +3. The `kubelet` will parse and execute all manifest, including the `kube-vip` manifest +4. `kube-vip` starts and advertises our VIP +5. The `kubeadm init` finishes succesfully. + +## Kube-Vip as **HA**, **Load-Balancer** or both ` ¯\_(ツ)_/¯` + +When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. + +With both enabled `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. + +## Generating a Manifest + +This section details creating a number of manifests for various use cases + +### Set configuration details + +`export VIP=192.168.0.40` + +`export INTERFACE=` + +## Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +### containerd +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` + +### Docker +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` + + +## ARP + +This configuration will create a manifest that starts `kube-vip` providing **controlplane** and **services** management, using **leaderElection**. When this instance is elected as the leader it will bind the `vip` to the specified `interface`, this is also the same for services of `type:LoadBalancer`. + +`export INTERFACE=eth0` + +``` +kube-vip manifest pod \ + --interface $INTERFACE \ + --vip $VIP \ + --controlplane \ + --services \ + --arp \ + --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +## BGP + +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. + +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. + +`export INTERFACE=lo` + +``` +kube-vip manifest pod \ + --interface $INTERFACE \ + --vip $VIP \ + --controlplane \ + --services \ + --bgp \ + --localAS 65000 \ + --bgpRouterID 192.168.0.2 \ + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml +``` \ No newline at end of file diff --git a/docs/k3s b/docs/k3s new file mode 100644 index 00000000..477a695d --- /dev/null +++ b/docs/k3s @@ -0,0 +1,61 @@ +#!/bin/bash + +echo "apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: \"true\" + - name: vip_interface + value: $vipInterface + - name: port + value: \"6443\" + - name: vip_cidr + value: \"32\" + - name: cp_enable + value: \"true\" + - name: cp_namespace + value: kube-system + - name: svc_enable + value: \"false\" + - name: vip_address + value: $vipAddress + image: plndr/kube-vip:v0.3.5 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + nodeSelector: + node-role.kubernetes.io/master: \"true\" + serviceAccountName: kube-vip + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0" \ No newline at end of file diff --git a/docs/index/kube-vip.png b/docs/kube-vip.png similarity index 100% rename from docs/index/kube-vip.png rename to docs/kube-vip.png diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md new file mode 100644 index 00000000..a3c96d20 --- /dev/null +++ b/docs/usage/EquinixMetal/index.md @@ -0,0 +1,99 @@ +# Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) + +## BGP with Equinix Metal + +When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). + +**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. + +## Creating HA clusters in Equinix Metal + +### Creating a manifest using the API + +We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. + +``` +kube-vip manifest pod \ + --interface $INTERFACE\ + --vip $VIP \ + --controlplane \ + --services \ + --bgp \ + --metal \ + --metalKey xxxxxxx \ + --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +### Creating a manifest using the metadata + +We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. + +``` +kube-vip manifest pod \ + --interface $INTERFACE\ + --vip $VIP \ + --controlplane \ + --services \ + --bgp \ + --peerAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].peer_as') \ + --peerAddress $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].peer_ips[0]') \ + --localAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].customer_as') \ + --bgpRouterID $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].customer_ip') | sudo tee /etc/kubernetes/manifests/vip.yaml +``` + +## Load Balancing servies on Equinix Metal + +Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. + +**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. + +### Using Annotations + +This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --services \ + --bgp \ + --annotations metal.equinix.com \ + --inCluster | k apply -f - +``` + +### Using the existing CCM secret + +Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. + +``` +kube-vip manifest daemonset --interface $INTERFACE \ +--services \ +--inCluster \ +--bgp \ +--metal \ +--provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - +``` + +## Troubleshooting + +If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node: + +``` +kubectl describe node k8s.bgp02 +... +Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock + node.alpha.kubernetes.io/ttl: 0 + metal.equinix.com/node-asn: 65000 + metal.equinix.com/peer-asn: 65530 + metal.equinix.com/peer-ip: x.x.x.x + metal.equinix.com/src-ip: x.x.x.x +``` + +If there are errors regarding `169.254.255.1` or `169.254.255.2` in the `kube-vip` logs then the routes to the ToR switches that provide BGP peering may by missing from the nodes. They can be replaced with the below command: + +``` +GATEWAY_IP=$(curl https://metadata.platformequinix.com/metadata | jq -r ".network.addresses[] | select(.public == false) | .gateway") +ip route add 169.254.255.1 via $GATEWAY_IP +ip route add 169.254.255.2 via $GATEWAY_IP +``` + +Additionally examining the logs of the Packet CCM may reveal why the node is not yet ready. \ No newline at end of file diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md new file mode 100644 index 00000000..85863e73 --- /dev/null +++ b/docs/usage/k3s/index.md @@ -0,0 +1,82 @@ +# K3s overview (on Equinix Metal) + +## Optional Tidy environment (best if something was running before) +``` +rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ +ip addr flush dev lo; \ +ip addr add 127.0.0.1/8 dev lo; +``` + +## Step 1: Create Manifests folder + +This is required, this folder will contain all of the generated manifests that `k3s` will execute as it starts. We will create it before `k3s` and place our `kube-vip` manifests within it. + +``` +mkdir -p /var/lib/rancher/k3s/server/manifests/ +``` + +## Step 2: Get rbac for `Kube-Vip` + +As `kube-vip` runs inside of the Kubernetes cluster, we will need to ensure that the required permissions exist. + +``` +curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/rbac.yaml +``` + +## Step 3: Generate kube-vip (A VIP address for the network will be required) + +Configure your virtual IP (for the control plane) and interface that will expose this VIP first. + +``` +export VIP=x.x.x.x +export INTERFACE=ethx +``` + +Modify the `VIP` and `INTERFACE` to match the floating IP address you'd like to use and the interface it should bind to. + +To generate the manifest we have two options! We can generate the manifest from [kube-vip.io](kube-vip.io) or use a kube-vip image to generate the manifest! + +## Step 3.1: Generate from kube-vip.io + +``` +curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml +``` + +## Step 3.2 Genereate from container image + +### containerd +`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` + +### Docker +`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` + + +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --vip $VIP \ + --controlplane \ + --services \ + --inCluster \ + --taint \ + --arp +``` + +## Step 4: Up Cluster + +From online `-->` + +``` +curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ +-t agent-secret --tls-san $VIP" sh - +``` + +From local `-->` + +``` +sudo ./k3s server --tls-san $VIP +``` + +## Step 5: Service Load-Balancing + +For this refer to the [on-prem](../on-prem) documentation \ No newline at end of file diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md new file mode 100644 index 00000000..6998a662 --- /dev/null +++ b/docs/usage/on-prem/index.md @@ -0,0 +1,237 @@ +# Kube-vip on-prem + +We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. + +## Flow + +This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: + +1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` +2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = ServiceTypeLoadBalancer` +3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. +4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. +5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. +6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. +7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. +8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. + +## CCM + +We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. + + +## Using the Kube-vip Cloud Provider + +The below instructions *should just work* on Kubernetes regardless of architecture (Linux Operating System is the only requirement) - you can quickly install the "latest" components: + +**Install the `kube-vip-cloud-provider`** + +``` +$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +``` + +It uses a `statefulSet` and can always be viewed with the following command: + +``` +kubectl describe pods -n kube-system kube-vip-cloud-provider-0 +``` + +**Create a global CIDR or IP Range** + +Any `service` in any `namespace` can use an address from the global CIDR `cidr-global` or range `range-global` + +``` +kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29 +``` +or +``` +kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 +``` + +Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific + + +## The Detailed guide + +### Deploy the Kube-vip Cloud Provider + +**Install the `kube-vip-cloud-provider`** + +``` +$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +``` + +The following output should appear when the manifest is applied: + +``` +serviceaccount/kube-vip-cloud-controller created +clusterrole.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-role created +clusterrolebinding.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-binding created +statefulset.apps/kube-vip-cloud-provider created +``` + +We can validate the cloud provider by examining the pods and following the logs: + +``` +kubectl describe pods -n kube-system kube-vip-cloud-provider-0 +kubectl logs -n kube-system kube-vip-cloud-provider-0 -f +``` + +### The Kube-vip Cloud Provider `configmap` + +To manage the IP address ranges for the load balancer instances the `kube-vip-cloud-provider` uses a `configmap` held in the `kube-system` namespace. IP address ranges can be configured using: +- IP address pools by CIDR +- IP ranges [start address - end address] +- Multiple pools by CIDR per namespace +- Multiple IP ranges per namespace (handles overlapping ranges) +- Setting of static addresses through --load-balancer-ip=x.x.x.x + +To control which IP address range is used for which service the following rules are applied: +- Global address pools (`cidr-global` or `range-global`) are available for use by *any* `service` in *any* `namespace` +- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by `service` in the *specific* `namespace` +- Static IP addresses can be applied to a load balancer `service` using the `loadbalancerIP` setting, even outside of the assigned ranges + +Example Configmap: + +``` +$ kubectl get configmap -n kube-system kubevip -o yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: kubevip + namespace: kube-system +data: + cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default namespace + range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development namespace + cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance namespace + cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any namespace +``` + +### Expose a service + +We can now expose a service and once the cloud provider has provided an address `kube-vip` will start to advertise that address to the outside world as shown below! + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx +``` + +or via a `service` YAML definition + +``` +apiVersion: v1 +kind: Service +metadata: + name: nginx +spec: + ports: + - name: http + port: 80 + protocol: TCP + selector: + app: nginx + type: LoadBalancer + ``` + + +We can also expose a specific address by specifying it on the command line: + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` + +or including it in the `service` definition: + +``` +apiVersion: v1 +kind: Service +metadata: + name: nginx +spec: + ports: + - name: http + port: 80 + protocol: TCP + selector: + app: nginx + type: LoadBalancer + loadBalancerIP: "1.1.1.1" +``` + +### Using DHCP for Load Balancers (experimental) + +With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a + Kubernetes service on the network. + +In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the +address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! + +``` +$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc +service/nginx-dhcp exposed +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s + +{ ... a second or so later ... } + +$ k get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 17m +nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s +``` + +### Using UPNP to expose a service to the outside world + +With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the inte +rnet. + +Most simple networks look something like the following: + +`<----- ----> Internet` + +Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. + +#### Enable UPNP + +Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. + +**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) + +``` +- name: enableUPNP + value: "true" +``` + +#### Exposing a service + +To expose a port successfully we'll need to change the command slightly: + +`--target-port=80` the port of the application in the pods (HTT/NGINX) +`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) + +`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` + +The above example should expose a port on your external (internet facing address), that can be tested externally with: + +``` +$ curl externalIP:32380 + + +... +``` + +### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) + +Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! + +``` +# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 ++-------+---------------+--------+----------------------+ +| ID | ADDRESS | PUBLIC | CREATED | ++-------+---------------+--------+----------------------+ +| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | ++-------+---------------+--------+----------------------+ + +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` \ No newline at end of file From 090182bcc8d7634f409ed39fa82b263123da3deb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 6 Jul 2021 13:44:32 +0100 Subject: [PATCH 115/542] BGP router_ID --- docs/install_daemonset/index.md | 33 ++++++++++++++++++++++++++++++--- docs/publish.sh | 11 +++++------ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 1eb5d8a1..5fc573de 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -105,15 +105,24 @@ spec: value: "true" - name: cp_namespace value: kube-system + - name: vip_ddns + value: "false" - name: svc_enable value: "true" - name: bgp_enable value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" - name: bgp_peers - value: "192.168.0.10:65000::false,192.168.0.11:65000::false" + value: 192.168.0.10:65000::false,192.168.0.11:65000::false - name: vip_address value: 192.168.0.40 - image: plndr/kube-vip:0.2.3 + image: 'plndr/kube-vip:' imagePullPolicy: Always name: kube-vip resources: {} @@ -121,17 +130,35 @@ spec: capabilities: add: - NET_ADMIN + - NET_RAW - SYS_TIME hostNetwork: true - serviceAccountName: kube-vip nodeSelector: node-role.kubernetes.io/master: "true" + serviceAccountName: kube-vip tolerations: - effect: NoSchedule key: node-role.kubernetes.io/master + operator: Exists updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 ``` +### Managing a `routerID` as a daemonset + +The routerID needs to be unique on each node that participates in BGP advertisements. In order to do this we can modify the manifest so that when `kube-vip` starts it will look up its local address and use that as the routerID. + +``` + - name: bgp_routerinterface + value: "ens160" +``` + +This will instruct each instance of `kube-vip` as part of the daemonset to look up the IP address on that interface and use it as the routerID. + ### Manifest Overview - `nodeSelector` - Ensures that this particular daemonset only runs on control plane nodes diff --git a/docs/publish.sh b/docs/publish.sh index fb52a8e2..ad5e6e45 100644 --- a/docs/publish.sh +++ b/docs/publish.sh @@ -2,9 +2,8 @@ echo Deploying updated documentation -generate-md --layout github --input ./index/ --output /var/www/kube-vip/ -generate-md --layout github --input ./architecture/ --output /var/www/kube-vip/architecture/ -generate-md --layout github --input ./control-plane/ --output /var/www/kube-vip/control-plane/ -generate-md --layout github --input ./hybrid/ --output /var/www/kube-vip/hybrid/ -generate-md --layout github --input ./kubernetes/ --output /var/www/kube-vip/kubernetes/ -generate-md --layout github --input ./manifests/ --output /var/www/kube-vip/manifests/ \ No newline at end of file +# Sleep for dramatic purposes! + +sleep 5 + +generate-md --layout github --input ./ --output /var/www/kube-vip/ From f6825359900b0e2530a520339904ea02c5c814f1 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 6 Jul 2021 13:53:35 +0100 Subject: [PATCH 116/542] Final re-arrange of lb docs --- docs/usage/EquinixMetal/index.md | 15 +++++++++++++++ docs/usage/on-prem/index.md | 15 --------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index a3c96d20..5027be83 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -73,6 +73,21 @@ kube-vip manifest daemonset --interface $INTERFACE \ --provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - ``` +### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) + +Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! + +``` +# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 ++-------+---------------+--------+----------------------+ +| ID | ADDRESS | PUBLIC | CREATED | ++-------+---------------+--------+----------------------+ +| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | ++-------+---------------+--------+----------------------+ + +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` + ## Troubleshooting If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node: diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index 6998a662..19b9196b 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -220,18 +220,3 @@ $ curl externalIP:32380 ... ``` - -### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) - -Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! - -``` -# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 -+-------+---------------+--------+----------------------+ -| ID | ADDRESS | PUBLIC | CREATED | -+-------+---------------+--------+----------------------+ -| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | -+-------+---------------+--------+----------------------+ - -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` \ No newline at end of file From d7078a89e2893df8ae25a8b1131baf4f57d22d91 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 6 Jul 2021 15:44:07 +0100 Subject: [PATCH 117/542] Create CODEOWNERS --- CODEOWNERS | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..ae4b473a --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,10 @@ + +# For more information on the syntax of the CODEOWNERS file, see: +# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners + +# The Kube-Vip maintainers team +* @thebsdbox @yastij + +# Emeritus Maintainers +# +# N/A From ad43fa32028fa57c8e700cc9355378a29d9ad5e5 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 6 Jul 2021 17:16:30 +0100 Subject: [PATCH 118/542] Adds documentation for KIND --- docs/index.md | 1 + docs/usage/kind/index.md | 57 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 docs/usage/kind/index.md diff --git a/docs/index.md b/docs/index.md index dcdbdd8f..85e156a4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -60,6 +60,7 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we ## Usage - [On-Prem with the kube-vip cloud controller](/usage/on-prem) +- [KIND](/usage/kind) - [Equinix Metal](/usage/EquinixMetal) - [k3s](/usage/k3s) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md new file mode 100644 index 00000000..c831e172 --- /dev/null +++ b/docs/usage/kind/index.md @@ -0,0 +1,57 @@ +# Kube-vip on KIND + +## Deploying KIND + +The documentation for KIND is fantastic and it's quickstart guide will have you up and running in no time -> [https://kind.sigs.k8s.io/docs/user/quick-start/](https://kind.sigs.k8s.io/docs/user/quick-start/) + +## Find Address Pool for Kube-Vip + +We will need to find addresses that can be used by Kube-Vip: + +``` +docker network inspect kind -f '{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}' +``` + +This will return a cidr range such as `172.18.0.0/16` and from here we can select a range. + +## Deploy the Kube-Vip Cloud Controller + +``` +$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +``` + +## Add our Address range + +``` +kubectl create configmap --namespace kube-system kubevip --from-literal range-global=172.18.100.10-172.18.100.30 +``` + +## Install kube-vip + +Set the correct `alias` for `kube-vip` +``` +alias kube-vip="docker run --network host --rm plndr/kube-vip:v0.3.5" +``` + +Install Kube-vip deamonset inside of KIND + +``` +kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - +``` + +## Test + +``` +kubectl apply -f https://k8s.io/examples/application/deployment.yaml +``` + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx +``` + +``` +kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubernetes ClusterIP 10.96.0.1 443/TCP 74m +nginx LoadBalancer 10.96.196.235 172.18.100.11 80:31236/TCP 6s +``` \ No newline at end of file From e906270eb2c39d63a994e8ac31f4e71add818a5d Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Tue, 6 Jul 2021 10:52:50 +0800 Subject: [PATCH 119/542] Refactor the DHCP client Signed-off-by: yaocw2020 --- go.mod | 7 +- go.sum | 34 +++- pkg/manager/manager.go | 17 +- pkg/manager/services.go | 15 +- pkg/manager/services_dhcp.go | 148 +++++++++-------- pkg/service/manager.go | 17 +- pkg/service/services.go | 7 + pkg/service/services_dhcp.go | 135 ++++++++------- pkg/service/watcher.go | 3 +- pkg/vip/ddns.go | 12 +- pkg/vip/dhcp.go | 309 ++++++++++++++++++++++++++--------- pkg/vip/dhcp_internals.go | 206 ----------------------- 12 files changed, 458 insertions(+), 452 deletions(-) delete mode 100644 pkg/vip/dhcp_internals.go diff --git a/go.mod b/go.mod index 49e3cea7..d1308803 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.19 github.com/google/uuid v1.2.0 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/go-hclog v0.16.0 // indirect @@ -19,13 +18,14 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/raft v1.3.1 github.com/imdario/mergo v0.3.12 // indirect + github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e github.com/jpillora/backoff v1.0.0 github.com/json-iterator/go v1.1.11 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/magiconair/properties v1.8.5 // indirect github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 - github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf + github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.7.0 @@ -35,7 +35,6 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.10.0 github.com/prometheus/common v0.23.0 // indirect - github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5 github.com/sirupsen/logrus v1.8.1 github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.3.1 // indirect @@ -47,7 +46,7 @@ require ( golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect - golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 + golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 // indirect diff --git a/go.sum b/go.sum index 4e5eb98e..85bb978e 100644 --- a/go.sum +++ b/go.sum @@ -147,6 +147,7 @@ github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQo github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -243,8 +244,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -322,6 +321,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -329,12 +330,18 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e h1:sgh63o+pm5kcdrgyYaCIoeD7mccyL6MscVmy+DvY6C4= +github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -392,8 +399,16 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= +github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -520,8 +535,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5 h1:/kzTBQ20DbbhSNaBXiFEk2gPrGhY26kajwC1ro/Vlh8= -github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5/go.mod h1:FwstIpm6vX98QgtR8KEwZcVjiRn2WP76LjXAHj84fK0= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -588,6 +601,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= +github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -693,6 +708,7 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -708,7 +724,9 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -742,11 +760,13 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -782,6 +802,8 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -790,8 +812,8 @@ golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index fe15b1f0..d3a8a9fc 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -10,15 +10,16 @@ import ( "syscall" "github.com/kamhlos/upnp" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + + "github.com/plunder-app/kube-vip/pkg/bgp" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" ) const plunderLock = "plndr-svcs-lock" @@ -58,9 +59,11 @@ type Instance struct { cluster cluster.Cluster // Service uses DHCP - isDHCP bool - dhcpInterface string - dhcpClient *vip.DHCPClient + isDHCP bool + dhcpInterface string + dhcpInterfaceHwaddr string + dhcpInterfaceIP string + dhcpClient *vip.DHCPClient // Kubernetes service mapping Vip string diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 37973719..12c9dd7a 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -6,12 +6,18 @@ import ( "strings" "sync" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" +) + +const ( + hwAddrKey = "kube-vip.io/hwaddr" + requestedIP = "kube-vip.io/requestedIP" ) func (sm *Manager) stopService(uid string) error { @@ -67,8 +73,8 @@ func (sm *Manager) deleteService(uid string) error { return nil } -func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { +func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() log.Debugf("[STARTING] Service Sync") @@ -104,10 +110,11 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types newService.Port = service.Spec.Ports[0].Port newService.ServiceName = service.Name + newService.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] + newService.dhcpInterfaceIP = service.Annotations[requestedIP] // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP if newServiceAddress == "0.0.0.0" { - err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) if err != nil { return err diff --git a/pkg/manager/services_dhcp.go b/pkg/manager/services_dhcp.go index 2461cc5b..b02e0acd 100644 --- a/pkg/manager/services_dhcp.go +++ b/pkg/manager/services_dhcp.go @@ -5,15 +5,16 @@ import ( "fmt" "net" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/insomniacslk/dhcp/dhcpv4/nclient4" log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/vishvananda/netlink" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" ) func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { @@ -30,7 +31,19 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi if err != nil { log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_DEFAULT} + hwaddr, err := net.ParseMAC(newService.dhcpInterfaceHwaddr) + if newService.dhcpInterfaceHwaddr != "" && err != nil { + return err + } + + mac := &netlink.Macvlan{ + LinkAttrs: netlink.LinkAttrs{ + Name: interfaceName, + ParentIndex: parent.Attrs().Index, + HardwareAddr: hwaddr, + }, + Mode: netlink.MACVLAN_MODE_DEFAULT, + } err = netlink.LinkAdd(mac) if err != nil { @@ -49,91 +62,84 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) } - client := vip.DHCPClient{ - Interface: iface, - OnBound: func(lease *vip.Lease) { - newVip.VIP = lease.ClientIP + var initRebootFlag bool + if newService.dhcpInterfaceHwaddr != "" { + initRebootFlag = true + } + + client := vip.NewDHCPClient(iface, initRebootFlag, newService.dhcpInterfaceIP, func(lease *nclient4.Lease) { + newVip.VIP = lease.ACK.YourIPAddr.String() + + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + // Create Add configuration to the new service + newService.vipConfig = *newVip - // Create Add configuration to the new service - newService.vipConfig = *newVip + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balancer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + newService.cluster = *c - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return + return err } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + currentServiceCopy.Annotations[hwAddrKey] = iface.HardwareAddr.String() + currentServiceCopy.Annotations[requestedIP] = newVip.VIP + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) if err != nil { - log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err } - newService.cluster = *c - - // Add new service to manager configuration - service.Spec.LoadBalancerIP = newVip.VIP - log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) - //sm.serviceInstances = append(sm.serviceInstances, *newService) - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - log.Errorf("Failed to set Services: %v", retryErr) + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err } - // Find an update our array + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + } + // Find an update our array - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - sm.serviceInstances[x] = *newService - } + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + sm.serviceInstances[x] = *newService } - sm.upnpMap(*newService) - }, - } + } + sm.upnpMap(*newService) + }) + // Set that DHCP is enabled newService.isDHCP = true // Set the name of the interface so that it can be removed on Service deletion newService.dhcpInterface = interfaceName // Add the client so that we can call it's stop function - newService.dhcpClient = &client + newService.dhcpClient = client sm.serviceInstances = append(sm.serviceInstances, *newService) go client.Start() - // newService.lease, err = vip.AcquireLease(newServiceUID[0:8], interfaceName, nil) - // if err != nil { - // return err - // } - - // ipNet, err := newService.lease.IPNet() - // if err != nil { - // return err - // } - // newVip.VIP = ipNet.IP.String() - // newVip.Interface = interfaceName - return nil } diff --git a/pkg/service/manager.go b/pkg/service/manager.go index b4a40023..944328cf 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -9,16 +9,15 @@ import ( "github.com/kamhlos/upnp" "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" "github.com/plunder-app/kube-vip/pkg/bgp" "github.com/plunder-app/kube-vip/pkg/cluster" "github.com/plunder-app/kube-vip/pkg/kubevip" "github.com/plunder-app/kube-vip/pkg/vip" - log "github.com/sirupsen/logrus" - - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" ) const plunderLock = "plunder-lock" @@ -60,9 +59,11 @@ type Instance struct { cluster cluster.Cluster // Service uses DHCP - isDHCP bool - dhcpInterface string - dhcpClient *vip.DHCPClient + isDHCP bool + dhcpInterface string + dhcpInterfaceHwaddr string + dhcpInterfaceIP string + dhcpClient *vip.DHCPClient // Kubernetes service mapping Vip string diff --git a/pkg/service/services.go b/pkg/service/services.go index 6810ab6f..c2bf49ee 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -13,6 +13,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + hwAddrKey = "kube-vip.io/hwaddr" + requestedIP = "kube-vip.io/requestedIP" +) + func (sm *Manager) stopService(uid string) error { found := false for x := range sm.serviceInstances { @@ -98,6 +103,8 @@ func (sm *Manager) syncServices(service *v1.Service) error { newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types newService.Port = service.Spec.Ports[0].Port newService.ServiceName = service.Name + newService.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] + newService.dhcpInterfaceIP = service.Annotations[requestedIP] // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP if newServiceAddress == "0.0.0.0" { diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index 290d5b12..4eedfee0 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -5,15 +5,16 @@ import ( "fmt" "net" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/insomniacslk/dhcp/dhcpv4/nclient4" log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/vishvananda/netlink" + "github.com/plunder-app/kube-vip/pkg/cluster" + "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/plunder-app/kube-vip/pkg/vip" ) func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { @@ -32,7 +33,19 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi if err != nil { log.Infof("Creating new macvlan interface for DHCP [%s]", interfaceName) - mac := &netlink.Macvlan{LinkAttrs: netlink.LinkAttrs{Name: interfaceName, ParentIndex: parent.Attrs().Index}, Mode: netlink.MACVLAN_MODE_DEFAULT} + hwaddr, err := net.ParseMAC(newService.dhcpInterfaceHwaddr) + if newService.dhcpInterfaceHwaddr != "" && err != nil { + return err + } + + mac := &netlink.Macvlan{ + LinkAttrs: netlink.LinkAttrs{ + Name: interfaceName, + ParentIndex: parent.Attrs().Index, + HardwareAddr: hwaddr, + }, + Mode: netlink.MACVLAN_MODE_DEFAULT, + } err = netlink.LinkAdd(mac) if err != nil { @@ -51,75 +64,79 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) } - client := vip.DHCPClient{ - Interface: iface, - OnBound: func(lease *vip.Lease) { - newVip.VIP = lease.ClientIP + var initRebootFlag bool + if newService.dhcpInterfaceHwaddr != "" { + initRebootFlag = true + } + + client := vip.NewDHCPClient(iface, initRebootFlag, newService.dhcpInterfaceIP, func(lease *nclient4.Lease) { + newVip.VIP = lease.ACK.YourIPAddr.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) + log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - // Create Add configuration to the new service - newService.vipConfig = *newVip + // Create Add configuration to the new service + newService.vipConfig = *newVip - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) + // TODO - start VIP + c, err := cluster.InitCluster(&newService.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + if err != nil { + log.Errorf("Failed to add Load Balancer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) + return + } + newService.cluster = *c + + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return + return err + } + + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) + currentServiceCopy.Annotations[hwAddrKey] = iface.HardwareAddr.String() + currentServiceCopy.Annotations[requestedIP] = newVip.VIP + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) if err != nil { - log.Errorf("Failed to add Load Balabcer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return + log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) + return err } - newService.cluster = *c - - // Add new service to manager configuration - service.Spec.LoadBalancerIP = newVip.VIP - log.Infof("Updating service [%s], with load balancer address [%s]", service.Name, service.Spec.LoadBalancerIP) - //sm.serviceInstances = append(sm.serviceInstances, *newService) - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - log.Errorf("Failed to set Services: %v", retryErr) + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + return err } - // Find an update our array + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + } + // Find an update our array - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - sm.serviceInstances[x] = *newService - } + for x := range sm.serviceInstances { + if sm.serviceInstances[x].UID == newServiceUID { + sm.serviceInstances[x] = *newService } - sm.upnpMap(*newService) - }, - } + } + sm.upnpMap(*newService) + }) // Set that DHCP is enabled newService.isDHCP = true // Set the name of the interface so that it can be removed on Service deletion newService.dhcpInterface = interfaceName // Add the client so that we can call it's stop function - newService.dhcpClient = &client + newService.dhcpClient = client sm.serviceInstances = append(sm.serviceInstances, *newService) diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index db0aca05..171e2b01 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/davecgh/go-spew/spew" - "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "golang.org/x/net/context" v1 "k8s.io/api/core/v1" @@ -13,6 +12,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" + + "github.com/plunder-app/kube-vip/pkg/kubevip" ) func rebuildEndpoints(eps v1.Endpoints) []kubevip.BackEnd { diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 11920ce3..0604976f 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -5,6 +5,7 @@ import ( "net" "time" + "github.com/insomniacslk/dhcp/dhcpv4/nclient4" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) @@ -41,14 +42,9 @@ func (ddns *ddnsManager) Start() (string, error) { // channel to wait for IP ipCh := make(chan string) - client := DHCPClient{ - // send host name, not current os.Hostname, but configured name from user - Hostname: ddns.network.DDNSHostName(), - Interface: iface, - OnBound: func(lease *Lease) { - ipCh <- lease.ClientIP - }, - } + client := NewDHCPClient(iface, false, "", func(lease *nclient4.Lease) { + ipCh <- lease.ACK.YourIPAddr.String() + }) log.Info("waiting for ip from dhcp") ip, timeout := "", time.After(1*time.Minute) diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index d447a089..e82fe281 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -1,112 +1,265 @@ +// It"s DHCP client implementation that refers to https://www.rfc-editor.org/rfc/rfc2131.html package vip import ( + "context" + "fmt" "net" - "sync" "time" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv4/nclient4" "github.com/jpillora/backoff" log "github.com/sirupsen/logrus" ) // Callback is a function called on certain events -type Callback func(*Lease) - -// Lease is -type Lease struct { - RenewAfter time.Time - ClientIP string - SubnetMask string - Router string - DNS []string -} +type Callback func(*nclient4.Lease) -//DHCPClient is +// Client is a DHCP client, responsible for maintaining ipv4 lease for one specified interface type DHCPClient struct { - Interface *net.Interface // e.g. net.InterfaceByName("eth0") - HWAddr net.HardwareAddr - Hostname string - Lease Lease - - err error - once sync.Once - onceErr error - connection net.PacketConn - hardwareAddr net.HardwareAddr - timeNow func() time.Time - generateXID func() uint32 - stop chan struct{} - - // last DHCPACK packet for renewal/release - Ack *layers.DHCPv4 - - OnBound Callback // On renew or rebound + iface *net.Interface + lease *nclient4.Lease + initRebootFlag bool + requestedIP net.IP + stopChan chan struct{} + onBound Callback } -// Err returns any errors from the DHCP client -func (c *DHCPClient) Err() error { - return c.err +func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string, onBound Callback) *DHCPClient { + return &DHCPClient{ + iface: iface, + stopChan: make(chan struct{}), + initRebootFlag: initRebootFlag, + requestedIP: net.ParseIP(requestedIP), + onBound: onBound, + } } -// Start will begin the DHCP client -func (c *DHCPClient) Start() error { +// Stop state-transition process and close dhcp client +func (c *DHCPClient) Stop() { + close(c.stopChan) +} - var ack *layers.DHCPv4 - pkt := gopacket.NewPacket(nil, layers.LayerTypeDHCPv4, gopacket.DecodeOptions{}) - if dhcp, ok := pkt.Layer(layers.LayerTypeDHCPv4).(*layers.DHCPv4); ok { - ack = dhcp - } - // Set ack packet - c.Ack = ack - // Get Hardware address - c.HWAddr = c.Interface.HardwareAddr - // Create a channel for notifications - c.stop = make(chan struct{}) - - // Configure the backoff +// Start state-transition process of dhcp client +// -------- ------- +// | | +-------------------------->| |<-------------------+ +// | INIT- | | +-------------------->| INIT | | +// | REBOOT |DHCPNAK/ +---------->| |<---+ | +// | |Restart| | ------- | | +// -------- | DHCPNAK/ | | | +// | Discard offer | -/Send DHCPDISCOVER | +// -/Send DHCPREQUEST | | | +// | | | DHCPACK v | | +// ----------- | (not accept.)/ ----------- | | +// | | | Send DHCPDECLINE | | | +// | REBOOTING | | | | SELECTING |<----+ | +// | | | / | | |DHCPOFFER/ | +// ----------- | / ----------- | |Collect | +// | | / | | | replies | +// DHCPACK/ | / +----------------+ +-------+ | +// Record lease, set| | v Select offer/ | +// timers T1, T2 ------------ send DHCPREQUEST | | +// | +----->| | DHCPNAK, Lease expired/ | +// | | | REQUESTING | Halt network | +// DHCPOFFER/ | | | | +// Discard ------------ | | +// | | | | ----------- | +// | +--------+ DHCPACK/ | | | +// | Record lease, set -----| REBINDING | | +// | timers T1, T2 / | | | +// | | DHCPACK/ ----------- | +// | v Record lease, set ^ | +// +----------------> ------- /timers T1,T2 | | +// +----->| |<---+ | | +// | | BOUND |<---+ | | +// DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/ +// DHCPNAK/Discard ------- | Broadcast Halt network +// | | | | DHCPREQUEST | +// +-------+ | DHCPACK/ | | +// T1 expires/ Record lease, set | | +// Send DHCPREQUEST timers T1, T2 | | +// to leasing server | | | +// | ---------- | | +// | | |------------+ | +// +->| RENEWING | | +// | |----------------------------+ +// ---------- +// Figure: State-transition diagram for DHCP clients +func (c *DHCPClient) Start() { backoff := backoff.Backoff{ Factor: 2, Jitter: true, Min: 10 * time.Second, Max: 1 * time.Minute, } - // Start renew loop for { - for c.obtainOrRenew() { - if err := c.Err(); err != nil { - dur := backoff.Duration() - log.Printf("Temporary error: %v (waiting %v)", err, dur) - time.Sleep(dur) - continue - } else { - backoff.Reset() - break - } - + var lease *nclient4.Lease + var err error + if c.initRebootFlag { + // DHCP State-transition: INIT-REBOOT --> BOUND + lease, err = c.initReboot() + } else { + // DHCP State-transition: INIT --> BOUND + lease, err = c.request() } - - // call the handler - if cb := c.OnBound; cb != nil { - cb(&c.Lease) - } - select { - case <-c.stop: - return c.err - case <-time.After(time.Until(c.Lease.RenewAfter)): - // remove lease and request a new one + if err != nil { + dur := backoff.Duration() + log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur) + time.Sleep(dur) continue + } else { + backoff.Reset() } + + c.initRebootFlag = false + c.lease = lease + c.onBound(lease) + + // Set up two ticker to renew/rebind regularly + t1Timeout := c.lease.ACK.IPAddressLeaseTime(0) / 2 + t2Timeout := c.lease.ACK.IPAddressLeaseTime(0) / 8 * 7 + + t1, t2 := time.NewTicker(t1Timeout), time.NewTicker(t2Timeout) + + for { + select { + case <-t1.C: + // renew + lease, err := c.renew() + if err == nil { + c.lease = lease + log.Infof("renew, lease: %+v", lease) + t2.Reset(t2Timeout) + } else { + log.Errorf("renew failed, error: %s", err.Error()) + } + case <-t2.C: + // rebind + lease, err := c.rebind() + if err == nil { + c.lease = lease + log.Infof("rebind, lease: %+v", lease) + t1.Reset(t1Timeout) + } else { + log.Errorf("rebind failed, error: %s", err.Error()) + t1.Stop() + t2.Stop() + break + } + case <-c.stopChan: + // release + if err := c.release(); err != nil { + log.Errorf("release lease failed, error: %s, lease: %+v", err.Error(), c.lease) + } + log.Infof("release, lease: %+v", c.lease) + t1.Stop() + t2.Stop() + return + } + } + } +} + +func (c *DHCPClient) request() (*nclient4.Lease, error) { + broadcast, err := nclient4.New(c.iface.Name) + defer broadcast.Close() + if err != nil { + return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %w", c.iface.Name, err) + } + return broadcast.Request(context.TODO()) +} + +func (c *DHCPClient) release() error { + unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(&net.UDPAddr{Port: nclient4.ClientPort}), + nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) + if err != nil { + return fmt.Errorf("create unicast client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) } + defer unicast.Close() + + // TODO modify lease + return unicast.Release(c.lease) } -// Stop will stop the DHCP client -func (c *DHCPClient) Stop() error { - err := c.release() +// -------------------------------------------------------- +// | |INIT-REBOOT | RENEWING |REBINDING | +// -------------------------------------------------------- +// |broad/unicast |broadcast | unicast |broadcast | +// |server-ip |MUST NOT | MUST NOT |MUST NOT | +// |requested-ip |MUST | MUST NOT |MUST NOT | +// |ciaddr |zero | IP address |IP address| +// -------------------------------------------------------- +func (c *DHCPClient) initReboot() (*nclient4.Lease, error) { + broadcast, err := nclient4.New(c.iface.Name) + if err != nil { + return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %w", c.iface.Name, err) + } + defer broadcast.Close() + message, err := dhcpv4.New( + dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), + dhcpv4.WithHwAddr(c.iface.HardwareAddr), + dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.requestedIP))) if err != nil { - log.Errorf("Unable ro return lease: %v", err) + return nil, fmt.Errorf("new dhcp message failed, error: %w", err) } - close(c.stop) - return nil + + return sendMessage(broadcast, message) +} + +func (c *DHCPClient) renew() (*nclient4.Lease, error) { + unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(&net.UDPAddr{Port: nclient4.ClientPort}), + nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) + if err != nil { + return nil, fmt.Errorf("create unicast client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) + } + defer unicast.Close() + + message, err := dhcpv4.New( + dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), + dhcpv4.WithHwAddr(c.iface.HardwareAddr), + dhcpv4.WithClientIP(c.lease.ACK.ClientIPAddr)) + if err != nil { + return nil, fmt.Errorf("new dhcp message failed, error: %w", err) + } + + return sendMessage(unicast, message) +} + +func (c *DHCPClient) rebind() (*nclient4.Lease, error) { + broadcast, err := nclient4.New(c.iface.Name) + if err != nil { + return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %s", c.iface.Name, err) + } + defer broadcast.Close() + message, err := dhcpv4.New( + dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), + dhcpv4.WithHwAddr(c.iface.HardwareAddr), + dhcpv4.WithClientIP(c.lease.ACK.ClientIPAddr)) + if err != nil { + return nil, fmt.Errorf("new dhcp message failed, error: %w", err) + } + + return sendMessage(broadcast, message) +} + +func sendMessage(client *nclient4.Client, message *dhcpv4.DHCPv4) (*nclient4.Lease, error) { + response, err := client.SendAndRead(context.TODO(), client.RemoteAddr(), message, + nclient4.IsMessageType(dhcpv4.MessageTypeAck, dhcpv4.MessageTypeNak)) + if err != nil { + return nil, fmt.Errorf("got an error while processing the request: %w", err) + } + if response.MessageType() == dhcpv4.MessageTypeNak { + return nil, &nclient4.ErrNak{ + Offer: message, + Nak: response, + } + } + + lease := &nclient4.Lease{} + lease.ACK = response + lease.Offer = message + lease.CreationTime = time.Now() + + return lease, nil } diff --git a/pkg/vip/dhcp_internals.go b/pkg/vip/dhcp_internals.go deleted file mode 100644 index aa2e7e41..00000000 --- a/pkg/vip/dhcp_internals.go +++ /dev/null @@ -1,206 +0,0 @@ -package vip - -import ( - "bytes" - "fmt" - "syscall" - "time" - - "github.com/google/gopacket/layers" - "github.com/mdlayher/raw" - "github.com/pkg/errors" - "github.com/rtr7/dhcp4" - "golang.org/x/sys/unix" -) - -func (c *DHCPClient) release() error { - release := c.packet(c.generateXID(), append([]layers.DHCPOption{ - dhcp4.MessageTypeOpt(layers.DHCPMsgTypeRelease), - }, serverID(c.Ack)...)) - release.ClientIP = c.Ack.YourClientIP - if err := dhcp4.Write(c.connection, release); err != nil { - return err - } - - c.Ack = nil - return nil -} - -func serverID(pkt *layers.DHCPv4) []layers.DHCPOption { - for _, o := range pkt.Options { - if o.Type == layers.DHCPOptServerID { - return []layers.DHCPOption{o} - } - } - return nil -} - -func (c *DHCPClient) packet(xid uint32, opts []layers.DHCPOption) *layers.DHCPv4 { - return &layers.DHCPv4{ - Operation: layers.DHCPOpRequest, - HardwareType: layers.LinkTypeEthernet, - HardwareLen: uint8(len(layers.EthernetBroadcast)), - HardwareOpts: 0, // clients set this to zero (used by relay agents) - Xid: xid, - Secs: 0, // TODO: fill in? - Flags: 0, // we can receive IP packets via unicast - ClientHWAddr: c.hardwareAddr, - ServerName: nil, - File: nil, - Options: opts, - } -} - -var errNAK = errors.New("received DHCPNAK") - -// ObtainOrRenew returns false when encountering a permanent error. -func (c *DHCPClient) obtainOrRenew() bool { - c.once.Do(func() { - if c.timeNow == nil { - c.timeNow = time.Now - } - if c.connection == nil && c.Interface != nil { - conn, err := raw.ListenPacket(c.Interface, syscall.ETH_P_IP, &raw.Config{ - LinuxSockDGRAM: true, - }) - if err != nil { - c.onceErr = err - return - } - c.connection = conn - } - if c.connection == nil && c.Interface == nil { - c.onceErr = fmt.Errorf("c.Interface is nil") - return - } - if c.hardwareAddr == nil && c.HWAddr != nil { - c.hardwareAddr = c.HWAddr - } - if c.hardwareAddr == nil { - c.hardwareAddr = c.Interface.HardwareAddr - } - if c.generateXID == nil { - c.generateXID = dhcp4.XIDGenerator(c.hardwareAddr) - } - if c.Hostname == "" { - var utsname unix.Utsname - if err := unix.Uname(&utsname); err != nil { - c.onceErr = err - return - } - c.Hostname = string(utsname.Nodename[:bytes.IndexByte(utsname.Nodename[:], 0)]) - } - }) - if c.onceErr != nil { - c.err = c.onceErr - return false // permanent error - } - c.err = nil // clear previous error - ack, err := c.dhcpRequest() - if err != nil { - if errno, ok := err.(syscall.Errno); ok && errno == syscall.EAGAIN { - c.err = fmt.Errorf("DHCP: timeout (server(s) unreachable)") - return true // temporary error - } - if err == errNAK { - c.Ack = nil // start over at DHCPDISCOVER - } - c.err = fmt.Errorf("DHCP: %v", err) - return true // temporary error - } - c.Ack = ack - c.Lease.ClientIP = ack.YourClientIP.String() - lease := dhcp4.LeaseFromACK(ack) - if mask := lease.Netmask; len(mask) > 0 { - c.Lease.SubnetMask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) - } - if len(lease.Router) > 0 { - c.Lease.Router = lease.Router.String() - } - if len(lease.DNS) > 0 { - c.Lease.DNS = make([]string, len(lease.DNS)) - for idx, ip := range lease.DNS { - c.Lease.DNS[idx] = ip.String() - } - } - c.Lease.RenewAfter = c.timeNow().Add(lease.RenewalTime) - return true -} - -func (c *DHCPClient) dhcpRequest() (*layers.DHCPv4, error) { - var last *layers.DHCPv4 - - if c.Ack != nil { - last = c.Ack - } else { - discover := c.packet(c.generateXID(), []layers.DHCPOption{ - dhcp4.MessageTypeOpt(layers.DHCPMsgTypeDiscover), - dhcp4.HostnameOpt(c.Hostname), - dhcp4.ClientIDOpt(layers.LinkTypeEthernet, c.hardwareAddr), - dhcp4.ParamsRequestOpt( - layers.DHCPOptDNS, - layers.DHCPOptRouter, - layers.DHCPOptSubnetMask), - }) - if err := dhcp4.Write(c.connection, discover); err != nil { - return nil, err - } - - // Look for DHCPOFFER packet (described in RFC2131 4.3.1): - c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)) - for { - offer, err := dhcp4.Read(c.connection) - if err != nil { - return nil, err - } - if offer == nil { - continue // not a DHCPv4 packet - } - if offer.Xid != discover.Xid { - continue // broadcast reply for different DHCP transaction - } - if !dhcp4.HasMessageType(offer.Options, layers.DHCPMsgTypeOffer) { - continue - } - last = offer - break - } - } - - // Build a DHCPREQUEST packet: - request := c.packet(last.Xid, append([]layers.DHCPOption{ - dhcp4.MessageTypeOpt(layers.DHCPMsgTypeRequest), - dhcp4.RequestIPOpt(last.YourClientIP), - dhcp4.HostnameOpt(c.Hostname), - dhcp4.ClientIDOpt(layers.LinkTypeEthernet, c.hardwareAddr), - dhcp4.ParamsRequestOpt( - layers.DHCPOptDNS, - layers.DHCPOptRouter, - layers.DHCPOptSubnetMask), - }, serverID(last)...)) - if err := dhcp4.Write(c.connection, request); err != nil { - return nil, err - } - - c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)) - for { - // Look for DHCPACK packet (described in RFC2131 4.3.1): - ack, err := dhcp4.Read(c.connection) - if err != nil { - return nil, err - } - if ack == nil { - continue // not a DHCPv4 packet - } - if ack.Xid != request.Xid { - continue // broadcast reply for different DHCP transaction - } - if !dhcp4.HasMessageType(ack.Options, layers.DHCPMsgTypeAck) { - if dhcp4.HasMessageType(ack.Options, layers.DHCPMsgTypeNak) { - return nil, errNAK - } - continue - } - return ack, nil - } -} From 27451767c32e684c5e28c9ee1f15b8d519a0224e Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 9 Jul 2021 11:37:47 +0100 Subject: [PATCH 120/542] Fixes re-application of VIP --- cmd/kube-vip-config.go | 2 +- cmd/kube-vip-kubeadm.go | 2 +- cmd/kube-vip-manifests.go | 2 +- cmd/kube-vip-start.go | 6 ++--- cmd/kube-vip.go | 6 ++--- demo/go.mod | 2 +- docs/architecture/index.md | 4 +-- docs/kubernetes/arp/index.md | 2 +- docs/kubernetes/bgp/index.md | 2 +- docs/kubernetes/index.md | 2 +- go.mod | 2 +- main.go | 2 +- pkg/cluster/cluster.go | 4 +-- pkg/cluster/clusterDDNS.go | 3 ++- pkg/cluster/clusterLeader.go | 39 +++++++++++++++--------------- pkg/cluster/clusterRaft.go | 6 ++--- pkg/cluster/singleNode.go | 38 +++++++++++++++-------------- pkg/kubevip/config_generator.go | 4 +-- pkg/kubevip/config_types.go | 2 +- pkg/loadbalancer/lb_connections.go | 2 +- pkg/loadbalancer/lb_http.go | 2 +- pkg/loadbalancer/lb_tcp.go | 2 +- pkg/loadbalancer/manager.go | 2 +- pkg/manager/manager.go | 8 +++--- pkg/manager/manager_arp.go | 4 +-- pkg/manager/manager_bgp.go | 8 +++--- pkg/manager/services.go | 7 +++--- pkg/manager/services_dhcp.go | 6 ++--- pkg/packet/bgp.go | 4 +-- pkg/packet/eip.go | 2 +- pkg/service/manager.go | 8 +++--- pkg/service/manager_bgp.go | 4 +-- pkg/service/services.go | 6 ++--- pkg/service/services_dhcp.go | 6 ++--- pkg/service/watcher.go | 2 +- 35 files changed, 102 insertions(+), 101 deletions(-) diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index 8d0d031a..cfcf744a 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/ghodss/yaml" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" appv1 "k8s.io/api/core/v1" diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index 842ca0b2..396ec87e 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -6,7 +6,7 @@ import ( "net" "os" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 4de46932..66c6fbc8 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 20b51375..d18bc542 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -4,9 +4,9 @@ import ( "os" "os/signal" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 11259b56..19bb85a2 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -7,9 +7,9 @@ import ( "os" "time" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/manager" - "github.com/plunder-app/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/manager" + "github.com/kube-vip/kube-vip/pkg/packet" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" diff --git a/demo/go.mod b/demo/go.mod index a9427e42..02df02d9 100644 --- a/demo/go.mod +++ b/demo/go.mod @@ -1,3 +1,3 @@ -module github.com/plunder-app/kube-vip/demo +module github.com/kube-vip/kube-vip/demo go 1.13 diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 1d6465d3..81859844 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -103,8 +103,8 @@ Additionally the load-balancing within `kibe-vip` has two modes of operation: The `kube-vip` kubernetes load-balancer requires a number of components in order to function: -- The Plunder Cloud Provider -> [https://github.com/plunder-app/plndr-cloud-provider](https://github.com/plunder-app/plndr-cloud-provider) -- The Kube-Vip Deployment -> [https://github.com/plunder-app/kube-vip](https://github.com/plunder-app/kube-vip) +- The Plunder Cloud Provider -> [https://github.com/kube-vip/plndr-cloud-provider](https://github.com/kube-vip/plndr-cloud-provider) +- The Kube-Vip Deployment -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) ### Architecture overview diff --git a/docs/kubernetes/arp/index.md b/docs/kubernetes/arp/index.md index 29b54c63..21caadb9 100644 --- a/docs/kubernetes/arp/index.md +++ b/docs/kubernetes/arp/index.md @@ -26,7 +26,7 @@ $ kubectl describe configmap -n kube-system kube-proxy | grep ARP To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml`, specific versions should be found in the repository as detailed below: -From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. +From the GitHub repository [https://github.com/kube-vip/kube-vip/tree/master/example/deploy](https://github.com/kube-vip/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. The following output should appear when the manifest is applied: ``` diff --git a/docs/kubernetes/bgp/index.md b/docs/kubernetes/bgp/index.md index 8929bc65..160376c0 100644 --- a/docs/kubernetes/bgp/index.md +++ b/docs/kubernetes/bgp/index.md @@ -4,7 +4,7 @@ To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml`, specific versions should be found in the repository as detailed below: -From the GitHub repository [https://github.com/plunder-app/kube-vip/tree/master/example/deploy](https://github.com/plunder-app/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. +From the GitHub repository [https://github.com/kube-vip/kube-vip/tree/master/example/deploy](https://github.com/kube-vip/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. The following output should appear when the manifest is applied: ``` diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md index a345e522..2078d83e 100644 --- a/docs/kubernetes/index.md +++ b/docs/kubernetes/index.md @@ -33,7 +33,7 @@ Edit the `configmap` and add in the cidr ranges for those namespaces, the key in To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/controller.yaml`, specific versions should be found in the repository as detailed below: -From the GitHub repository [https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod](https://github.com/plunder-app/plndr-cloud-provider/tree/master/example/pod), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. +From the GitHub repository [https://github.com/kube-vip/plndr-cloud-provider/tree/master/example/pod](https://github.com/kube-vip/plndr-cloud-provider/tree/master/example/pod), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. The following output should appear when the manifest is applied: diff --git a/go.mod b/go.mod index d1308803..125cdc6b 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/plunder-app/kube-vip +module github.com/kube-vip/kube-vip go 1.14 diff --git a/main.go b/main.go index 313f5f91..3bd6f4dc 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,6 @@ package main -import "github.com/plunder-app/kube-vip/cmd" +import "github.com/kube-vip/kube-vip/cmd" // Version is populated from the Makefile and is tied to the release TAG var Version string diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 46d3e68f..1d524a03 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -1,8 +1,8 @@ package cluster import ( - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" ) const leaderLogcount = 5 diff --git a/pkg/cluster/clusterDDNS.go b/pkg/cluster/clusterDDNS.go index 7d045e7f..9f904ef2 100644 --- a/pkg/cluster/clusterDDNS.go +++ b/pkg/cluster/clusterDDNS.go @@ -2,7 +2,8 @@ package cluster import ( "context" - "github.com/plunder-app/kube-vip/pkg/vip" + + "github.com/kube-vip/kube-vip/pkg/vip" ) // StartDDNS should start go routine for dhclient to hold the lease for the IP diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index fa0d4f1f..79dbb199 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -9,13 +9,13 @@ import ( "syscall" "time" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/kubevip" - leaderelection "github.com/plunder-app/kube-vip/pkg/leaderElection" - "github.com/plunder-app/kube-vip/pkg/loadbalancer" - "github.com/plunder-app/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/kubevip" + leaderelection "github.com/kube-vip/kube-vip/pkg/leaderElection" + "github.com/kube-vip/kube-vip/pkg/loadbalancer" + "github.com/kube-vip/kube-vip/pkg/packet" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/vip" "github.com/packethost/packngo" @@ -295,24 +295,23 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } for { - - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } - select { case <-ctx.Done(): // if cancel() execute return default: + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + } + if vip.IsIPv4(ipString) { // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address err := vip.ARPSendGratuitous(ipString, c.Interface) diff --git a/pkg/cluster/clusterRaft.go b/pkg/cluster/clusterRaft.go index 9734e2bc..08218384 100644 --- a/pkg/cluster/clusterRaft.go +++ b/pkg/cluster/clusterRaft.go @@ -6,9 +6,9 @@ import ( "time" "github.com/hashicorp/raft" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/loadbalancer" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/loadbalancer" + "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 69307fbf..cc33a9a8 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -7,10 +7,10 @@ import ( log "github.com/sirupsen/logrus" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/loadbalancer" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/loadbalancer" + "github.com/kube-vip/kube-vip/pkg/vip" ) // StartSingleNode will start a single node cluster @@ -148,23 +148,24 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } for { - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } select { case <-ctx.Done(): // if cancel() execute return default: + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + } + if vip.IsIPv4(ipString) { // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address err := vip.ARPSendGratuitous(ipString, c.Interface) @@ -198,14 +199,15 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser for { select { case <-cluster.stop: + // Stop the Arp context if it is running + cancelArp() + log.Info("[LOADBALANCER] Stopping load balancers") log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) err = cluster.Network.DeleteIP() if err != nil { log.Warnf("%v", err) } - // Stop the Arp context if it is running - cancelArp() close(cluster.completed) return diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 821e20d2..d7763499 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -7,8 +7,8 @@ import ( "strings" "github.com/ghodss/yaml" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/detector" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/detector" log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 59e6f32d..0cb003e2 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -3,7 +3,7 @@ package kubevip import ( "net/url" - "github.com/plunder-app/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/bgp" ) // Config defines all of the settings for the Kube-Vip Pod diff --git a/pkg/loadbalancer/lb_connections.go b/pkg/loadbalancer/lb_connections.go index b7dd1c7a..7dbce424 100644 --- a/pkg/loadbalancer/lb_connections.go +++ b/pkg/loadbalancer/lb_connections.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/loadbalancer/lb_http.go b/pkg/loadbalancer/lb_http.go index 4a7b7387..7a0bef40 100644 --- a/pkg/loadbalancer/lb_http.go +++ b/pkg/loadbalancer/lb_http.go @@ -8,7 +8,7 @@ import ( "net/url" "time" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/loadbalancer/lb_tcp.go b/pkg/loadbalancer/lb_tcp.go index fcb1442f..78cac55b 100644 --- a/pkg/loadbalancer/lb_tcp.go +++ b/pkg/loadbalancer/lb_tcp.go @@ -7,7 +7,7 @@ import ( "net" "time" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/loadbalancer/manager.go b/pkg/loadbalancer/manager.go index 7c191320..550d4359 100644 --- a/pkg/loadbalancer/manager.go +++ b/pkg/loadbalancer/manager.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index d3a8a9fc..5f7ef6e3 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -16,10 +16,10 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" ) const plunderLock = "plndr-svcs-lock" diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 576117a3..cd46878b 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -8,8 +8,8 @@ import ( "time" "github.com/kamhlos/upnp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection" diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index da3c0838..6b69ae6e 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -5,11 +5,11 @@ import ( "os" "syscall" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/vip" "github.com/packethost/packngo" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/packet" - "github.com/plunder-app/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 12c9dd7a..6f925dfa 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -11,12 +11,12 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" ) const ( - hwAddrKey = "kube-vip.io/hwaddr" + hwAddrKey = "kube-vip.io/hwaddr" requestedIP = "kube-vip.io/requestedIP" ) @@ -73,7 +73,6 @@ func (sm *Manager) deleteService(uid string) error { return nil } - func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() diff --git a/pkg/manager/services_dhcp.go b/pkg/manager/services_dhcp.go index b02e0acd..87ef6430 100644 --- a/pkg/manager/services_dhcp.go +++ b/pkg/manager/services_dhcp.go @@ -12,9 +12,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" ) func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { diff --git a/pkg/packet/bgp.go b/pkg/packet/bgp.go index 01e80f14..778055ca 100644 --- a/pkg/packet/bgp.go +++ b/pkg/packet/bgp.go @@ -3,9 +3,9 @@ package packet import ( "fmt" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/packethost/packngo" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index 901eb19a..e5bf8478 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -4,8 +4,8 @@ import ( "fmt" "path" + "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/packethost/packngo" - "github.com/plunder-app/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 944328cf..2402a868 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -14,10 +14,10 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" ) const plunderLock = "plunder-lock" diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index c5b332ea..259f52d1 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -6,9 +6,9 @@ import ( "os/signal" "syscall" + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/packet" "github.com/packethost/packngo" - "github.com/plunder-app/kube-vip/pkg/bgp" - "github.com/plunder-app/kube-vip/pkg/packet" log "github.com/sirupsen/logrus" ) diff --git a/pkg/service/services.go b/pkg/service/services.go index c2bf49ee..a4a1bddd 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -5,8 +5,8 @@ import ( "fmt" "strings" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" @@ -14,7 +14,7 @@ import ( ) const ( - hwAddrKey = "kube-vip.io/hwaddr" + hwAddrKey = "kube-vip.io/hwaddr" requestedIP = "kube-vip.io/requestedIP" ) diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index 4eedfee0..dc8a6ed1 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -12,9 +12,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/plunder-app/kube-vip/pkg/cluster" - "github.com/plunder-app/kube-vip/pkg/kubevip" - "github.com/plunder-app/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" ) func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index 171e2b01..4d5dd72f 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -13,7 +13,7 @@ import ( "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" - "github.com/plunder-app/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/kubevip" ) func rebuildEndpoints(eps v1.Endpoints) []kubevip.BackEnd { From c395d45200d6c79b127ccd126c9b029285e73fa4 Mon Sep 17 00:00:00 2001 From: Abhinav Pandey Date: Mon, 12 Jul 2021 09:01:33 -0700 Subject: [PATCH 121/542] Add example manifest for kube-vip:v0.3.5 --- example/deploy/0.3.5.yaml | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 example/deploy/0.3.5.yaml diff --git a/example/deploy/0.3.5.yaml b/example/deploy/0.3.5.yaml new file mode 100644 index 00000000..a93da17f --- /dev/null +++ b/example/deploy/0.3.5.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: svc_enable + value: "true" + - name: vip_startleader + value: "false" + - name: vip_addpeerstolb + value: "true" + - name: vip_localpeer + value: ip-172-20-40-207:172.20.40.207:10000 + - name: vip_address + image: plndr/kube-vip:v0.3.5 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 From 81f7338dbd733c0aee3996ea9ee860548ab86a1a Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 21 Jul 2021 15:42:43 +0100 Subject: [PATCH 122/542] Update index.md --- docs/index.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 85e156a4..c56d3491 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,3 @@ -# Kube-vip - ![kube-vip.png](kube-vip.png) ## Overview @@ -71,4 +69,10 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we ## Links - The Kube-Vip Cloud Provider Repository -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) -- The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) \ No newline at end of file +- The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) + +© 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All right reserved + +The Linux Foundation has registered trademarks and uses trademarks. + +For a list trademarks of The Linux Foundation, please see our [Trademark Usage page](https://www.linuxfoundation.org/en/trademark-usage). From aa155cd7d50c502b4a2292b1405fb00fa626e1a2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 21 Jul 2021 15:43:59 +0100 Subject: [PATCH 123/542] Update index.md --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index c56d3491..62764183 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,6 +71,8 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we - The Kube-Vip Cloud Provider Repository -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) - The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) +## Copyright + © 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All right reserved The Linux Foundation has registered trademarks and uses trademarks. From df8a3addc10fd6ba721eb6faea7fc2017d90ae3b Mon Sep 17 00:00:00 2001 From: Manjunath A Kumatagi Date: Fri, 23 Jul 2021 09:38:35 +0530 Subject: [PATCH 124/542] Add support for ppc64le architecture --- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- Makefile | 6 +++--- demo/Makefile | 2 +- docs/architecture/index.md | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 7bdce92f..03891912 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -35,7 +35,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64 + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.prep.outputs.tags }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e24ef4f9..c913f2e1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64 + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.prep.outputs.tags }} diff --git a/Makefile b/Makefile index 828cf328..6208c1b5 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ fmt: demo: @cd demo - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created @cd .. @@ -54,7 +54,7 @@ dockerx86: docker: @-rm ./kube-vip - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created ## Local (docker load of images) @@ -71,7 +71,7 @@ dockerx86Action: dockerLocal: @-rm ./kube-vip - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created simplify: diff --git a/demo/Makefile b/demo/Makefile index 216c881a..1804f5e8 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -45,7 +45,7 @@ fmt: @gofmt -l -w $(SRC) docker: - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created simplify: diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 1d6465d3..3602c7fc 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -7,7 +7,7 @@ This section covers two parts of the architecture: The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expanded to provide the same functionality for applications within a Kubernetes cluster. -Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). +Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`,`ppc64le`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). ## Technologies From 976d2f64fbe859f18fad4537d471f67ead03ec2f Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 23 Jul 2021 17:52:51 +0100 Subject: [PATCH 125/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 82ae1654..6335eb71 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.3.5 +VERSION := v0.3.7 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 31448255e8f7ee730370d8a480fed539fdc0febf Mon Sep 17 00:00:00 2001 From: David McKay Date: Sat, 24 Jul 2021 16:34:37 +0100 Subject: [PATCH 126/542] chore: use git to fetch latest tag --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6335eb71..6f73a7a8 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.3.7 +VERSION := $(git tag -l | sort -r | head -n1) BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 39043ce0f8597d8ed867455d18d0086d548c1849 Mon Sep 17 00:00:00 2001 From: David McKay Date: Sat, 24 Jul 2021 16:35:04 +0100 Subject: [PATCH 127/542] fix: backticks are deprecated and not POSIX compat, replace with $() --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6f73a7a8..1467d6c1 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET := kube-vip # These will be provided to the target VERSION := $(git tag -l | sort -r | head -n1) -BUILD := `git rev-parse HEAD` +BUILD := $(git rev-parse HEAD) # Operating System Default (LINUX) TARGETOS=linux From a26288a1d04484bec11403adf4dcd6b8c0fe4502 Mon Sep 17 00:00:00 2001 From: David McKay Date: Sat, 24 Jul 2021 16:53:57 +0100 Subject: [PATCH 128/542] chore: encourage useage of GHCR instead of rate limited Docker Hub --- Makefile | 4 ++-- cmd/kube-vip-config.go | 2 +- docs/control-plane/index.md | 18 +++++++++--------- docs/hybrid/daemonset/index.md | 6 +++--- docs/hybrid/static/index.md | 4 ++-- docs/install_daemonset/index.md | 6 +++--- docs/install_static/index.md | 4 ++-- docs/k3s | 2 +- docs/manifests/kube-vip-arp.yaml | 2 +- docs/manifests/kube-vip-bgp.yaml | 2 +- docs/manifests/kube-vip-em.yaml | 2 +- docs/manifests/kube-vip.yaml | 2 +- docs/usage/k3s/index.md | 4 ++-- docs/usage/kind/index.md | 2 +- example/deploy/0.1.2.yaml | 2 +- example/deploy/0.1.3.yaml | 2 +- kubernetes-control-plane.md | 8 ++++---- pkg/kubevip/config_generator.go | 2 +- 18 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 1467d6c1..6335eb71 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := $(git tag -l | sort -r | head -n1) -BUILD := $(git rev-parse HEAD) +VERSION := v0.3.7 +BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) TARGETOS=linux diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index cfcf744a..8d227d27 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -104,7 +104,7 @@ var kubeVipSampleManifest = &cobra.Command{ Containers: []appv1.Container{ { Name: "kube-vip", - Image: fmt.Sprintf("docker.io/plndr/kube-vip:%s", Release.Version), + Image: fmt.Sprintf("ghcr.io/kube-vip/kube-vip:%s", Release.Version), SecurityContext: &appv1.SecurityContext{ Capabilities: &appv1.Capabilities{ Add: []appv1.Capability{ diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md index 14c3e71c..f7a5867e 100644 --- a/docs/control-plane/index.md +++ b/docs/control-plane/index.md @@ -20,7 +20,7 @@ Below are examples of the steps required: ``` # First Node -sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ +sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -32,7 +32,7 @@ sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0 sudo kubeadm join 192.168.0.75:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 -sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ +sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ --arp \ @@ -59,7 +59,7 @@ All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.2.1 \ + --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ @@ -108,7 +108,7 @@ spec: value: "1" - name: vip_address value: 192.168.0.75 - image: plndr/kube-vip:0.2.1 + image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip resources: {} @@ -129,7 +129,7 @@ Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/man ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.2.1 \ + --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ @@ -137,7 +137,7 @@ sudo docker run --network host \ --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml ``` -Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1.8` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. +Ensure that `image: ghcr.io/kube-vip/kube-vip:` is modified to point to a specific version (`0.3.7` at the time of writing), refer to [GitHyb](https://github.com/kube-vip/kube-vip/pkgs/container/kube-vip) for details. The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. @@ -168,7 +168,7 @@ At this point **DON’T** generate the manifests, this is due to some bizarre `k ``` sudo docker run --network host \ - --rm plndr/kube-vip:0.2.1 \ + --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ manifest pod \ --interface ens192 \ --vip 192.168.0.75 \ @@ -243,7 +243,7 @@ export PACKET_AUTH_TOKEN=XYZ ``` # Generate the manifest -sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ +sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ --arp=false \ --interface lo \ --vip $EIP \ @@ -265,7 +265,7 @@ kubeadm join $EIP:6443 --token BLAH --control-plane --certificate-key BLAH --dis # Generate Manifest -sudo docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod \ +sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ --arp=false \ --interface lo \ --vip $EIP \ diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 49016d5d..0f8130ac 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -36,10 +36,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` ### BGP Example @@ -108,7 +108,7 @@ spec: value: "192.168.0.10:65000::false,192.168.0.11:65000::false" - name: vip_address value: 192.168.0.40 - image: plndr/kube-vip:0.2.3 + image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip resources: {} diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index b95b80d5..d07f3356 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -19,10 +19,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` ### ARP diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 5fc573de..ad739416 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -41,10 +41,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip"` #### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` ### BGP Example @@ -122,7 +122,7 @@ spec: value: 192.168.0.10:65000::false,192.168.0.11:65000::false - name: vip_address value: 192.168.0.40 - image: 'plndr/kube-vip:' + image: 'ghcr.io/kube-vip/kube-vip:' imagePullPolicy: Always name: kube-vip resources: {} diff --git a/docs/install_static/index.md b/docs/install_static/index.md index a1ba64e6..b8e4ce79 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -32,10 +32,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` ## ARP diff --git a/docs/k3s b/docs/k3s index 477a695d..73840e89 100644 --- a/docs/k3s +++ b/docs/k3s @@ -36,7 +36,7 @@ spec: value: \"false\" - name: vip_address value: $vipAddress - image: plndr/kube-vip:v0.3.5 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 imagePullPolicy: Always name: kube-vip resources: {} diff --git a/docs/manifests/kube-vip-arp.yaml b/docs/manifests/kube-vip-arp.yaml index 503b23f4..f16dadcc 100644 --- a/docs/manifests/kube-vip-arp.yaml +++ b/docs/manifests/kube-vip-arp.yaml @@ -62,7 +62,7 @@ spec: - kube-vip-workers topologyKey: "kubernetes.io/hostname" containers: - - image: plndr/kube-vip:0.2.2 + - image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip command: diff --git a/docs/manifests/kube-vip-bgp.yaml b/docs/manifests/kube-vip-bgp.yaml index 83b43e71..53d5e738 100644 --- a/docs/manifests/kube-vip-bgp.yaml +++ b/docs/manifests/kube-vip-bgp.yaml @@ -59,7 +59,7 @@ spec: - kube-vip-workers topologyKey: "kubernetes.io/hostname" containers: - - image: plndr/kube-vip:0.2.2 + - image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip command: diff --git a/docs/manifests/kube-vip-em.yaml b/docs/manifests/kube-vip-em.yaml index 0cf6e178..08ec4e21 100644 --- a/docs/manifests/kube-vip-em.yaml +++ b/docs/manifests/kube-vip-em.yaml @@ -64,7 +64,7 @@ spec: value: "true" - name: bgp_enable value: "true" - image: plndr/kube-vip:0.2.3 + image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip resources: {} diff --git a/docs/manifests/kube-vip.yaml b/docs/manifests/kube-vip.yaml index a693e6a1..b76bf985 100644 --- a/docs/manifests/kube-vip.yaml +++ b/docs/manifests/kube-vip.yaml @@ -58,7 +58,7 @@ spec: - kube-vip-cluster topologyKey: "kubernetes.io/hostname" containers: - - image: plndr/kube-vip:0.1.3 + - image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip command: diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 85863e73..34efb8a5 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -45,10 +45,10 @@ curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee ## Step 3.2 Genereate from container image ### containerd -`alias kube-vip="ctr run --rm --net-host docker.io/plndr/kube-vip:0.3.1 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm plndr/kube-vip:0.3.1"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` ``` diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index c831e172..1b4088b4 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -30,7 +30,7 @@ kubectl create configmap --namespace kube-system kubevip --from-literal range-gl Set the correct `alias` for `kube-vip` ``` -alias kube-vip="docker run --network host --rm plndr/kube-vip:v0.3.5" +alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.7" ``` Install Kube-vip deamonset inside of KIND diff --git a/example/deploy/0.1.2.yaml b/example/deploy/0.1.2.yaml index 4e5c5a2f..2f6caa31 100644 --- a/example/deploy/0.1.2.yaml +++ b/example/deploy/0.1.2.yaml @@ -28,7 +28,7 @@ spec: - kube-vip-cluster topologyKey: "kubernetes.io/hostname" containers: - - image: plndr/kube-vip:0.1.2 + - image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip command: diff --git a/example/deploy/0.1.3.yaml b/example/deploy/0.1.3.yaml index a693e6a1..b76bf985 100644 --- a/example/deploy/0.1.3.yaml +++ b/example/deploy/0.1.3.yaml @@ -58,7 +58,7 @@ spec: - kube-vip-cluster topologyKey: "kubernetes.io/hostname" containers: - - image: plndr/kube-vip:0.1.3 + - image: ghcr.io/kube-vip/kube-vip:0.3.7 imagePullPolicy: Always name: kube-vip command: diff --git a/kubernetes-control-plane.md b/kubernetes-control-plane.md index 0bf508bc..835862a8 100644 --- a/kubernetes-control-plane.md +++ b/kubernetes-control-plane.md @@ -26,7 +26,7 @@ All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. Make sure that the config directory exists: `sudo mkdir -p /etc/kube-vip/`, this directory can be any directory however the `hostPath` in the manifest will need modifying to point to the correct path. ``` -sudo docker run -it --rm plndr/kube-vip:0.1.5 sample config | sudo tee /etc/kube-vip/config.yaml +sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample config | sudo tee /etc/kube-vip/config.yaml ``` ### Modify the configuration @@ -90,10 +90,10 @@ To generate the basic Kubernetes static pod `yaml` configuration: Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` ``` -sudo docker run -it --rm plndr/kube-vip:0.1.5 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml +sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml ``` -Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1.5` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isn’t the above path. +Ensure that `image: ghcr.io/kube-vip/kube-vip:` is modified to point to a specific version (`0.3.7` at the time of writing), refer to [GitHub](https://github.com/kube-vip/kube-vip/pkgs/container/kube-vip) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isn’t the above path. The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. @@ -124,7 +124,7 @@ At this point **DON’T** generate the manifests, this is due to some bizarre `k **After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). ``` -sudo docker run -it --rm plndr/kube-vip:0.1.5 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml +sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml ``` Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index d7763499..5539a1a0 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -720,7 +720,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Containers: []corev1.Container{ { Name: "kube-vip", - Image: fmt.Sprintf("plndr/kube-vip:%s", imageVersion), + Image: fmt.Sprintf("ghcr.io/kube-vip/kube-vip:%s", imageVersion), ImagePullPolicy: corev1.PullAlways, SecurityContext: &corev1.SecurityContext{ Capabilities: &corev1.Capabilities{ From fc24064e2a5f2fed7b1a4cd8b93751d42f433795 Mon Sep 17 00:00:00 2001 From: David McKay Date: Mon, 26 Jul 2021 09:40:25 +0100 Subject: [PATCH 129/542] fix: ensure node annotations are checked before watch --- pkg/manager/watcher.go | 137 ++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 55 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 957245f5..c147b28a 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -120,6 +120,25 @@ func (sm *Manager) annotationsWatcher() error { LabelSelector: labels.Set(labelSelector.MatchLabels).String(), } + // First we'll check the annotations for the node and if + // they aren't what are expected, we'll drop into the watch until they are + nodeList, err := sm.clientSet.CoreV1().Nodes().List(context.Background(), listOptions) + if err != nil { + return err + } + + // We'll assume there's only one node with the hostname annotation. If that's not true, + // there's probably bigger problems + node := nodeList.Items[0] + if err = sm.parseNodeAnnotations(&node); err == nil { + // No error, the annotations already exist. + return nil + } + + // We got an error with the annotations, falling back to the watch until + // they're as needed + log.Warn(err) + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { return sm.clientSet.CoreV1().Nodes().Watch(context.Background(), listOptions) @@ -140,7 +159,6 @@ func (sm *Manager) annotationsWatcher() error { //defer rw.Stop() for event := range ch { - // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added, watch.Modified: @@ -149,63 +167,11 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") } - // BGP Local configuration - nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] - if nodeASN != "" { - u64, err := strconv.ParseUint(nodeASN, 10, 32) - if err != nil { - return err - } - sm.config.BGPConfig.AS = uint32(u64) - } else { - continue - } - - srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] - if srcIP != "" { - sm.config.BGPConfig.RouterID = srcIP - } else { - continue - } - - // Peer configuration [REQUIRED] - peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] - if peerASN != "" { - u64, err := strconv.ParseUint(peerASN, 10, 32) - if err != nil { - return err - } - sm.config.BGPPeerConfig.AS = uint32(u64) - } else { + if err := sm.parseNodeAnnotations(node); err != nil { + log.Error(err) continue } - peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] - - peerIPs := strings.Split(peerIPString, ",") - - for _, peerIP := range peerIPs { - ipAddr := strings.TrimSpace(peerIP) - - if ipAddr != "" { - sm.config.BGPPeerConfig.Address = ipAddr - sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) - } - } - - // BGP Password, if it doesn't find a password don't "continue" [OPTIONAL] - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] - if base64BGPPassword != "" { - // Decode base64 encoded string - decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) - if err != nil { - return err - } - sm.config.BGPPeerConfig.Password = string(decodedPassword) - } - - log.Debugf("%s / %d / %s / %d /n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) - rw.Stop() break case watch.Deleted: @@ -239,3 +205,64 @@ func (sm *Manager) annotationsWatcher() error { return nil } + +// parseNodeAnnotations parses the annotations on the node and updates the configuration +// returning an error if the annotations are not valid or missing; and nil if everything is OK +// to continue +func (sm *Manager) parseNodeAnnotations(node *v1.Node) error { + nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] + if nodeASN == "" { + return fmt.Errorf("node-asn value missing or empty") + } + + u64, err := strconv.ParseUint(nodeASN, 10, 32) + if err != nil { + return err + } + + sm.config.BGPConfig.AS = uint32(u64) + + srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] + if srcIP == "" { + return fmt.Errorf("src-ip value missing or empty") + } + + sm.config.BGPConfig.RouterID = srcIP + + peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] + if peerASN == "" { + return fmt.Errorf("peer-asn value missing or empty") + } + + u64, err = strconv.ParseUint(peerASN, 10, 32) + if err != nil { + return err + } + sm.config.BGPPeerConfig.AS = uint32(u64) + + peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] + + peerIPs := strings.Split(peerIPString, ",") + + for _, peerIP := range peerIPs { + ipAddr := strings.TrimSpace(peerIP) + + if ipAddr != "" { + sm.config.BGPPeerConfig.Address = ipAddr + sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + } + } + + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] + if base64BGPPassword != "" { + // Decode base64 encoded string + decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) + if err != nil { + return err + } + sm.config.BGPPeerConfig.Password = string(decodedPassword) + } + + log.Debugf("%s / %d / %s / %d /n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) + return nil +} From 7c644d680d8198bdec8503656df3cf3d917ea952 Mon Sep 17 00:00:00 2001 From: David McKay Date: Mon, 26 Jul 2021 11:01:40 +0100 Subject: [PATCH 130/542] chore: use node ResourceVersion --- pkg/manager/watcher.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index c147b28a..973ae928 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -139,7 +139,7 @@ func (sm *Manager) annotationsWatcher() error { // they're as needed log.Warn(err) - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + rw, err := watchtools.NewRetryWatcher(node.ResourceVersion, &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { return sm.clientSet.CoreV1().Nodes().Watch(context.Background(), listOptions) }, @@ -167,7 +167,7 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") } - if err := sm.parseNodeAnnotations(node); err != nil { + if err := sm.parseBgpAnnotations(node); err != nil { log.Error(err) continue } @@ -209,7 +209,7 @@ func (sm *Manager) annotationsWatcher() error { // parseNodeAnnotations parses the annotations on the node and updates the configuration // returning an error if the annotations are not valid or missing; and nil if everything is OK // to continue -func (sm *Manager) parseNodeAnnotations(node *v1.Node) error { +func (sm *Manager) parseBgpAnnotations(node *v1.Node) error { nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] if nodeASN == "" { return fmt.Errorf("node-asn value missing or empty") From 76dbce050cd9386d6ebdf72eb852ade5b47492a3 Mon Sep 17 00:00:00 2001 From: David McKay Date: Mon, 26 Jul 2021 11:33:02 +0100 Subject: [PATCH 131/542] chore: add tests for parseBgpAnnotations --- go.mod | 1 + go.sum | 2 ++ pkg/manager/watcher.go | 61 +++++++++++++++++++++++-------------- pkg/manager/watcher_test.go | 58 +++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 pkg/manager/watcher_test.go diff --git a/go.mod b/go.mod index 125cdc6b..bc20a3b4 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 // indirect + github.com/stretchr/testify v1.7.0 // indirect github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect diff --git a/go.sum b/go.sum index 85bb978e..9c1bd4dd 100644 --- a/go.sum +++ b/go.sum @@ -596,6 +596,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 973ae928..9ec2f82b 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -9,6 +9,7 @@ import ( "strings" "sync" + "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -130,8 +131,12 @@ func (sm *Manager) annotationsWatcher() error { // We'll assume there's only one node with the hostname annotation. If that's not true, // there's probably bigger problems node := nodeList.Items[0] - if err = sm.parseNodeAnnotations(&node); err == nil { - // No error, the annotations already exist. + + bgpConfig, bgpPeer, err := parseBgpAnnotations(&node, sm.config.Annotations) + if err == nil { + // No error, the annotations already exist + sm.config.BGPConfig = bgpConfig + sm.config.BGPPeerConfig = bgpPeer return nil } @@ -167,11 +172,15 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") } - if err := sm.parseBgpAnnotations(node); err != nil { + bgpConfig, bgpPeer, err := parseBgpAnnotations(node, sm.config.Annotations) + if err != nil { log.Error(err) continue } + sm.config.BGPConfig = bgpConfig + sm.config.BGPPeerConfig = bgpPeer + rw.Stop() break case watch.Deleted: @@ -209,38 +218,42 @@ func (sm *Manager) annotationsWatcher() error { // parseNodeAnnotations parses the annotations on the node and updates the configuration // returning an error if the annotations are not valid or missing; and nil if everything is OK // to continue -func (sm *Manager) parseBgpAnnotations(node *v1.Node) error { - nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", sm.config.Annotations)] +func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { + bgpConfig := bgp.Config{} + bgpPeer := bgp.Peer{} + + nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] if nodeASN == "" { - return fmt.Errorf("node-asn value missing or empty") + return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") } u64, err := strconv.ParseUint(nodeASN, 10, 32) if err != nil { - return err + return bgpConfig, bgpPeer, err } - sm.config.BGPConfig.AS = uint32(u64) + bgpConfig.AS = uint32(u64) - srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", sm.config.Annotations)] + srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] if srcIP == "" { - return fmt.Errorf("src-ip value missing or empty") + return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") } - sm.config.BGPConfig.RouterID = srcIP + bgpConfig.RouterID = srcIP - peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", sm.config.Annotations)] + peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] if peerASN == "" { - return fmt.Errorf("peer-asn value missing or empty") + return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") } u64, err = strconv.ParseUint(peerASN, 10, 32) if err != nil { - return err + return bgpConfig, bgpPeer, err } - sm.config.BGPPeerConfig.AS = uint32(u64) - peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", sm.config.Annotations)] + bgpPeer.AS = uint32(u64) + + peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] peerIPs := strings.Split(peerIPString, ",") @@ -248,21 +261,23 @@ func (sm *Manager) parseBgpAnnotations(node *v1.Node) error { ipAddr := strings.TrimSpace(peerIP) if ipAddr != "" { - sm.config.BGPPeerConfig.Address = ipAddr - sm.config.BGPConfig.Peers = append(sm.config.BGPConfig.Peers, sm.config.BGPPeerConfig) + bgpPeer.Address = ipAddr + bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) } } - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", sm.config.Annotations)] + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] if base64BGPPassword != "" { // Decode base64 encoded string decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) if err != nil { - return err + return bgpConfig, bgpPeer, err } - sm.config.BGPPeerConfig.Password = string(decodedPassword) + bgpPeer.Password = string(decodedPassword) } - log.Debugf("%s / %d / %s / %d /n", sm.config.BGPConfig.RouterID, sm.config.BGPConfig.AS, sm.config.BGPConfig.Peers[0].Address, sm.config.BGPConfig.Peers[0].AS) - return nil + log.Debugf("BGPConfig: %v\n", bgpConfig) + log.Debugf("BGPPeerConfig: %v\n", bgpPeer) + + return bgpConfig, bgpPeer, nil } diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go new file mode 100644 index 00000000..05ed2733 --- /dev/null +++ b/pkg/manager/watcher_test.go @@ -0,0 +1,58 @@ +package manager + +import ( + "testing" + + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestParseBgpAnnotations(t *testing.T) { + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{}}, + } + + _, _, err := parseBgpAnnotations(node, "bgp") + if err == nil { + t.Fatal("Parsing BGP annotations should return an error when no annotations exist") + } + + node.Annotations = map[string]string{ + "bgp/node-asn": "1", + "bgp/peer-asn": "2", + "bgp/src-ip": "3", + } + + bgpConfig, bgpPeer, err := parseBgpAnnotations(node, "bgp") + if err != nil { + t.Fatal("Parsing BGP annotations should return nil when minimum config is met") + } + + assert.Equal(t, uint32(1), bgpConfig.AS, "bgpConfig.AS parsed incorrectly") + assert.Equal(t, uint32(2), bgpPeer.AS, "bgpPeer.AS parsed incorrectly") + assert.Equal(t, "3", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") + + node.Annotations = map[string]string{ + "bgp/node-asn": "1", + "bgp/peer-asn": "2", + "bgp/src-ip": "3", + "bgp/peer-ip": "1,2,3", + "bgp/bgp-pass": "cGFzc3dvcmQ=", // password + } + + bgpConfig, bgpPeer, err = parseBgpAnnotations(node, "bgp") + if err != nil { + t.Fatal("Parsing BGP annotations should return nil when minimum config is met") + } + + bgpPeers := []bgp.Peer{ + {Address: "1", AS: uint32(2)}, + {Address: "2", AS: uint32(2)}, + {Address: "3", AS: uint32(2)}, + } + assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") + assert.Equal(t, "3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") + assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") +} From a42a5e74935caf336b6a9bc46b1603adaab82e70 Mon Sep 17 00:00:00 2001 From: panpan0000 Date: Thu, 5 Aug 2021 02:19:14 -0400 Subject: [PATCH 132/542] fix typo of ServiceType --- docs/hybrid/services/index.md | 2 +- docs/usage/on-prem/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index f609b929..56a0665a 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -7,7 +7,7 @@ We've designed `kube-vip` to be as de-coupled or agnostic from other components This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: 1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = ServiceTypeLoadBalancer` +2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` 3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. 5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index 19b9196b..f2c0f362 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -7,7 +7,7 @@ We've designed `kube-vip` to be as de-coupled or agnostic from other components This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: 1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = ServiceTypeLoadBalancer` +2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` 3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. 5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. From 9188f554ab85a98cba9fbd26d91d3bf8d48f5a61 Mon Sep 17 00:00:00 2001 From: Jake Plimack Date: Mon, 16 Aug 2021 18:05:44 -0600 Subject: [PATCH 133/542] spelling Signed-off-by: Jake Plimack --- cmd/kube-vip-start.go | 2 +- pkg/cluster/clusterLeader.go | 2 +- pkg/manager/manager_bgp.go | 2 +- pkg/service/manager_arp.go | 2 +- pkg/service/manager_bgp.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index d18bc542..3a868627 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -96,7 +96,7 @@ var kubeVipStart = &cobra.Command{ } if startConfig.EnableBGP { - log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + log.Info("Starting the BGP server to advertise VIP routes to VGP peers") bgpServer, err = bgp.NewBGPServer(&startConfig.BGPConfig) if err != nil { log.Fatalf("%v", err) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 79dbb199..a0a0b222 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -170,7 +170,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if c.EnableBGP { // Lets start BGP - log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + log.Info("Starting the BGP server to advertise VIP routes to VGP peers") bgpServer, err = bgp.NewBGPServer(&c.BGPConfig) if err != nil { log.Error(err) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 6b69ae6e..a91a7c52 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -48,7 +48,7 @@ func (sm *Manager) startBGP() error { } } - log.Info("Starting the BGP server to adverise VIP routes to BGP peers") + log.Info("Starting the BGP server to advertise VIP routes to BGP peers") sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) if err != nil { return err diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index a2f05349..af471877 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -45,7 +45,7 @@ func (sm *Manager) startARP() error { // // If BGP is enabled then we start the server that will broadcast VIPs // if sm.config.EnableBGP { // // Lets start BGP - // log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + // log.Info("Starting the BGP server to advertise VIP routes to VGP peers") // sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) // if err != nil { // log.Error(err) diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 259f52d1..00694806 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -34,7 +34,7 @@ func (sm *Manager) startBGP() error { } } - log.Info("Starting the BGP server to adverise VIP routes to VGP peers") + log.Info("Starting the BGP server to advertise VIP routes to VGP peers") sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) if err != nil { return err From 2b0345cc86bcaaab9f5698d8315ca4c5f71ff339 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 25 Aug 2021 15:58:11 +0100 Subject: [PATCH 134/542] Adds BGP Source --- cmd/kube-vip.go | 3 + docs/manifests/v0.3.7/kube-vip-arp-ds.yaml | 65 ++++++++++++++ docs/manifests/v0.3.7/kube-vip-arp.yaml | 57 +++++++++++++ docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml | 74 ++++++++++++++++ docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml | 84 +++++++++++++++++++ docs/manifests/v0.3.7/kube-vip-bgp.yaml | 64 ++++++++++++++ go.mod | 2 +- go.sum | 1 - pkg/bgp/peers.go | 12 +-- pkg/bgp/server.go | 6 +- pkg/kubevip/config_envvar.go | 4 + pkg/kubevip/config_generator.go | 32 ++++++- pkg/kubevip/config_manager.go | 4 +- pkg/manager/watcher_test.go | 63 ++++++++++---- 14 files changed, 442 insertions(+), 29 deletions(-) create mode 100644 docs/manifests/v0.3.7/kube-vip-arp-ds.yaml create mode 100644 docs/manifests/v0.3.7/kube-vip-arp.yaml create mode 100644 docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml create mode 100644 docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml create mode 100644 docs/manifests/v0.3.7/kube-vip-bgp.yaml diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 19bb85a2..ba3fbb8b 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -103,6 +103,9 @@ func init() { // BGP flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableBGP, "bgp", false, "This will enable BGP support within kube-vip") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIP, "sourceIP", "", "The source address for bgp peering (not to be used with sourceIF)") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.AS, "localAS", 65000, "The local AS number for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") diff --git a/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml new file mode 100644 index 00000000..a5d14fd7 --- /dev/null +++ b/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.7/kube-vip-arp.yaml b/docs/manifests/v0.3.7/kube-vip-arp.yaml new file mode 100644 index 00000000..95ad7c18 --- /dev/null +++ b/docs/manifests/v0.3.7/kube-vip-arp.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml b/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml new file mode 100644 index 00000000..07fc64dc --- /dev/null +++ b/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml new file mode 100644 index 00000000..e4c7268b --- /dev/null +++ b/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: provider_config + value: /etc/cloud-sa/cloud-sa.json + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/cloud-sa + name: cloud-sa-volume + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - name: cloud-sa-volume + secret: + secretName: metal-cloud-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.7/kube-vip-bgp.yaml b/docs/manifests/v0.3.7/kube-vip-bgp.yaml new file mode 100644 index 00000000..cdc80317 --- /dev/null +++ b/docs/manifests/v0.3.7/kube-vip-bgp.yaml @@ -0,0 +1,64 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_startleader + value: "false" + - name: vip_addpeerstolb + value: "true" + - name: vip_localpeer + value: code:192.168.0.22:10000 + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.7 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/go.mod b/go.mod index bc20a3b4..4e70ded4 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 // indirect - github.com/stretchr/testify v1.7.0 // indirect + github.com/stretchr/testify v1.7.0 github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect diff --git a/go.sum b/go.sum index 9c1bd4dd..abf75e7a 100644 --- a/go.sum +++ b/go.sum @@ -594,7 +594,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index d4524ea1..7de454b6 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -50,13 +50,13 @@ func (b *Server) AddPeer(peer Peer) (err error) { }, } - // if b.c.SourceIP != "" { - // p.Transport.LocalAddress = b.c.SourceIP - // } + if b.c.SourceIP != "" { + p.Transport.LocalAddress = b.c.SourceIP + } - // if b.c.SourceIF != "" { - // p.Transport.BindInterface = b.c.SourceIF - // } + if b.c.SourceIF != "" { + p.Transport.BindInterface = b.c.SourceIF + } return b.s.AddPeer(context.Background(), &api.AddPeerRequest{ Peer: p, diff --git a/pkg/bgp/server.go b/pkg/bgp/server.go index 11555c4f..33f42e9f 100644 --- a/pkg/bgp/server.go +++ b/pkg/bgp/server.go @@ -16,9 +16,9 @@ func NewBGPServer(c *Config) (b *Server, err error) { return nil, fmt.Errorf("You need to provide AS") } - // if c.SourceIP != "" && c.SourceIF != "" { - // return nil, fmt.Errorf("SourceIP and SourceIF are mutually exclusive") - // } + if c.SourceIP != "" && c.SourceIF != "" { + return nil, fmt.Errorf("SourceIP and SourceIF are mutually exclusive") + } if len(c.Peers) == 0 { return nil, fmt.Errorf("You need to provide at least one peer") diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index cd3fbd9b..d6eeefd1 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -98,6 +98,10 @@ const ( bgpPeerPassword = "bgp_peerpass" //bgpMultiHop enables mulithop routing bgpMultiHop = "bgp_multihop" + //bgpSourceIF defines the source interface for BGP peering + bgpSourceIF = "bgp_source_if" + //bgpSourceIP defines the source address for BGP peering + bgpSourceIP = "bgp_source_ip" //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 5539a1a0..8e77fe31 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -23,7 +23,7 @@ func ParseEnvironment(c *Config) error { if env != "" { logLevel, err := strconv.Atoi(env) if err != nil { - panic(fmt.Sprintf("Unable to parse environment variable [vip_loglevel], should be int")) + panic("Unable to parse environment variable [vip_loglevel], should be int") } log.SetLevel(log.Level(logLevel)) } @@ -306,6 +306,18 @@ func ParseEnvironment(c *Config) error { c.BGPPeerConfig.Password = env } + // BGP Source Interface + env = os.Getenv(bgpSourceIF) + if env != "" { + c.BGPConfig.SourceIF = env + } + + // BGP Source Address + env = os.Getenv(bgpSourceIP) + if env != "" { + c.BGPConfig.SourceIP = env + } + // BGP Peer options, add them if relevant env = os.Getenv(bgpPeerAddress) if env != "" { @@ -626,6 +638,24 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } + // Detect if we should be using a source interface for speaking to a bgp peer + if c.BGPConfig.SourceIF != "" { + bgpConfig = append(bgpConfig, corev1.EnvVar{ + Name: bgpSourceIF, + Value: c.BGPConfig.SourceIF, + }, + ) + } + // Detect if we should be using a source address for speaking to a bgp peer + + if c.BGPConfig.SourceIP != "" { + bgpConfig = append(bgpConfig, corev1.EnvVar{ + Name: bgpSourceIP, + Value: c.BGPConfig.SourceIP, + }, + ) + } + var peers string if len(c.BGPPeers) != 0 { for x := range c.BGPPeers { diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 93dcdbcd..ae596ce2 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -71,7 +71,7 @@ func OpenConfig(path string) (*Config, error) { func (c *Config) PrintConfig() { b, _ := yaml.Marshal(c) - fmt.Printf(string(b)) + fmt.Print(string(b)) } //ParseFlags will write the current configuration to a specified [path] @@ -159,7 +159,7 @@ func SampleConfig() { } b, _ := yaml.Marshal(c) - fmt.Printf(string(b)) + fmt.Print(string(b)) } //WriteConfig will write the current configuration to a specified [path] diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index 05ed2733..663189a3 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -1,11 +1,13 @@ package manager import ( + "reflect" "testing" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -20,9 +22,9 @@ func TestParseBgpAnnotations(t *testing.T) { } node.Annotations = map[string]string{ - "bgp/node-asn": "1", - "bgp/peer-asn": "2", - "bgp/src-ip": "3", + "bgp/node-asn": "65000", + "bgp/peer-asn": "64000", + "bgp/src-ip": "10.0.0.254", } bgpConfig, bgpPeer, err := parseBgpAnnotations(node, "bgp") @@ -30,15 +32,15 @@ func TestParseBgpAnnotations(t *testing.T) { t.Fatal("Parsing BGP annotations should return nil when minimum config is met") } - assert.Equal(t, uint32(1), bgpConfig.AS, "bgpConfig.AS parsed incorrectly") - assert.Equal(t, uint32(2), bgpPeer.AS, "bgpPeer.AS parsed incorrectly") - assert.Equal(t, "3", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") + assert.Equal(t, uint32(65000), bgpConfig.AS, "bgpConfig.AS parsed incorrectly") + assert.Equal(t, uint32(64000), bgpPeer.AS, "bgpPeer.AS parsed incorrectly") + assert.Equal(t, "10.0.0.254", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") node.Annotations = map[string]string{ - "bgp/node-asn": "1", - "bgp/peer-asn": "2", - "bgp/src-ip": "3", - "bgp/peer-ip": "1,2,3", + "bgp/node-asn": "65000", + "bgp/peer-asn": "64000", + "bgp/src-ip": "10.0.0.254", + "bgp/peer-ip": "10.0.0.1,10.0.0.2,10.0.0.3", "bgp/bgp-pass": "cGFzc3dvcmQ=", // password } @@ -48,11 +50,42 @@ func TestParseBgpAnnotations(t *testing.T) { } bgpPeers := []bgp.Peer{ - {Address: "1", AS: uint32(2)}, - {Address: "2", AS: uint32(2)}, - {Address: "3", AS: uint32(2)}, + {Address: "10.0.0.1", AS: uint32(64000)}, + {Address: "10.0.0.2", AS: uint32(64000)}, + {Address: "10.0.0.3", AS: uint32(64000)}, } assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") - assert.Equal(t, "3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") - assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") + assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") + //assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") +} + +func Test_parseBgpAnnotations(t *testing.T) { + type args struct { + node *v1.Node + prefix string + } + tests := []struct { + name string + args args + want bgp.Config + want1 bgp.Peer + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, err := parseBgpAnnotations(tt.args.node, tt.args.prefix) + if (err != nil) != tt.wantErr { + t.Errorf("parseBgpAnnotations() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseBgpAnnotations() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("parseBgpAnnotations() got1 = %v, want %v", got1, tt.want1) + } + }) + } } From 54615fa7500af3961efe58fc8ce23ddc8c3a3ebb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 25 Aug 2021 16:00:51 +0100 Subject: [PATCH 135/542] Remove duplicate flag --- cmd/kube-vip.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index ba3fbb8b..1a3bfd7a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -105,7 +105,6 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIP, "sourceIP", "", "The source address for bgp peering (not to be used with sourceIF)") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.AS, "localAS", 65000, "The local AS number for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") From fab9be29f0258d7013f7dd05c3bc42eb10e287ca Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 31 Aug 2021 17:18:16 +0100 Subject: [PATCH 136/542] Fixes the broken logic in password parsing --- pkg/manager/watcher.go | 21 +++++++++++---------- pkg/manager/watcher_test.go | 8 ++++---- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 9ec2f82b..848bb7a7 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -262,20 +262,21 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er if ipAddr != "" { bgpPeer.Address = ipAddr + // Check if we're also expecting a password for this peer + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] + if base64BGPPassword != "" { + // Decode base64 encoded string + decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) + if err != nil { + return bgpConfig, bgpPeer, err + } + // Set the password for each peer + bgpPeer.Password = string(decodedPassword) + } bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) } } - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] - if base64BGPPassword != "" { - // Decode base64 encoded string - decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) - if err != nil { - return bgpConfig, bgpPeer, err - } - bgpPeer.Password = string(decodedPassword) - } - log.Debugf("BGPConfig: %v\n", bgpConfig) log.Debugf("BGPPeerConfig: %v\n", bgpPeer) diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index 663189a3..7b12383f 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -50,13 +50,13 @@ func TestParseBgpAnnotations(t *testing.T) { } bgpPeers := []bgp.Peer{ - {Address: "10.0.0.1", AS: uint32(64000)}, - {Address: "10.0.0.2", AS: uint32(64000)}, - {Address: "10.0.0.3", AS: uint32(64000)}, + {Address: "10.0.0.1", AS: uint32(64000), Password: "password"}, + {Address: "10.0.0.2", AS: uint32(64000), Password: "password"}, + {Address: "10.0.0.3", AS: uint32(64000), Password: "password"}, } assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") - //assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") + assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") } func Test_parseBgpAnnotations(t *testing.T) { From 4a814f24271610e47e59c7672fac9979618e83f7 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Tue, 31 Aug 2021 17:32:53 -0400 Subject: [PATCH 137/542] [metal] Use provided provider id in config if defined Signed-off-by: Jason DeTiberus --- pkg/packet/eip.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index e5bf8478..d9b48931 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -12,13 +12,20 @@ import ( // AttachEIP will use the packet APIs to move an EIP and attach to a host func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { - // Find our project - proj := findProject(k.MetalProject, c) - if proj == nil { - return fmt.Errorf("Unable to find Project [%s]", k.MetalProject) + // Use MetalProjectID if it is defined + projID := k.MetalProjectID + + if projID == "" { + // Fallback to attempting to find the project by name + proj := findProject(k.MetalProject, c) + if proj == nil { + return fmt.Errorf("Unable to find Project [%s]", k.MetalProject) + } + + projID = proj.ID } - ips, _, _ := c.ProjectIPs.List(proj.ID, &packngo.ListOptions{}) + ips, _, _ := c.ProjectIPs.List(projID, &packngo.ListOptions{}) for _, ip := range ips { // Find the device id for our EIP @@ -33,7 +40,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { } // Lookup this server through the packet API - thisDevice := findSelf(c, proj.ID) + thisDevice := findSelf(c, projID) if thisDevice == nil { return fmt.Errorf("Unable to find local/this device in packet API") } From 925b3bdc20faec9120f9beeabc06e4d695a9ef14 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Tue, 31 Aug 2021 18:20:50 -0400 Subject: [PATCH 138/542] [packet] Support Address config in addition to VIP Signed-off-by: Jason DeTiberus --- pkg/packet/eip.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index d9b48931..29d30787 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -25,11 +25,17 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { projID = proj.ID } + // Prefer Address over VIP + vip := k.Address + if vip == "" { + vip = k.VIP + } + ips, _, _ := c.ProjectIPs.List(projID, &packngo.ListOptions{}) for _, ip := range ips { // Find the device id for our EIP - if ip.Address == k.VIP { + if ip.Address == vip { log.Infof("Found EIP ->%s ID -> %s\n", ip.Address, ip.ID) // If attachements already exist then remove them if len(ip.Assignments) != 0 { @@ -48,7 +54,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { // Assign the EIP to this device log.Infof("Assigning EIP to -> %s\n", thisDevice.Hostname) _, _, err := c.DeviceIPs.Assign(thisDevice.ID, &packngo.AddressStruct{ - Address: k.VIP, + Address: vip, }) if err != nil { return err From 8021ef7bf690a1fdf5e83e70403bca5d7633e7f2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 1 Sep 2021 09:42:11 +0100 Subject: [PATCH 139/542] Updates Makefile to correct version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6335eb71..c187047c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.3.7 +VERSION := v0.3.8 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 0a578165670615d79b1101f33a7778e0d26e7754 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 1 Sep 2021 09:51:00 +0100 Subject: [PATCH 140/542] Fixes Docs --- docs/flags/index.md | 8 ++++++++ docs/install_daemonset/index.md | 4 ++-- docs/install_static/index.md | 4 ++-- docs/usage/EquinixMetal/index.md | 10 ++++++++++ docs/usage/k3s/index.md | 4 ++-- docs/usage/kind/index.md | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 07a71383..df45e82c 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -6,6 +6,8 @@ These flags are typically used in manifest generation. | Category | Flag | Usage | Notes | |--------------|------|-------|-------| +|**Troubleshooting** |||| +| |`--log`|default 4|Set to `5` for debugging logs| |**Mode** |||| | |`--controlPlane`|Enables `kube-vip` control-plane functionality|| | |`--services`|Enables `kube-vip` to watch services of type:LoadBalancer|| @@ -34,6 +36,8 @@ These flags are typically used in manifest generation. | |`--peerAS`|default 65000|AS of a single BGP Peer| | |`--peerPass`|""| Password to work with a single BGP Peer| | |`--multiHop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| +| |`--sourceif`|Source Interface| Determines which interface BGP should peer _from_| +| |`--sourceip`|Source Address| Determines which IP address BGP should peer _from_| | |`--annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| |**Equinix Metal**|||(May be deprecated)| | |`--metal`|Enables Equinix Metal API calls|| @@ -50,6 +54,8 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | Category | Environment Variable | Usage | Notes | |--------------|------|-------|-------| +|**Troubleshooting** |||| +| |`vip_loglevel`|default 4|Set to `5` for debugging logs| |**Mode** |||| | |`cp_enable`|Enables `kube-vip` control-plane functionality|| | |`svc_enable`|Enables `kube-vip` to watch services of `type:LoadBalancer`|| @@ -75,6 +81,8 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | |`bgp_peeras`|default 65000|AS of a single BGP Peer| | |`bgp_peerpass`|""| Password to work with a single BGP Peer| | |`bgp_multihop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| +| |`bgp_sourceif`|Source Interface| Determines which interface BGP should peer _from_| +| |`bgp_sourceip`|Source Address| Determines which IP address BGP should peer _from_| | |`annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| |**Equinix Metal**|||(May be deprecated)| | |`vip_packet`|Enables Equinix Metal API calls|| diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index ad739416..4d6c2a19 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -41,10 +41,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip"` #### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` ### BGP Example diff --git a/docs/install_static/index.md b/docs/install_static/index.md index b8e4ce79..b94b6cb7 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -32,10 +32,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` ## ARP diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index 5027be83..f0c6dfba 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -6,6 +6,16 @@ When deploying Kubernetes with Equinix Metal with the `--controlplane` functiona **Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. +## Configure to use a container runtime + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +### containerd +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` + +### Docker +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` + ## Creating HA clusters in Equinix Metal ### Creating a manifest using the API diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 34efb8a5..379e1f2e 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -45,10 +45,10 @@ curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee ## Step 3.2 Genereate from container image ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` ``` diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index 1b4088b4..8d32c456 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -30,7 +30,7 @@ kubectl create configmap --namespace kube-system kubevip --from-literal range-gl Set the correct `alias` for `kube-vip` ``` -alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.7" +alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8" ``` Install Kube-vip deamonset inside of KIND From 306a75ff84bb2fc76c8d738005be21cff8cce9e5 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 1 Sep 2021 14:53:55 +0100 Subject: [PATCH 141/542] This will set source IP for BGP from annotations --- pkg/manager/watcher.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 848bb7a7..fdd02a62 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -239,7 +239,9 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") } - bgpConfig.RouterID = srcIP + // Set the routerID (Unique ID for BGP) to the source IP + // Also set the BGP peering to the sourceIP + bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] if peerASN == "" { From d06176a56b5406d0b6611298cbb2aeaac7fa7d05 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 2 Sep 2021 10:07:17 +0100 Subject: [PATCH 142/542] Implements a secondary interface just for services --- cmd/kube-vip-config.go | 2 +- cmd/kube-vip-kubeadm.go | 6 ++++-- cmd/kube-vip-manifests.go | 4 ++-- cmd/kube-vip.go | 2 ++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 23 +++++++++++++++++++++-- pkg/kubevip/config_generator_test.go | 23 +++++++++++++++++++++++ pkg/kubevip/config_types.go | 3 +++ pkg/manager/services.go | 16 ++++++++++++---- 9 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 pkg/kubevip/config_generator_test.go diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index 8d227d27..60857f3e 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -141,6 +141,6 @@ var kubeVipSampleManifest = &cobra.Command{ } b, _ := yaml.Marshal(p) - fmt.Printf(string(b)) + fmt.Print(string(b)) }, } diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index 396ec87e..a0e43857 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -101,7 +101,9 @@ var kubeKubeadmJoin = &cobra.Command{ opts := metav1.ListOptions{} opts.LabelSelector = "node-role.kubernetes.io/master" nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), opts) - + if err != nil { + log.Fatal(err.Error()) + } // Iterate over all nodes that are masters and find the details to build a peer list for x := range nodes.Items { // Get hostname and address @@ -150,7 +152,7 @@ func autoGenLocalPeer() (*kubevip.RaftPeer, error) { } } if a == "" { - return nil, fmt.Errorf("Unable to find local address") + return nil, fmt.Errorf("nable to find local address") } return &kubevip.RaftPeer{ ID: h, diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 66c6fbc8..d7ca0e0e 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -49,7 +49,7 @@ var kubeManifestPod = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && initConfig.DDNS == false) { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } @@ -75,7 +75,7 @@ var kubeManifestDaemon = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && initConfig.DDNS == false) { + if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1a3bfd7a..21ae6dcc 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -67,6 +67,8 @@ func init() { initConfig.LocalPeer = *localpeer //initConfig.Peers = append(initConfig.Peers, *localpeer) kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "listen port for the VIP") diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d6eeefd1..4715ae7b 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -24,6 +24,9 @@ const ( //vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" + //vipInterface - defines the interface that the vip should bind too + vipServicesInterface = "vip_servicesinterface" + //vipCidr - defines the cidr that the vip will use vipCidr = "vip_cidr" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 8e77fe31..03894854 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -34,6 +34,12 @@ func ParseEnvironment(c *Config) error { c.Interface = env } + // Find (services) interface + env = os.Getenv(vipServicesInterface) + if env != "" { + c.ServicesInterface = env + } + // Find provider configuration env = os.Getenv(providerConfig) if env != "" { @@ -358,10 +364,11 @@ func ParseEnvironment(c *Config) error { return err } c.EnableLoadBalancer = b + // Load Balancer configuration + return parseEnvironmentLoadBalancer(c) } - // Load Balancer configuration - return parseEnvironmentLoadBalancer(c) + return nil } func parseEnvironmentLoadBalancer(c *Config) error { @@ -458,6 +465,18 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } + // Detect if we should be using a seperate interface for sercices + if c.ServicesInterface != "" { + // build environment variables + svcInterface := []corev1.EnvVar{ + { + Name: vipServicesInterface, + Value: c.ServicesInterface, + }, + } + newEnvironment = append(newEnvironment, svcInterface...) + } + // If a CIDR is used add it to the manifest if c.VIPCIDR != "" { // build environment variables diff --git a/pkg/kubevip/config_generator_test.go b/pkg/kubevip/config_generator_test.go new file mode 100644 index 00000000..f39bfb3a --- /dev/null +++ b/pkg/kubevip/config_generator_test.go @@ -0,0 +1,23 @@ +package kubevip + +import "testing" + +func TestParseEnvironment(t *testing.T) { + + tests := []struct { + name string + c *Config + wantErr bool + }{ + {"", nil, false}, + {"", &Config{Interface: "eth0", ServicesInterface: "eth1"}, false}, + } + for _, tt := range tests { + t.Logf("%v", tt.c) + t.Run(tt.name, func(t *testing.T) { + if err := ParseEnvironment(tt.c); (err != nil) != tt.wantErr { + t.Errorf("ParseEnvironment() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 0cb003e2..f8038cba 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -63,6 +63,9 @@ type Config struct { // Interface is the network interface to bind to (default: First Adapter) Interface string `yaml:"interface,omitempty"` + // Interface is the network interface to bind to (default: First Adapter) + ServicesInterface string `yaml:"servicesInterface,omitempty"` + // EnableLoadBalancer, provides the flexibility to make the load-balancer optional EnableLoadBalancer bool `yaml:"enableLoadBalancer"` diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 6f925dfa..94bbf55b 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -28,8 +28,8 @@ func (sm *Manager) stopService(uid string) error { sm.serviceInstances[x].cluster.Stop() } } - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) + if !found { + return fmt.Errorf("unable to find/stop service [%s]", uid) } return nil } @@ -90,10 +90,18 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { } + // Detect if we're using a specific interface for services + var serciceInterface string + if sm.config.ServicesInterface != "" { + serciceInterface = sm.config.ServicesInterface + } else { + serciceInterface = sm.config.Interface + } + // Generate new Virtual IP configuration newVip := kubevip.Config{ VIP: newServiceAddress, //TODO support more than one vip? - Interface: sm.config.Interface, + Interface: serciceInterface, SingleNode: true, EnableARP: sm.config.EnableARP, EnableBGP: sm.config.EnableBGP, @@ -101,7 +109,7 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { } // This instance wasn't found, we need to add it to the manager - if foundInstance == false { + if !foundInstance { // Create new service var newService Instance newService.UID = newServiceUID From 9addea61496cc951746caa5bd9aa9f9cc59f3fbe Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Thu, 2 Sep 2021 13:42:29 -0400 Subject: [PATCH 143/542] Update DaemonSet generation to improve scheduling - Tolerate more than just the node-role.kubernetes.io/master taint, this allows the daemonset to schedule prior to CNI being deployed. - Switch from using a nodeSelector to using nodeAffinity - Allows scheduling even if the node label does not match the value (for the node-role label, the value is generally ignored). - Add support for the control-plane node role rather than just master. Signed-off-by: Jason DeTiberus --- pkg/kubevip/config_generator.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 8e77fe31..6d96c226 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -855,13 +855,37 @@ func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inClust if taint { newManifest.Spec.Template.Spec.Tolerations = []corev1.Toleration{ { - Key: "node-role.kubernetes.io/master", Effect: corev1.TaintEffectNoSchedule, Operator: corev1.TolerationOpExists, }, + { + Effect: corev1.TaintEffectNoExecute, + Operator: corev1.TolerationOpExists, + }, } - newManifest.Spec.Template.Spec.NodeSelector = map[string]string{ - "node-role.kubernetes.io/master": "true", + newManifest.Spec.Template.Spec.Affinity = &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "node-role.kubernetes.io/master", + Operator: corev1.NodeSelectorOpExists, + }, + }, + }, + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "node-role.kubernetes.io/control-plane", + Operator: corev1.NodeSelectorOpExists, + }, + }, + }, + }, + }, + }, } } b, _ := yaml.Marshal(newManifest) From 7bfa79750da3a313496790c417e8a684fbb507e2 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Thu, 2 Sep 2021 16:21:11 -0400 Subject: [PATCH 144/542] Support use Equinix Metal credentials from config Use Equinix Metal credentials when available with EIP configuration not just BGP configuration. Signed-off-by: Jason DeTiberus --- pkg/cluster/clusterLeader.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index a0a0b222..f6c8d3cf 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -153,6 +153,17 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // If Packet is enabled then we can begin our preperation work var packetClient *packngo.Client if c.EnableMetal { + if c.ProviderConfig != "" { + key, project, err := packet.GetPacketConfig(c.ProviderConfig) + if err != nil { + log.Error(err) + } else { + // Set the environment variable with the key for the project + os.Setenv("PACKET_AUTH_TOKEN", key) + // Update the configuration with the project key + c.MetalProjectID = project + } + } packetClient, err = packngo.NewClient() if err != nil { log.Error(err) From 5f751cc3219dd85c4b585b9d042b28c5a4b097cd Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 3 Sep 2021 13:37:43 +0100 Subject: [PATCH 145/542] Fixes from feedback --- cmd/kube-vip-kubeadm.go | 2 +- pkg/kubevip/config_envvar.go | 2 +- pkg/kubevip/config_types.go | 2 +- pkg/manager/services.go | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index a0e43857..fdb2a515 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -152,7 +152,7 @@ func autoGenLocalPeer() (*kubevip.RaftPeer, error) { } } if a == "" { - return nil, fmt.Errorf("nable to find local address") + return nil, fmt.Errorf("unable to find local address") } return &kubevip.RaftPeer{ ID: h, diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 4715ae7b..6b1edb19 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -24,7 +24,7 @@ const ( //vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" - //vipInterface - defines the interface that the vip should bind too + //vipServicesInterface - defines the interface that the service vips should bind too vipServicesInterface = "vip_servicesinterface" //vipCidr - defines the cidr that the vip will use diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index f8038cba..ca0f656d 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -63,7 +63,7 @@ type Config struct { // Interface is the network interface to bind to (default: First Adapter) Interface string `yaml:"interface,omitempty"` - // Interface is the network interface to bind to (default: First Adapter) + // ServicesInterface is the network interface to bind to for services (optional) ServicesInterface string `yaml:"servicesInterface,omitempty"` // EnableLoadBalancer, provides the flexibility to make the load-balancer optional diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 94bbf55b..153c92ed 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -91,17 +91,17 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { } // Detect if we're using a specific interface for services - var serciceInterface string + var serviceInterface string if sm.config.ServicesInterface != "" { - serciceInterface = sm.config.ServicesInterface + serviceInterface = sm.config.ServicesInterface } else { - serciceInterface = sm.config.Interface + serviceInterface = sm.config.Interface } // Generate new Virtual IP configuration newVip := kubevip.Config{ VIP: newServiceAddress, //TODO support more than one vip? - Interface: serciceInterface, + Interface: serviceInterface, SingleNode: true, EnableARP: sm.config.EnableARP, EnableBGP: sm.config.EnableBGP, From 975b892e6ddeaf2597f8d9444ffc6172e4bd1df1 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Fri, 10 Sep 2021 14:05:20 -0400 Subject: [PATCH 146/542] Bump gobgp dependency to the latest v2.31.0 Signed-off-by: Jason DeTiberus --- go.mod | 12 +++--------- go.sum | 56 ++++++++++++++++++-------------------------------------- 2 files changed, 21 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 4e70ded4..4d1d696b 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,10 @@ go 1.14 require ( github.com/armon/go-metrics v0.3.8 // indirect github.com/davecgh/go-spew v1.1.1 - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.2.0 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/go-hclog v0.16.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.0 // indirect @@ -21,7 +19,6 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e github.com/jpillora/backoff v1.0.0 github.com/json-iterator/go v1.1.11 // indirect - github.com/k-sone/critbitgo v1.4.0 // indirect github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/magiconair/properties v1.8.5 // indirect github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 @@ -29,7 +26,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.7.0 - github.com/osrg/gobgp v2.0.0+incompatible + github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee github.com/packethost/packngo v0.13.0 github.com/pelletier/go-toml v1.9.0 // indirect github.com/pkg/errors v0.9.1 @@ -40,12 +37,11 @@ require ( github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.7.1 // indirect github.com/stretchr/testify v1.7.0 - github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 + github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 + golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect @@ -63,5 +59,3 @@ require ( sigs.k8s.io/kind v0.10.0 sigs.k8s.io/structured-merge-diff/v4 v4.1.1 // indirect ) - -replace github.com/osrg/gobgp v2.0.0+incompatible => github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 diff --git a/go.sum b/go.sum index abf75e7a..6134d7a4 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,9 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -107,6 +108,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -117,7 +119,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20171119141306-ac7624ea8da3/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= @@ -130,7 +131,6 @@ github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.0.2/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -154,7 +154,6 @@ github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGE github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -187,6 +186,8 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= +github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -208,7 +209,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -257,8 +257,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -309,7 +309,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v0.0.0-20170509225359-392dba7d905e/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -332,8 +331,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e h1:sgh63o+pm5kcdrgyYaCIoeD7mccyL6MscVmy+DvY6C4= github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/jessevdk/go-flags v1.3.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -355,7 +354,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/k-sone/critbitgo v1.3.1-0.20191024122315-48c9e1530131/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= @@ -370,6 +368,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -378,7 +377,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= @@ -419,7 +417,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -465,8 +462,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0 h1:sqWev+JAbQevLXYorfyTzf1c5VubkPi+Q83O9oBCNgA= -github.com/osrg/gobgp v0.0.0-20191101114856-a42a1a5f6bf0/go.mod h1:IVw8wEHROhX0qrmI8c6j3N8EDXZSC4YkktSzkX/JZ8Q= +github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee h1:p9cPdDaBWf5r9+arw2pUuc0aDT/tkfCEBVqfx/UBb2o= +github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee/go.mod h1:QvEj9qq9o66TvTyFC0Yyn1zgSSFrno8MsptfrjyMR7A= github.com/packethost/packngo v0.13.0 h1:VIeDY/Uju53v8LAKxiqTrfR9jkpX5PhWdnQC0h3aUU8= github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= @@ -475,8 +472,6 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v1.0.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= @@ -535,12 +530,12 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -553,31 +548,25 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v0.0.0-20170217164146-9be650865eab/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.0-20170731170427-b26b538f6930/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v0.0.0-20170523133247-0efa5202c046/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= @@ -589,7 +578,6 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -607,11 +595,9 @@ github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v0.0.0-20170802012344-a95659537721/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 h1:IlMBmSoCDZ9UY3OehFgvKSIgMNnU1vbAD4Fl+y2Rbis= -github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066/go.mod h1:FSQhuTO7eHT34mPzX+B04SUAjiqLxtXs1et0S6l9k4k= -github.com/vishvananda/netns v0.0.0-20170707011535-86bef332bfc3/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -731,8 +717,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125 h1:Ugb8sMTWuWRC3+sz5WeN/4kejDx9BvIwnPUiJBjJE+8= -golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -783,7 +769,6 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -800,6 +785,7 @@ golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -855,10 +841,8 @@ golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190826182127-07722704da13/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -922,7 +906,6 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -956,7 +939,6 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 h1:0pBp6vCQyvmttnWa4c74n/y2U7bAQeIUVyVvZpb7Fyo= google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/grpc v1.5.1/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1010,7 +992,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170721122051-25c4ec802a7d/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1029,7 +1010,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20191022112108-ee025456fe28/go.mod h1:YZLKf07TTEX58hlaDFZRbZEdP4uwSiqhU91o1aN3EvM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= From 96c7dc5f150c28245d73b4f0eca74051bfaccf6d Mon Sep 17 00:00:00 2001 From: Mario Vejlupek Date: Thu, 16 Sep 2021 09:44:16 +0200 Subject: [PATCH 147/542] Add link to Equinix Metal metal-gateway guide Signed-off-by: Mario Vejlupek --- docs/usage/k3s/index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 379e1f2e..04b8ad04 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -1,5 +1,9 @@ # K3s overview (on Equinix Metal) +## Prerequisites + +In order to make ARP work on Equinix Metal, you need to follow [metal-gateway](https://metal.equinix.com/developers/docs/networking/metal-gateway/) guide to have public VLAN subnet, which you can use as your loadbalancer IP. + ## Optional Tidy environment (best if something was running before) ``` rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ @@ -29,7 +33,7 @@ Configure your virtual IP (for the control plane) and interface that will expose ``` export VIP=x.x.x.x -export INTERFACE=ethx +export INTERFACE=bind0 # or ethX depends on your networking setup ``` Modify the `VIP` and `INTERFACE` to match the floating IP address you'd like to use and the interface it should bind to. @@ -79,4 +83,4 @@ sudo ./k3s server --tls-san $VIP ## Step 5: Service Load-Balancing -For this refer to the [on-prem](../on-prem) documentation \ No newline at end of file +For this refer to the [on-prem](../on-prem) documentation From 0c82f3e00b3e1bbb398f8aa71ac6e1c4c98d1bb3 Mon Sep 17 00:00:00 2001 From: larrymapacket Date: Tue, 28 Sep 2021 17:09:54 -0500 Subject: [PATCH 148/542] Changing EquiniMetal usage document to add a few missing information and links. Signed-off-by: larrymapacket --- docs/usage/EquinixMetal/index.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index f0c6dfba..c36d6cfb 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -4,7 +4,9 @@ When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). -**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. +**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. + +For information on how to deploy [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) ## Configure to use a container runtime @@ -18,6 +20,12 @@ The easiest method to generate a manifest is using the container itself, below w ## Creating HA clusters in Equinix Metal +export VIP= metal_EIP +export INTERFACE= + +where metal_EIPis the elastci IP (EIP) address your requested via Metal's UI or API, for more informaiton on how to request a Metal's EIP, please see the following Equinix Metal document - https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses +and is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. + ### Creating a manifest using the API We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. @@ -33,7 +41,9 @@ kube-vip manifest pod \ --metalKey xxxxxxx \ --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml ``` +where metalKey is your "personal API key" under "Personal Settings" of your Metal's portal, and MetalProjectID is your Metal's "Project ID" under "Project Settings" +Or ### Creating a manifest using the metadata We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. @@ -55,7 +65,7 @@ kube-vip manifest pod \ Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. -**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. +**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. ### Using Annotations @@ -85,17 +95,10 @@ kube-vip manifest daemonset --interface $INTERFACE \ ### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) -Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! +Follow the Equinix Metal's Elastic IP document (https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) either through the API or through the UI, create a public IPv4 EIP address, for example (145.75.75.1) and this is the address you can expose through BGP! ``` -# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 -+-------+---------------+--------+----------------------+ -| ID | ADDRESS | PUBLIC | CREATED | -+-------+---------------+--------+----------------------+ -| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | -+-------+---------------+--------+----------------------+ - -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=147.75.75.1 ``` ## Troubleshooting From a46042e5488db95c767fa3f8cbf2cec27b7030b1 Mon Sep 17 00:00:00 2001 From: larrymapacket Date: Mon, 4 Oct 2021 17:09:57 -0500 Subject: [PATCH 149/542] update the Equinix Metal kube-vip doc. Signed-off-by: larrymapacket --- docs/usage/EquinixMetal/index.md | 46 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index c36d6cfb..fbb64609 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -1,12 +1,10 @@ -# Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) +# Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal)) ## BGP with Equinix Metal -When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). +When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP (VIP) for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). -**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. - -For information on how to deploy [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) +**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. ## Configure to use a container runtime @@ -19,17 +17,18 @@ The easiest method to generate a manifest is using the container itself, below w `alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` ## Creating HA clusters in Equinix Metal - -export VIP= metal_EIP -export INTERFACE= - -where metal_EIPis the elastci IP (EIP) address your requested via Metal's UI or API, for more informaiton on how to request a Metal's EIP, please see the following Equinix Metal document - https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses -and is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. - + ### Creating a manifest using the API We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. +``` +export VIP= metal_EIP +export INTERFACE= +``` +where metal_EIP is the Elastic IP (EIP) address your requested via Metal's UI or API. For more informaiton on how to request a Metal's EIP, please see the following [Equinix Metal's EIP document](https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) + is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. + ``` kube-vip manifest pod \ --interface $INTERFACE\ @@ -42,8 +41,7 @@ kube-vip manifest pod \ --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml ``` where metalKey is your "personal API key" under "Personal Settings" of your Metal's portal, and MetalProjectID is your Metal's "Project ID" under "Project Settings" - -Or + ### Creating a manifest using the metadata We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. @@ -65,8 +63,13 @@ kube-vip manifest pod \ Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. -**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. +**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) to be installed prior to the kube-vip setup and that the cluster/kubelet is configured to use an "external" cloud provider. +``` +export INTERFACE= +``` +where is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. + ### Using Annotations This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. @@ -93,11 +96,18 @@ kube-vip manifest daemonset --interface $INTERFACE \ --provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - ``` -### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) +### Expose with [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) -Follow the Equinix Metal's Elastic IP document (https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) either through the API or through the UI, create a public IPv4 EIP address, for example (145.75.75.1) and this is the address you can expose through BGP! +Follow the [Equinix Metal's Elastic IP (EIP) document](https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) either through the API, CLI or through the UI, to create a public IPv4 EIP address, for example (145.75.75.1) and this is the address you can expose through BGP as the service loadbalancer. ``` +# metal ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 ++-------+---------------+--------+----------------------+ +| ID | ADDRESS | PUBLIC | CREATED | ++-------+---------------+--------+----------------------+ +| xxxxx | 147.75.75.1 | true | 2020-11-10T15:57:39Z | ++-------+---------------+--------+----------------------+ + kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=147.75.75.1 ``` @@ -124,4 +134,4 @@ ip route add 169.254.255.1 via $GATEWAY_IP ip route add 169.254.255.2 via $GATEWAY_IP ``` -Additionally examining the logs of the Packet CCM may reveal why the node is not yet ready. \ No newline at end of file +Additionally examining the logs of the Equinix Metal's CCM may reveal why the node is not yet ready. From 74fa77735b72e5cbea226b28f5a8c2855c471e5f Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 12 Oct 2021 10:49:08 +0100 Subject: [PATCH 150/542] Adds easier moving between Kubernetes versions --- testing/kubeadm/create.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 99d6d2fe..79ebc9ee 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -29,8 +29,14 @@ esac source ./testing/nodes -echo "Creating First node!" +echo "Installing Kubernetes dependencies for Kubernetes $! on all nodes" +ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +echo "Creating First node!" ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod $mode --interface ens160 --vip $4 --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml" CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $4 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") ssh $NODE01 "sudo rm -rf ~/.kube/" @@ -58,4 +64,4 @@ sleep 5 ssh $NODE01 "kubectl get nodes" ssh $NODE01 "kubectl get pods -A" echo -echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $4" \ No newline at end of file +echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $4" From 1f7ff01bec42e079dcbc0c2a2c29c858b7383a55 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 12 Oct 2021 11:41:44 +0100 Subject: [PATCH 151/542] Use localhost to connect to manager --- pkg/manager/manager.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 5f7ef6e3..20ab0ffa 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -113,13 +113,8 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. if config.EnableControlPane { - log.Debugf("Modifying address of Kubernetes server to hostname") - // We modify the config so that we can always speak to the correct host - id, err := os.Hostname() - if err != nil { - return nil, err - } - cfg.Host = fmt.Sprintf("%s:%v", id, config.Port) + log.Debugf("Modifying address of Kubernetes server to localhost") + cfg.Host = fmt.Sprintf("localhost:%v", config.Port) clientset, err = kubernetes.NewForConfig(cfg) } if err != nil { From e2c8e4d72493e3a27de892d653f2523e7386a88d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 13 Oct 2021 10:48:17 +0100 Subject: [PATCH 152/542] Automates the changes required for callback to API server --- Makefile | 8 +- docs/manifests/v0.3.9/kube-vip-arp-ds.yaml | 65 ++++++++++++++ docs/manifests/v0.3.9/kube-vip-arp.yaml | 61 ++++++++++++++ docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml | 74 ++++++++++++++++ docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml | 84 +++++++++++++++++++ docs/manifests/v0.3.9/kube-vip-bgp.yaml | 68 +++++++++++++++ pkg/kubevip/config_generator.go | 7 ++ pkg/manager/manager.go | 2 +- 8 files changed, 367 insertions(+), 2 deletions(-) create mode 100644 docs/manifests/v0.3.9/kube-vip-arp-ds.yaml create mode 100644 docs/manifests/v0.3.9/kube-vip-arp.yaml create mode 100644 docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml create mode 100644 docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml create mode 100644 docs/manifests/v0.3.9/kube-vip-bgp.yaml diff --git a/Makefile b/Makefile index c187047c..49da6c6f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.3.8 +VERSION := v0.3.9 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) @@ -47,6 +47,12 @@ demo: ## Remote (push of images) # This build a local docker image (x86 only) for quick testing + +dockerx86Dev: + @-rm ./kube-vip + @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):dev . + @echo New single x86 Architecture Docker image created + dockerx86: @-rm ./kube-vip @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . diff --git a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml new file mode 100644 index 00000000..24552ab2 --- /dev/null +++ b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.9/kube-vip-arp.yaml b/docs/manifests/v0.3.9/kube-vip-arp.yaml new file mode 100644 index 00000000..17d0e3b2 --- /dev/null +++ b/docs/manifests/v0.3.9/kube-vip-arp.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml new file mode 100644 index 00000000..e7f977ce --- /dev/null +++ b/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml new file mode 100644 index 00000000..e13d519d --- /dev/null +++ b/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: provider_config + value: /etc/cloud-sa/cloud-sa.json + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/cloud-sa + name: cloud-sa-volume + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - name: cloud-sa-volume + secret: + secretName: metal-cloud-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.3.9/kube-vip-bgp.yaml b/docs/manifests/v0.3.9/kube-vip-bgp.yaml new file mode 100644 index 00000000..5c9d78db --- /dev/null +++ b/docs/manifests/v0.3.9/kube-vip-bgp.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: vip_interface + value: eth0 + - name: port + value: "6443" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_startleader + value: "false" + - name: vip_addpeerstolb + value: "true" + - name: vip_localpeer + value: code:192.168.0.22:10000 + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index a2e35327..3ec3dba1 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -809,6 +809,13 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } newManifest.Spec.Volumes = append(newManifest.Spec.Volumes, adminConfVolume) + // Add Host modification + + hostAlias := corev1.HostAlias{ + IP: "127.0.0.1", + Hostnames: []string{"kubernetes"}, + } + newManifest.Spec.HostAliases = append(newManifest.Spec.HostAliases, hostAlias) } if c.ProviderConfig != "" { diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 20ab0ffa..6ed45888 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -114,7 +114,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // ensure connectivity. if config.EnableControlPane { log.Debugf("Modifying address of Kubernetes server to localhost") - cfg.Host = fmt.Sprintf("localhost:%v", config.Port) + cfg.Host = fmt.Sprintf("kubernetes:%v", config.Port) clientset, err = kubernetes.NewForConfig(cfg) } if err != nil { From 0d492faaf0c1b4124b377285fd364669518dd7c6 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 19 Oct 2021 11:17:33 +0100 Subject: [PATCH 153/542] Auto detect default interface for VIP --- cmd/kube-vip-manifests.go | 19 +++++++++++++++++++ cmd/kube-vip.go | 20 ++++++++++++++++++-- pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 33 +++++++++++++++++++++++++++++---- pkg/kubevip/config_types.go | 3 +++ pkg/manager/manager.go | 2 +- pkg/vip/util.go | 21 +++++++++++++++++++++ 7 files changed, 94 insertions(+), 7 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index d7ca0e0e..1363dc48 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -43,6 +44,15 @@ var kubeManifestPod = &cobra.Command{ // TODO - A load of text detailing what's actually happening kubevip.ParseEnvironment(&initConfig) // TODO - check for certain things VIP/interfaces + + if initConfig.AutoInterface { + defaultIF, err := vip.GetDefaultGatewayInterface() + if err != nil { + log.Fatalf("unable to set default interface -> [%v]", err) + } + initConfig.Interface = defaultIF.Name + } + if initConfig.Interface == "" { cmd.Help() log.Fatalln("No interface is specified for kube-vip to bind to") @@ -69,6 +79,15 @@ var kubeManifestDaemon = &cobra.Command{ // TODO - A load of text detailing what's actually happening kubevip.ParseEnvironment(&initConfig) // TODO - check for certain things VIP/interfaces + + if initConfig.AutoInterface { + defaultIF, err := vip.GetDefaultGatewayInterface() + if err != nil { + log.Fatalf("unable to set default interface -> [%v]", err) + } + initConfig.Interface = defaultIF.Name + } + if initConfig.Interface == "" { cmd.Help() log.Fatalln("No interface is specified for kube-vip to bind to") diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 21ae6dcc..a0174249 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -10,6 +10,7 @@ import ( "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/manager" "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/vip" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" @@ -67,6 +68,8 @@ func init() { initConfig.LocalPeer = *localpeer //initConfig.Peers = append(initConfig.Peers, *localpeer) kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AutoInterface, "autoInterface", false, "Name of the interface to bind to") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") @@ -209,6 +212,19 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) + if initConfig.AutoInterface { + defaultIF, err := vip.GetDefaultGatewayInterface() + if err != nil { + log.Fatalf("unable to set default interface -> [%v]", err) + } + initConfig.Interface = defaultIF.Name + } + + if initConfig.Interface == "" { + cmd.Help() + log.Fatalln("No interface is specified for kube-vip to bind to") + } + go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ Addr: initConfig.PrometheusHTTPServer, }) @@ -240,7 +256,7 @@ var kubeVipManager = &cobra.Command{ // Define the new service manager mgr, err := manager.New(configMap, &initConfig) if err != nil { - log.Fatalf("%v", err) + log.Fatalf("configuring new Manager error -> %v", err) } prometheus.MustRegister(mgr.PrometheusCollector()...) @@ -248,7 +264,7 @@ 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("%v", err) + log.Fatalf("starting new Manager error -> %v", err) } }, } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 6b1edb19..d3191d87 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -24,6 +24,9 @@ const ( //vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" + //vipAutoInterface - defines the interface that the vip should bind too + vipAutoInterface = "vip_autointerface" + //vipServicesInterface - defines the interface that the service vips should bind too vipServicesInterface = "vip_servicesinterface" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 3ec3dba1..bf36039c 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -34,6 +34,16 @@ func ParseEnvironment(c *Config) error { c.Interface = env } + // Find interface + env = os.Getenv(vipAutoInterface) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.AutoInterface = b + } + // Find (services) interface env = os.Getenv(vipServicesInterface) if env != "" { @@ -449,22 +459,37 @@ func parseEnvironmentLoadBalancer(c *Config) error { // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" + // build environment variables newEnvironment := []corev1.EnvVar{ { Name: vipArp, Value: strconv.FormatBool(c.EnableARP), }, - { - Name: vipInterface, - Value: c.Interface, - }, { Name: port, Value: fmt.Sprintf("%d", c.Port), }, } + if c.AutoInterface { + // build environment variables + autoInterface := []corev1.EnvVar{ + { + Name: vipAutoInterface, + Value: strconv.FormatBool(c.AutoInterface), + }, + } + newEnvironment = append(newEnvironment, autoInterface...) + } else { + iface := []corev1.EnvVar{ + { + Name: vipInterface, + Value: c.Interface, + }, + } + newEnvironment = append(newEnvironment, iface...) + } // Detect if we should be using a seperate interface for sercices if c.ServicesInterface != "" { // build environment variables diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index ca0f656d..ed0ba65b 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -63,6 +63,9 @@ type Config struct { // Interface is the network interface to bind to (default: First Adapter) Interface string `yaml:"interface,omitempty"` + // AutoInterface is the network interface to bind to (Adapter is determined from Default Gateway) + AutoInterface bool `yaml:"interface,omitempty"` + // ServicesInterface is the network interface to bind to for services (optional) ServicesInterface string `yaml:"servicesInterface,omitempty"` diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 6ed45888..50ec62a5 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -93,7 +93,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // Second check in home directory for kube config configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") if fileExists(configPath) { - log.Debugf("Using external Kubernetes configuration from file [%s]", configPath) + log.Debugf("Using external Kubernetes configuration from home file [%s]", configPath) cfg, err = clientcmd.BuildConfigFromFlags("", configPath) if err != nil { return nil, err diff --git a/pkg/vip/util.go b/pkg/vip/util.go index fa391afa..a7335a46 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -4,8 +4,10 @@ import ( "fmt" "net" "strings" + "syscall" "github.com/pkg/errors" + "github.com/vishvananda/netlink" ) // LookupHost resolves dnsName and return an IP or an error @@ -64,3 +66,22 @@ func GetFullMask(address string) (string, error) { } return "", fmt.Errorf("failed to parse %s as either IPv4 or IPv6", address) } + +// GetDefaultGatewayInterface return default gateway interface link +func GetDefaultGatewayInterface() (*net.Interface, error) { + routes, err := netlink.RouteList(nil, syscall.AF_INET) + if err != nil { + return nil, err + } + + for _, route := range routes { + if route.Dst == nil || route.Dst.String() == "0.0.0.0/0" { + if route.LinkIndex <= 0 { + return nil, errors.New("Found default route but could not determine interface") + } + return net.InterfaceByIndex(route.LinkIndex) + } + } + + return nil, errors.New("Unable to find default route") +} From 821a488e15c0be773da17bce1fe23333a7051aa5 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 19 Oct 2021 14:34:54 +0100 Subject: [PATCH 154/542] Removed autoInterface option --- cmd/kube-vip-manifests.go | 28 ---------------------------- cmd/kube-vip.go | 13 +++++-------- pkg/kubevip/config_envvar.go | 3 --- pkg/kubevip/config_generator.go | 23 +++-------------------- pkg/kubevip/config_types.go | 3 --- pkg/manager/manager.go | 2 +- pkg/manager/watcher.go | 1 + 7 files changed, 10 insertions(+), 63 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 1363dc48..16f0aea5 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -43,20 +42,6 @@ var kubeManifestPod = &cobra.Command{ initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer) // TODO - A load of text detailing what's actually happening kubevip.ParseEnvironment(&initConfig) - // TODO - check for certain things VIP/interfaces - - if initConfig.AutoInterface { - defaultIF, err := vip.GetDefaultGatewayInterface() - if err != nil { - log.Fatalf("unable to set default interface -> [%v]", err) - } - initConfig.Interface = defaultIF.Name - } - - if initConfig.Interface == "" { - cmd.Help() - log.Fatalln("No interface is specified for kube-vip to bind to") - } // The control plane has a requirement for a VIP being specified if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { @@ -80,19 +65,6 @@ var kubeManifestDaemon = &cobra.Command{ kubevip.ParseEnvironment(&initConfig) // TODO - check for certain things VIP/interfaces - if initConfig.AutoInterface { - defaultIF, err := vip.GetDefaultGatewayInterface() - if err != nil { - log.Fatalf("unable to set default interface -> [%v]", err) - } - initConfig.Interface = defaultIF.Name - } - - if initConfig.Interface == "" { - cmd.Help() - log.Fatalln("No interface is specified for kube-vip to bind to") - } - // The control plane has a requirement for a VIP being specified if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { cmd.Help() diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index a0174249..28cca413 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -68,7 +68,6 @@ func init() { initConfig.LocalPeer = *localpeer //initConfig.Peers = append(initConfig.Peers, *localpeer) kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AutoInterface, "autoInterface", false, "Name of the interface to bind to") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") @@ -212,17 +211,15 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) - if initConfig.AutoInterface { + if initConfig.Interface == "" { + log.Infof("No interface is specified for VIP in config, auto-detecting default Interface") defaultIF, err := vip.GetDefaultGatewayInterface() if err != nil { - log.Fatalf("unable to set default interface -> [%v]", err) + cmd.Help() + log.Fatalf("unable to detect default interface -> [%v]", err) } initConfig.Interface = defaultIF.Name - } - - if initConfig.Interface == "" { - cmd.Help() - log.Fatalln("No interface is specified for kube-vip to bind to") + log.Infof("kube-vip will bind to interface [%s]", initConfig.Interface) } go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d3191d87..6b1edb19 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -24,9 +24,6 @@ const ( //vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" - //vipAutoInterface - defines the interface that the vip should bind too - vipAutoInterface = "vip_autointerface" - //vipServicesInterface - defines the interface that the service vips should bind too vipServicesInterface = "vip_servicesinterface" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index bf36039c..84b36aa5 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -34,16 +34,6 @@ func ParseEnvironment(c *Config) error { c.Interface = env } - // Find interface - env = os.Getenv(vipAutoInterface) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.AutoInterface = b - } - // Find (services) interface env = os.Getenv(vipServicesInterface) if env != "" { @@ -472,16 +462,8 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } - if c.AutoInterface { - // build environment variables - autoInterface := []corev1.EnvVar{ - { - Name: vipAutoInterface, - Value: strconv.FormatBool(c.AutoInterface), - }, - } - newEnvironment = append(newEnvironment, autoInterface...) - } else { + // If we're specifically saying which interface to use then add it to the manifest + if c.Interface != "" { iface := []corev1.EnvVar{ { Name: vipInterface, @@ -490,6 +472,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newEnvironment = append(newEnvironment, iface...) } + // Detect if we should be using a seperate interface for sercices if c.ServicesInterface != "" { // build environment variables diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index ed0ba65b..ca0f656d 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -63,9 +63,6 @@ type Config struct { // Interface is the network interface to bind to (default: First Adapter) Interface string `yaml:"interface,omitempty"` - // AutoInterface is the network interface to bind to (Adapter is determined from Default Gateway) - AutoInterface bool `yaml:"interface,omitempty"` - // ServicesInterface is the network interface to bind to for services (optional) ServicesInterface string `yaml:"servicesInterface,omitempty"` diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 50ec62a5..a5f0e149 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -113,7 +113,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. if config.EnableControlPane { - log.Debugf("Modifying address of Kubernetes server to localhost") + log.Debugf("Modifying address of Kubernetes server to \"kubernetes\" (internal hostname)") cfg.Host = fmt.Sprintf("kubernetes:%v", config.Port) clientset, err = kubernetes.NewForConfig(cfg) } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index fdd02a62..a2bb8edd 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -58,6 +58,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } + if svc.Spec.LoadBalancerIP == "" { log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) } else { From ec6fbfd16255a8ec865c18ca4d457348c6969197 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 20 Oct 2021 14:53:19 +0100 Subject: [PATCH 155/542] Fixes order for reading env vars, and ignore svc --- cmd/kube-vip.go | 12 ++++++------ pkg/manager/manager_bgp.go | 4 +++- pkg/manager/watcher.go | 9 ++++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 28cca413..43123ac6 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -211,6 +211,12 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) + // parse environment variables, these will overwrite anything loaded or flags + err := kubevip.ParseEnvironment(&initConfig) + if err != nil { + log.Fatalln(err) + } + if initConfig.Interface == "" { log.Infof("No interface is specified for VIP in config, auto-detecting default Interface") defaultIF, err := vip.GetDefaultGatewayInterface() @@ -226,12 +232,6 @@ var kubeVipManager = &cobra.Command{ Addr: initConfig.PrometheusHTTPServer, }) - // parse environment variables, these will overwrite anything loaded or flags - err := kubevip.ParseEnvironment(&initConfig) - if err != nil { - log.Fatalln(err) - } - // User Environment variables as an option to make manifest clearer envConfigMap := os.Getenv("vip_configmap") if envConfigMap != "" { diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index a91a7c52..409f481f 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -75,7 +75,9 @@ func (sm *Manager) startBGP() error { <-sm.signalChan log.Info("Received termination, signaling shutdown") if sm.config.EnableControlPane { - cpCluster.Stop() + if cpCluster != nil { + cpCluster.Stop() + } } // Cancel the context, which will in turn cancel the leadership cancel() diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index a2bb8edd..f32c9a4b 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -58,7 +58,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } if svc.Spec.LoadBalancerIP == "" { log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) } else { @@ -75,6 +78,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } err = sm.stopService(string(svc.UID)) if err != nil { log.Error(err) From 2e9c2244c1382a77f95536095208795d4ad342b1 Mon Sep 17 00:00:00 2001 From: Steve Sloka Date: Tue, 19 Oct 2021 11:15:09 -0400 Subject: [PATCH 156/542] Adds golangci-lint to check for code errors + clean up resulting findings after running. Signed-off-by: Steve Sloka --- .golangci.yml | 13 +++ Makefile | 2 +- cmd/kube-vip-config.go | 8 +- cmd/kube-vip-kubeadm.go | 22 +++-- cmd/kube-vip-manifests.go | 15 ++-- cmd/kube-vip-start.go | 8 +- cmd/kube-vip.go | 15 ++-- pkg/bgp/peers.go | 9 ++- pkg/cluster/clusterLeader.go | 18 ++--- pkg/cluster/clusterRaft.go | 35 ++++---- pkg/cluster/singleNode.go | 13 +-- pkg/kubevip/config_envvar.go | 14 ++-- pkg/kubevip/config_generator.go | 16 ++-- pkg/kubevip/config_manager.go | 2 +- pkg/kubevip/config_types.go | 2 +- pkg/leaderElection/leaderelection.go | 3 +- pkg/leaderElection/metrics.go | 5 +- pkg/loadbalancer/lb_connections.go | 4 +- pkg/loadbalancer/lb_http.go | 9 ++- pkg/loadbalancer/lb_tcp.go | 117 --------------------------- pkg/manager/manager.go | 5 +- pkg/manager/manager_arp.go | 2 +- pkg/manager/manager_bgp.go | 2 +- pkg/manager/prom.go | 1 + pkg/manager/services.go | 14 ++-- pkg/manager/watcher.go | 3 +- pkg/packet/eip.go | 9 ++- pkg/service/manager.go | 4 +- pkg/service/manager_arp.go | 7 +- pkg/service/manager_bgp.go | 7 +- pkg/service/services.go | 18 +++-- pkg/service/watcher.go | 33 -------- pkg/vip/address.go | 4 +- pkg/vip/arp.go | 3 +- pkg/vip/dhcp.go | 10 ++- pkg/vip/dns.go | 9 ++- pkg/vip/ndp.go | 4 + testing/e2e/e2e_test.go | 3 +- 38 files changed, 192 insertions(+), 276 deletions(-) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..bda104b7 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,13 @@ +run: + timeout: 10m + +linters: + enable: + - bodyclose + - gofmt + - goimports + - revive + - gosec + - misspell + - unconvert + - unparam diff --git a/Makefile b/Makefile index 49da6c6f..0cab2b98 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ check: go mod tidy test -z "$(git status --porcelain)" test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" - golint ./... + golangci-lint run go vet ./... run: install diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index 60857f3e..d3f4ab8d 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -24,13 +24,13 @@ func init() { kubeVipSampleConfig.Flags().BoolVar(&cliConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") kubeVipSampleConfig.Flags().BoolVar(&cliConfig.EnableARP, "arp", true, "Use ARP broadcasts to improve VIP re-allocations") kubeVipSampleConfig.Flags().StringVar(&cliLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") - kubeVipSampleConfig.Flags().StringSliceVar(&cliRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port") + kubeVipSampleConfig.Flags().StringSliceVar(&cliRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma separated remotePeers, format: id:address:port") // Load Balancer flags kubeVipSampleConfig.Flags().BoolVar(&cliConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP") kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)") kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance") kubeVipSampleConfig.Flags().IntVar(&cliConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") - kubeVipSampleConfig.Flags().StringSliceVar(&cliBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma seperated backends, format: address:port") + kubeVipSampleConfig.Flags().StringSliceVar(&cliBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") } var kubeVipSampleConfig = &cobra.Command{ @@ -72,13 +72,13 @@ var kubeVipSampleConfig = &cobra.Command{ err := cliConfig.ParseFlags(cliLocalPeer, cliRemotePeers, cliBackends) if err != nil { - cmd.Help() + _ = cmd.Help() log.Fatalln(err) } err = kubevip.ParseEnvironment(&cliConfig) if err != nil { - cmd.Help() + _ = cmd.Help() log.Fatalln(err) } diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index fdb2a515..d618a283 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -29,7 +29,7 @@ var kubeKubeadm = &cobra.Command{ Use: "kubeadm", Short: "Kubeadm functions", Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() // TODO - A load of text detailing what's actually happening }, } @@ -43,15 +43,19 @@ var kubeKubeadmInit = &cobra.Command{ log.SetLevel(log.Level(logLevel)) initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer) // TODO - A load of text detailing what's actually happening - kubevip.ParseEnvironment(&initConfig) + err := kubevip.ParseEnvironment(&initConfig) + if err != nil { + log.Fatalf("Error parsing environment from config: %v", err) + } + // TODO - check for certain things VIP/interfaces if initConfig.Interface == "" { - cmd.Help() + _ = cmd.Help() log.Fatalln("No interface is specified for kube-vip to bind to") } if initConfig.VIP == "" && initConfig.Address == "" { - cmd.Help() + _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) @@ -69,15 +73,19 @@ var kubeKubeadmJoin = &cobra.Command{ initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer) // TODO - A load of text detailing what's actually happening - kubevip.ParseEnvironment(&initConfig) + err := kubevip.ParseEnvironment(&initConfig) + if err != nil { + log.Fatalf("Error parsing environment from config: %v", err) + } + // TODO - check for certain things VIP/interfaces if initConfig.Interface == "" { - cmd.Help() + _ = cmd.Help() log.Fatalln("No interface is specified for kube-vip to bind to") } if initConfig.VIP == "" && initConfig.Address == "" { - cmd.Help() + _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 16f0aea5..ec01e096 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -28,7 +28,7 @@ var kubeManifest = &cobra.Command{ Use: "manifest", Short: "Manifest functions", Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() // TODO - A load of text detailing what's actually happening }, } @@ -41,11 +41,13 @@ var kubeManifestPod = &cobra.Command{ log.SetLevel(log.Level(logLevel)) initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer) // TODO - A load of text detailing what's actually happening - kubevip.ParseEnvironment(&initConfig) + if err := kubevip.ParseEnvironment(&initConfig); err != nil { + log.Fatalf("Error parsing environment from config: %v", err) + } // The control plane has a requirement for a VIP being specified if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { - cmd.Help() + _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) @@ -62,12 +64,15 @@ var kubeManifestDaemon = &cobra.Command{ log.SetLevel(log.Level(logLevel)) initConfig.LoadBalancers = append(initConfig.LoadBalancers, initLoadBalancer) // TODO - A load of text detailing what's actually happening - kubevip.ParseEnvironment(&initConfig) + if err := kubevip.ParseEnvironment(&initConfig); err != nil { + log.Fatalf("error parsing environment config: %v", err) + } + // TODO - check for certain things VIP/interfaces // The control plane has a requirement for a VIP being specified if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { - cmd.Help() + _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 3a868627..f1173a92 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -33,14 +33,14 @@ func init() { kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") kubeVipStart.Flags().BoolVar(&startConfig.EnableARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") kubeVipStart.Flags().StringVar(&startLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") - kubeVipStart.Flags().StringSliceVar(&startRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma seperated remotePeers, format: id:address:port") + kubeVipStart.Flags().StringSliceVar(&startRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma separated remotePeers, format: id:address:port") // Load Balancer flags kubeVipStart.Flags().BoolVar(&startConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP") kubeVipStart.Flags().StringVar(&startConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)") kubeVipStart.Flags().StringVar(&startConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance") kubeVipStart.Flags().IntVar(&startConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") kubeVipStart.Flags().IntVar(&startConfigLB.BackendPort, "lbBackEndPort", 6443, "A port that all backends may be using (optional)") - kubeVipStart.Flags().StringSliceVar(&startBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma seperated backends, format: address:port") + kubeVipStart.Flags().StringSliceVar(&startBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") // Cluster configuration kubeVipStart.Flags().StringVar(&startKubeConfigPath, "kubeConfig", "/etc/kubernetes/admin.conf", "The path of a kubernetes configuration file") @@ -83,7 +83,9 @@ var kubeVipStart = &cobra.Command{ if startConfig.SingleNode { // If the Virtual IP isn't disabled then create the netlink configuration // Start a single node cluster - newCluster.StartSingleNode(&startConfig, disableVIP) + if err := newCluster.StartSingleNode(&startConfig, disableVIP); err != nil { + log.Errorf("error starting single node: %v", err) + } } else { if disableVIP { log.Fatalln("Cluster mode requires the Virtual IP to be enabled, use single node with no VIP") diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 28cca413..1f877bcd 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -21,16 +21,16 @@ import ( var configPath string // Path to the configuration file -var namespace string +// var namespace string // Disable the Virtual IP (bind to the existing network stack) var disableVIP bool // Disable the Virtual IP (bind to the existing network stack) -var controlPlane bool +// var controlPlane bool // Run as a load balancer service (within a pod / kubernetes) -var serviceArp bool +// var serviceArp bool // ConfigMap name within a Kubernetes cluster var configMap string @@ -114,7 +114,7 @@ func init() { kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support") - kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma seperated BGP Peer, format: address:as:password:multihop") + kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma separated BGP Peer, format: address:as:password:multihop") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") @@ -129,7 +129,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") // Prometheus HTTP Server - kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "promethuesHTTPServer", ":2112", "Host and port used to expose Promethues metrics via an HTTP server") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "promethuesHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) @@ -167,7 +167,7 @@ var kubeVipSample = &cobra.Command{ Use: "sample", Short: "Generate a Sample configuration", Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + _ = cmd.Help() }, } @@ -215,7 +215,7 @@ var kubeVipManager = &cobra.Command{ log.Infof("No interface is specified for VIP in config, auto-detecting default Interface") defaultIF, err := vip.GetDefaultGatewayInterface() if err != nil { - cmd.Help() + _ = cmd.Help() log.Fatalf("unable to detect default interface -> [%v]", err) } initConfig.Interface = defaultIF.Name @@ -266,6 +266,7 @@ var kubeVipManager = &cobra.Command{ }, } +// PrometheusHTTPServerConfig defines the Prometheus server configuration. type PrometheusHTTPServerConfig struct { // Addr sets the http server address used to expose the metric endpoint Addr string diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 7de454b6..c04b404c 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -7,12 +7,12 @@ import ( "strconv" "strings" - "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes" //nolint "github.com/golang/protobuf/ptypes/any" api "github.com/osrg/gobgp/api" ) -//AddPeer will add peers to the BGP configuration +// AddPeer will add peers to the BGP configuration func (b *Server) AddPeer(peer Peer) (err error) { port := 179 @@ -20,7 +20,7 @@ func (b *Server) AddPeer(peer Peer) (err error) { peer.Address = t[0] if port, err = strconv.Atoi(t[1]); err != nil { - return fmt.Errorf("Unable to parse port '%s' as int: %s", t[1], err) + return fmt.Errorf("unable to parse port '%s' as int: %s", t[1], err) } } @@ -73,11 +73,13 @@ func (b *Server) getPath(ip net.IP) *api.Path { pfxLen = 128 } + //nolint nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ Prefix: ip.String(), PrefixLen: pfxLen, }) + //nolint a1, _ := ptypes.MarshalAny(&api.OriginAttribute{ Origin: 0, }) @@ -91,6 +93,7 @@ func (b *Server) getPath(ip net.IP) *api.Path { nh = b.c.RouterID } + //nolint a2, _ := ptypes.MarshalAny(&api.NextHopAttribute{ NextHop: nh, }) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index f6c8d3cf..f38d4c57 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -126,6 +126,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe signal.Notify(signalChan, syscall.SIGTERM) // Add Notification for SIGKILL (sent from Kubernetes) + //nolint signal.Notify(signalChan, syscall.SIGKILL) go func() { @@ -137,7 +138,10 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe }() // (attempt to) Remove the virtual IP, incase it already exists - cluster.Network.DeleteIP() + err = cluster.Network.DeleteIP() + if err != nil { + log.Errorf("could not delete virtualIP: %v", err) + } // Managers for Vip load balancers and none-vip loadbalancers nonVipLB := loadbalancer.LBManager{} @@ -150,7 +154,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } }() - // If Packet is enabled then we can begin our preperation work + // If Packet is enabled then we can begin our preparation work var packetClient *packngo.Client if c.EnableMetal { if c.ProviderConfig != "" { @@ -194,7 +198,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if len(c.LoadBalancers) != 0 { for x := range c.LoadBalancers { // If the load balancer doesn't bind to the VIP - if c.LoadBalancers[x].BindToVip == false { + if !c.LoadBalancers[x].BindToVip { err = nonVipLB.Add("", &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -267,7 +271,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // Once we have the VIP running, start the load balancer(s) that bind to the VIP for x := range c.LoadBalancers { - if c.LoadBalancers[x].BindToVip == true { + if c.LoadBalancers[x].BindToVip { err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -287,7 +291,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } } - if c.EnableARP == true { + if c.EnableARP { ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() @@ -375,10 +379,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe OnNewLeader: func(identity string) { // we're notified when new leader elected log.Infof("Node [%s] is assuming leadership of the cluster", identity) - - if identity == id { - // We have the lock - } }, }, }) diff --git a/pkg/cluster/clusterRaft.go b/pkg/cluster/clusterRaft.go index 08218384..755968af 100644 --- a/pkg/cluster/clusterRaft.go +++ b/pkg/cluster/clusterRaft.go @@ -51,7 +51,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { // If we want to start a node as leader then we will not add any remote peers, this will leave this as a cluster of one // The remotePeers will add themselves to the cluster as they're added - if c.StartAsLeader != true { + if !c.StartAsLeader { for x := range c.RemotePeers { // Make sure that we don't add in this server twice if c.LocalPeer.Address != c.RemotePeers[x].Address { @@ -87,7 +87,10 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { isLeader := c.StartAsLeader // (attempt to) Remove the virtual IP, incase it already exists - cluster.Network.DeleteIP() + err = cluster.Network.DeleteIP() + if err != nil { + log.Errorf("error deleting virtual IP: %v", err) + } // leader log broadcast - this counter is used to stop flooding STDOUT with leader log entries var leaderbroadcast int @@ -98,7 +101,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { // Iterate through all Configurations for x := range c.LoadBalancers { // If the load balancer doesn't bind to the VIP - if c.LoadBalancers[x].BindToVip == false { + if !c.LoadBalancers[x].BindToVip { err = nonVipLB.Add("", &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -112,15 +115,6 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { go func() { for { - if c.AddPeersAsBackends == true { - // Get addresses and change backends - - // c.LoadBalancers[0].Backends - // for x := range raftServer.GetConfiguration().Configuration().Servers { - // raftServer.GetConfiguration().Configuration().Servers[x].Address - // } - - } // Broadcast the current leader on this node if it's the correct time (every leaderLogcount * time.Second) if leaderbroadcast == leaderLogcount { log.Infof("The Node [%s] is leading", raftServer.Leader()) @@ -130,7 +124,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { // ensure that if this node is the leader, it is set as the leader if localAddress == string(raftServer.Leader()) { // Re-broadcast arp to ensure network stays up to date - if c.EnableARP == true { + if c.EnableARP { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -143,7 +137,10 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { } } else { // (attempt to) Remove the virtual IP, incase it already exists to keep nodes clean - cluster.Network.DeleteIP() + err := cluster.Network.DeleteIP() + if err != nil { + log.Errorf("could not delete virtualIP: %v", err) + } isLeader = false } @@ -166,7 +163,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { for x := range c.LoadBalancers { - if c.LoadBalancers[x].BindToVip == true { + if c.LoadBalancers[x].BindToVip { err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -187,7 +184,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { } } - if c.EnableARP == true { + if c.EnableARP { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -220,7 +217,7 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { log.WithFields(log.Fields{"error": err, "ip": cluster.Network.IP(), "interface": cluster.Network.Interface()}).Error("Could not check ip") } - if result == false { + if !result { log.Error("This node is leader and is adopting the virtual IP") err = cluster.Network.AddIP() @@ -231,14 +228,14 @@ func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { for x := range c.LoadBalancers { - if c.LoadBalancers[x].BindToVip == true { + if c.LoadBalancers[x].BindToVip { err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) } } } - if c.EnableARP == true { + if c.EnableARP { // Gratuitous ARP, will broadcast to new MAC <-> IP err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index cc33a9a8..88393b94 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -17,7 +17,7 @@ import ( func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) error { // Start kube-vip as a single node server - // TODO - Split all this code out as a seperate function + // TODO - Split all this code out as a separate function log.Infoln("Starting kube-vip as a single node cluster") log.Info("This node is assuming leadership of the cluster") @@ -32,7 +32,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro // Iterate through all Configurations for x := range c.LoadBalancers { // If the load balancer doesn't bind to the VIP - if c.LoadBalancers[x].BindToVip == false { + if !c.LoadBalancers[x].BindToVip { err := nonVipLB.Add("", &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -55,7 +55,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro // Once we have the VIP running, start the load balancer(s) that bind to the VIP for x := range c.LoadBalancers { - if c.LoadBalancers[x].BindToVip == true { + if c.LoadBalancers[x].BindToVip { err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) if err != nil { log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) @@ -64,7 +64,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro } } - if c.EnableARP == true { + if c.EnableARP { // Gratuitous ARP, will broadcast to new MAC <-> IP err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) if err != nil { @@ -73,6 +73,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro } go func() { + //nolint for { select { case <-cluster.stop: @@ -114,6 +115,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // use a Go context so we can tell the arp loop code when we // want to step down + //nolint ctxArp, cancelArp := context.WithCancel(context.Background()) defer cancelArp() @@ -130,7 +132,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser log.Warnf("%v", err) } - if c.EnableARP == true { + if c.EnableARP { ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() @@ -196,6 +198,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } go func() { + //nolint for { select { case <-cluster.stop: diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 6b1edb19..848f9692 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -6,16 +6,16 @@ const ( //vipArp - defines if the arp broadcast should be enabled vipArp = "vip_arp" - //vipLeaderElection - defines if the kubernetes algorithim should be used + //vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaderElection = "vip_leaderelection" - //vipLeaderElection - defines if the kubernetes algorithim should be used + //vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaseDuration = "vip_leaseduration" - //vipLeaderElection - defines if the kubernetes algorithim should be used + //vipLeaderElection - defines if the kubernetes algorithm should be used vipRenewDeadline = "vip_renewdeadline" - //vipLeaderElection - defines if the kubernetes algorithim should be used + //vipLeaderElection - defines if the kubernetes algorithm should be used vipRetryPeriod = "vip_retryperiod" //vipLogLevel - defines the level of logging to produce (5 being the most verbose) @@ -66,7 +66,7 @@ const ( vipLocalPeer = "vip_localpeer" //vipRemotePeers defines the configuration of the local raft peer - vipRemotePeers = "vip_remotepeers" + // vipRemotePeers = "vip_remotepeers" //vipAddPeersToLB defines that RAFT peers should be added to the load-balancer vipAddPeersToLB = "vip_addpeerstolb" @@ -98,7 +98,7 @@ const ( //bgpPeerAS defines the AS for a BGP peer bgpPeerAS = "bgp_peeras" //bgpPeerAS defines the AS for a BGP peer - bgpPeerPassword = "bgp_peerpass" + bgpPeerPassword = "bgp_peerpass" // nolint //bgpMultiHop enables mulithop routing bgpMultiHop = "bgp_multihop" //bgpSourceIF defines the source interface for BGP peering @@ -137,5 +137,5 @@ const ( lbBackends = "lb_backends" //vipConfigMap defines the configmap that kube-vip will watch for service definitions - vipConfigMap = "vip_configmap" + // vipConfigMap = "vip_configmap" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 84b36aa5..9a0988e1 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -56,7 +56,7 @@ func ParseEnvironment(c *Config) error { c.EnableLeaderElection = b } - // Attempt to find the Lease configuration from teh environment variables + // Attempt to find the Lease configuration from the environment variables env = os.Getenv(vipLeaseDuration) if env != "" { i, err := strconv.ParseInt(env, 10, 32) @@ -196,7 +196,7 @@ func ParseEnvironment(c *Config) error { c.EnableARP = b } - //Removal of seperate peer + //Removal of separate peer env = os.Getenv(vipLocalPeer) if env != "" { // Parse the string in format :

: @@ -213,10 +213,10 @@ func ParseEnvironment(c *Config) error { // Remove existing peers c.RemotePeers = []RaftPeer{} - // Parse the remote peers (comma seperated) + // Parse the remote peers (comma separated) s := strings.Split(env, ",") if len(s) == 0 { - return fmt.Errorf("The Remote Peer List [%s] is unable to be parsed, should be in comma seperated format :
:", env) + return fmt.Errorf("The Remote Peer List [%s] is unable to be parsed, should be in comma separated format :
:", env) } for x := range s { // Parse the each remote peer string in format :
: @@ -426,10 +426,10 @@ func parseEnvironmentLoadBalancer(c *Config) error { // Remove existing backends c.LoadBalancers[0].Backends = []BackEnd{} - // Parse the remote peers (comma seperated) + // Parse the remote peers (comma separated) s := strings.Split(env, ",") if len(s) == 0 { - return fmt.Errorf("The Backends List [%s] is unable to be parsed, should be in comma seperated format
:", env) + return fmt.Errorf("The Backends List [%s] is unable to be parsed, should be in comma separated format
:", env) } for x := range s { // Parse the each remote peer string in format
: @@ -473,7 +473,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, iface...) } - // Detect if we should be using a seperate interface for sercices + // Detect if we should be using a separate interface for sercices if c.ServicesInterface != "" { // build environment variables svcInterface := []corev1.EnvVar{ @@ -743,7 +743,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }) } - // Parse peers into a comma seperated string + // Parse peers into a comma separated string if len(c.RemotePeers) != 0 { var peers string for x := range c.RemotePeers { diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index ae596ce2..a9e588c0 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -55,7 +55,7 @@ func OpenConfig(path string) (*Config, error) { return nil, err } - // If data is read succesfully parse the yaml + // If data is read successfully parse the yaml var c Config err = yaml.Unmarshal(configData, &c) if err != nil { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index ca0f656d..20959660 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -99,7 +99,7 @@ type Config struct { // LeaderElection defines all of the settings for Kubernetes LeaderElection type LeaderElection struct { - // EnableLeaderElection will use the Kubernetes leader election algorithim + // EnableLeaderElection will use the Kubernetes leader election algorithm EnableLeaderElection bool `yaml:"enableLeaderElection"` // Lease Duration - length of time a lease can be held for diff --git a/pkg/leaderElection/leaderelection.go b/pkg/leaderElection/leaderelection.go index 24afd72d..3755dade 100644 --- a/pkg/leaderElection/leaderelection.go +++ b/pkg/leaderElection/leaderelection.go @@ -109,6 +109,7 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) { } // LeaderElectionConfig defines the configuration for the leaderElection +// nolint type LeaderElectionConfig struct { // Lock is the resource that will be used for locking Lock rl.Interface @@ -191,7 +192,7 @@ type LeaderElector struct { metrics leaderMetricsAdapter // name is the name of the resource lock for debugging - name string + // name string } // Run starts the leader election loop diff --git a/pkg/leaderElection/metrics.go b/pkg/leaderElection/metrics.go index 65917bf8..20c0311c 100644 --- a/pkg/leaderElection/metrics.go +++ b/pkg/leaderElection/metrics.go @@ -28,7 +28,7 @@ type leaderMetricsAdapter interface { leaderOff(name string) } -// GaugeMetric represents a single numerical value that can arbitrarily go up +// SwitchMetric represents a single numerical value that can arbitrarily go up // and down. type SwitchMetric interface { On(name string) @@ -72,7 +72,8 @@ type MetricsProvider interface { type noopMetricsProvider struct{} -func (_ noopMetricsProvider) NewLeaderMetric() SwitchMetric { +// NewLeaderMetric returns a new SwitchMetric. +func (nmp noopMetricsProvider) NewLeaderMetric() SwitchMetric { return noopMetric{} } diff --git a/pkg/loadbalancer/lb_connections.go b/pkg/loadbalancer/lb_connections.go index 7dbce424..4a7ed227 100644 --- a/pkg/loadbalancer/lb_connections.go +++ b/pkg/loadbalancer/lb_connections.go @@ -62,7 +62,7 @@ func persistentConnection(frontendConnection net.Conn, lb *kubevip.LoadBalancer) wg.Done() }() // go func() { - // Begin copying recieving (endpoint -> back to frontend) + // Begin copying receiving (endpoint -> back to frontend) bytes, err := io.Copy(frontendConnection, endpoint) log.Debugf("[%d] bytes of data sent to client", bytes) if err != nil { @@ -116,7 +116,7 @@ func persistentUDPConnection(frontendConnection net.Conn, lb *kubevip.LoadBalanc wg.Done() }() // go func() { - // Begin copying recieving (endpoint -> back to frontend) + // Begin copying receiving (endpoint -> back to frontend) bytes, err := io.Copy(frontendConnection, endpoint) log.Debugf("[%d] bytes of data sent to client", bytes) if err != nil { diff --git a/pkg/loadbalancer/lb_http.go b/pkg/loadbalancer/lb_http.go index 7a0bef40..57477206 100644 --- a/pkg/loadbalancer/lb_http.go +++ b/pkg/loadbalancer/lb_http.go @@ -57,11 +57,10 @@ func (lb *LBInstance) startHTTP(bindAddress string) error { server := &http.Server{Addr: frontEnd, Handler: mux} - go func() error { + go func() { if err := server.ListenAndServe(); err != nil { - return err + log.Fatalf("error starting http server: %v", err) } - return nil }() // If the stop channel is closed then the server will be gracefully shut down @@ -120,7 +119,9 @@ func StartHTTP(lb *kubevip.LoadBalancer, address string) error { mux := http.NewServeMux() mux.HandleFunc("/", handler) log.Infof("Starting server listening [%s]", frontEnd) - http.ListenAndServe(frontEnd, mux) + if err := http.ListenAndServe(frontEnd, mux); err != nil { + log.Fatalf("error serving: %v", err) + } // Should never get here return nil } diff --git a/pkg/loadbalancer/lb_tcp.go b/pkg/loadbalancer/lb_tcp.go index 78cac55b..a2b6c6e8 100644 --- a/pkg/loadbalancer/lb_tcp.go +++ b/pkg/loadbalancer/lb_tcp.go @@ -1,13 +1,11 @@ package loadbalancer import ( - "bytes" "fmt" "io" "net" "time" - "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" ) @@ -61,118 +59,3 @@ func (lb *LBInstance) startTCP(bindAddress string) error { return nil } - -// startTCPDNU - Start TCP service Do not use -// This stops the service by closing the listener and then ignorning the error from Accept() -func (lb *LBInstance) startTCPDNU(bindAddress string) error { - fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port) - log.Infof("Starting TCP Load Balancer for service [%s]", fullAddress) - - //l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port)) - laddr, err := net.ResolveTCPAddr("tcp", fullAddress) - if nil != err { - log.Errorln(err) - } - l, err := net.ListenTCP("tcp", laddr) - if nil != err { - return fmt.Errorf("Unable to bind [%s]", err.Error()) - } - go func() { - <-lb.stop - log.Debugln("Closing listener") - - // We've closed the stop channel - err = l.Close() - if err != nil { - return - } - // Close the stopped channel as the listener has been stopped - close(lb.stopped) - - }() - - go func() { - for { - - fd, err := l.Accept() - if err != nil { - // Check it it's an accept timeout - if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { - continue - } else if err != io.EOF { - log.Errorf("TCP Accept error [%s]", err) - return - } - } - go persistentConnection(fd, lb.instance) - //go processRequests(lb.instance, fd) - } - // } - }() - log.Infof("Load Balancer [%s] started", lb.instance.Name) - - return nil -} - -// user -> [LB] -// [LB] (select end pot) -> [endpoint] -// -// -// -// -// -// - -func processRequests(lb *kubevip.LoadBalancer, frontendConnection net.Conn) { - for { - // READ FROM client - buf := make([]byte, 1024*1024) - datalen, err := frontendConnection.Read(buf) - if err != nil { - log.Fatalf("%v", err) - } - log.Debugf("Sent [%d] bytes to the LB", datalen) - data := buf[0:datalen] - - // Connect to Endpoint - ep, err := lb.ReturnEndpointAddr() - if err != nil { - log.Errorf("No Backends available") - } - log.Debugf("Attempting endpoint [%s]", ep) - - endpoint, err := net.Dial("tcp", ep) - if err != nil { - fmt.Println("dial error:", err) - // return nil, err - } - log.Debugf("succesfully connected to [%s]", ep) - - // Set a timeout - endpoint.SetReadDeadline(time.Now().Add(time.Second * 1)) - - b, err := endpointRequest(endpoint, ep, string(data)) - - _, err = frontendConnection.Write(b) - if err != nil { - log.Fatal("Write: ", err) - } - } -} - -// endpointRequest will take an endpoint address and send the data and wait for the response -func endpointRequest(endpoint net.Conn, endpointAddr, request string) ([]byte, error) { - - // defer conn.Close() - datalen, err := fmt.Fprintf(endpoint, request) - if err != nil { - fmt.Println("dial error:", err) - return nil, err - } - log.Debugf("Sent [%d] bytes to the endpoint", datalen) - - var b bytes.Buffer - io.Copy(&b, endpoint) - log.Debugf("Recieved [%d] from the endpoint", b.Len()) - return b.Bytes(), nil -} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index a5f0e149..19a2018d 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -31,7 +31,7 @@ type Manager struct { config *kubevip.Config // Manager services - service bool + // service bool // Keeps track of all running instances serviceInstances []Instance @@ -45,7 +45,7 @@ type Manager struct { // This channel is used to signal a shutdown signalChan chan os.Signal - // This is a promethues counter used to count the number of events received + // This is a prometheus counter used to count the number of events received // from the service watcher countServiceWatchEvent *prometheus.CounterVec } @@ -148,6 +148,7 @@ func (sm *Manager) Start() error { signal.Notify(sm.signalChan, syscall.SIGTERM) // Add Notification for SIGKILL (sent from Kubernetes) + //nolint signal.Notify(sm.signalChan, syscall.SIGKILL) // If BGP is enabled then we start a server instance that will broadcast VIPs diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index cd46878b..68cc730b 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -110,7 +110,7 @@ func (sm *Manager) startARP() error { // Set the struct to nil so nothing should use it in future sm.upnp = nil } else { - log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + log.Infof("Successfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) } } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index a91a7c52..eb60c18a 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -19,7 +19,7 @@ func (sm *Manager) startBGP() error { //var ns string var err error - // If Packet is enabled then we can begin our preperation work + // If Packet is enabled then we can begin our preparation work var packetClient *packngo.Client if sm.config.EnableMetal { if sm.config.ProviderConfig != "" { diff --git a/pkg/manager/prom.go b/pkg/manager/prom.go index be3c0014..3020484a 100644 --- a/pkg/manager/prom.go +++ b/pkg/manager/prom.go @@ -2,6 +2,7 @@ package manager import "github.com/prometheus/client_golang/prometheus" +// PrometheusCollector defines a service watch event counter. func (sm *Manager) PrometheusCollector() []prometheus.Collector { return []prometheus.Collector{sm.countServiceWatchEvent} } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 153c92ed..5e039428 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -44,14 +44,18 @@ func (sm *Manager) deleteService(uid string) error { } else { // Flip the found when we match found = true - if sm.serviceInstances[x].isDHCP == true { + if sm.serviceInstances[x].isDHCP { sm.serviceInstances[x].dhcpClient.Stop() macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for deleting DHCP Link : %v", err) + return fmt.Errorf("error finding VIP Interface: %v", err) + } + + err = netlink.LinkDel(macvlan) + if err != nil { + return fmt.Errorf("error deleting DHCP Link : %v", err) } - netlink.LinkDel(macvlan) } if sm.serviceInstances[x].vipConfig.EnableBGP { cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) @@ -61,8 +65,8 @@ func (sm *Manager) deleteService(uid string) error { } } // If we've been through all services and not found the correct one then error - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) + if !found { + return fmt.Errorf("unable to find/stop service [%s]", uid) } // Update the service array diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index a2bb8edd..4892bf7c 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -58,7 +58,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - + if svc.Spec.LoadBalancerIP == "" { log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) } else { @@ -183,7 +183,6 @@ func (sm *Manager) annotationsWatcher() error { sm.config.BGPPeerConfig = bgpPeer rw.Stop() - break case watch.Deleted: node, ok := event.Object.(*v1.Node) if !ok { diff --git a/pkg/packet/eip.go b/pkg/packet/eip.go index 29d30787..0ecb3558 100644 --- a/pkg/packet/eip.go +++ b/pkg/packet/eip.go @@ -19,7 +19,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { // Fallback to attempting to find the project by name proj := findProject(k.MetalProject, c) if proj == nil { - return fmt.Errorf("Unable to find Project [%s]", k.MetalProject) + return fmt.Errorf("unable to find Project [%s]", k.MetalProject) } projID = proj.ID @@ -40,7 +40,10 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { // If attachements already exist then remove them if len(ip.Assignments) != 0 { hrefID := path.Base(ip.Assignments[0].Href) - c.DeviceIPs.Unassign(hrefID) + _, err := c.DeviceIPs.Unassign(hrefID) + if err != nil { + return fmt.Errorf("unable to unassign deviceIP %q: %v", hrefID, err) + } } } } @@ -48,7 +51,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { // Lookup this server through the packet API thisDevice := findSelf(c, projID) if thisDevice == nil { - return fmt.Errorf("Unable to find local/this device in packet API") + return fmt.Errorf("unable to find local/this device in packet API") } // Assign the EIP to this device diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 2402a868..3082a5f9 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -45,7 +45,7 @@ type Manager struct { // This channel is used to signal a shutdown signalChan chan os.Signal - // This is a promethues counter used to count the number of events received + // This is a prometheus counter used to count the number of events received // from the service watcher countServiceWatchEvent *prometheus.CounterVec } @@ -77,7 +77,7 @@ type Instance struct { // NewManager will create a new managing object func NewManager(configMap string, config *kubevip.Config) (*Manager, error) { var clientset *kubernetes.Clientset - if OutSideCluster == false { + if !OutSideCluster { // This will attempt to load the configuration when running within a POD cfg, err := rest.InClusterConfig() if err != nil { diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index af471877..3705cc21 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -38,7 +38,7 @@ func (sm *Manager) startARP() error { // Set the struct to nil so nothing should use it in future sm.upnp = nil } else { - log.Infof("Succesfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + log.Infof("Successfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) } } @@ -89,6 +89,7 @@ func (sm *Manager) startARP() error { signal.Notify(signalChan, syscall.SIGTERM) // Add Notification for SIGKILL (sent from Kubernetes) + //nolint signal.Notify(signalChan, syscall.SIGKILL) go func() { <-signalChan @@ -112,7 +113,9 @@ func (sm *Manager) startARP() error { RetryPeriod: 1 * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - sm.servicesWatcher(ctx) + if err := sm.servicesWatcher(ctx); err != nil { + log.Fatalf("error starting services watcher: %v", err) + } }, OnStoppedLeading: func() { // we can do cleanup here diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 00694806..11d017e1 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -15,7 +15,7 @@ import ( // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) startBGP() error { - // If Packet is enabled then we can begin our preperation work + // If Packet is enabled then we can begin our preparation work var packetClient *packngo.Client var err error if sm.config.EnableMetal { @@ -63,6 +63,7 @@ func (sm *Manager) startBGP() error { signal.Notify(signalChan, syscall.SIGTERM) // Add Notification for SIGKILL (sent from Kubernetes) + //nolint signal.Notify(signalChan, syscall.SIGKILL) go func() { <-signalChan @@ -71,7 +72,9 @@ func (sm *Manager) startBGP() error { cancel() }() - sm.servicesWatcher(ctx) + if err := sm.servicesWatcher(ctx); err != nil { + log.Fatalf("error starting services watcher: %v", err) + } log.Infof("Shutting down Kube-Vip") diff --git a/pkg/service/services.go b/pkg/service/services.go index a4a1bddd..499d6df6 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -26,8 +26,8 @@ func (sm *Manager) stopService(uid string) error { sm.serviceInstances[x].cluster.Stop() } } - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) + if !found { + return fmt.Errorf("unable to find/stop service [%s]", uid) } return nil } @@ -42,12 +42,14 @@ func (sm *Manager) deleteService(uid string) error { } else { // Flip the found when we match found = true - if sm.serviceInstances[x].isDHCP == true { + if sm.serviceInstances[x].isDHCP { macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) if err != nil { - return fmt.Errorf("Error finding VIP Interface, for deleting DHCP Link : %v", err) + return fmt.Errorf("error finding VIP Interface, for deleting DHCP Link : %v", err) + } + if err := netlink.LinkDel(macvlan); err != nil { + return fmt.Errorf("error deleing link: %v", err) } - netlink.LinkDel(macvlan) } if sm.serviceInstances[x].vipConfig.EnableBGP { cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) @@ -57,8 +59,8 @@ func (sm *Manager) deleteService(uid string) error { } } // If we've been through all services and not found the correct one then error - if found == false { - return fmt.Errorf("Unable to find/stop service [%s]", uid) + if !found { + return fmt.Errorf("unable to find/stop service [%s]", uid) } // Update the service array @@ -95,7 +97,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { } // This instance wasn't found, we need to add it to the manager - if foundInstance == false { + if !foundInstance { // Create new service var newService Instance newService.UID = newServiceUID diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index 4d5dd72f..bbea8af4 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -12,41 +12,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" - - "github.com/kube-vip/kube-vip/pkg/kubevip" ) -func rebuildEndpoints(eps v1.Endpoints) []kubevip.BackEnd { - var addresses []string - var ports []int32 - - for x := range eps.Subsets { - // Loop over addresses - for y := range eps.Subsets[x].Addresses { - addresses = append(addresses, eps.Subsets[x].Addresses[y].IP) - } - for y := range eps.Subsets[x].Ports { - ports = append(ports, eps.Subsets[x].Ports[y].Port) - } - } - var newBackend []kubevip.BackEnd - - // Build endpoints - for x := range addresses { - for y := range ports { - // Print out Backends if debug logging is enabled - if log.GetLevel() == log.DebugLevel { - fmt.Printf("-> Address: %s:%d \n", addresses[x], ports[y]) - } - newBackend = append(newBackend, kubevip.BackEnd{ - Address: addresses[x], - Port: int(ports[y]), - }) - } - } - return newBackend -} - // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context) error { // Watch function diff --git a/pkg/vip/address.go b/pkg/vip/address.go index fb3dfe94..2a3eb814 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -92,7 +92,7 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { return result, err } -//AddIP - Add an IP address to the interface +// AddIP - Add an IP address to the interface func (configurator *network) AddIP() error { if err := netlink.AddrReplace(configurator.link, configurator.address); err != nil { return errors.Wrap(err, "could not add ip") @@ -100,7 +100,7 @@ func (configurator *network) AddIP() error { return nil } -//DeleteIP - Remove an IP address from the interface +// DeleteIP - Remove an IP address from the interface func (configurator *network) DeleteIP() error { result, err := configurator.IsSet() if err != nil { diff --git a/pkg/vip/arp.go b/pkg/vip/arp.go index a8b1642f..6038f0a8 100644 --- a/pkg/vip/arp.go +++ b/pkg/vip/arp.go @@ -1,6 +1,7 @@ +//go:build linux // +build linux -// These syscalls are only supported on Linux, so this uses a build directive during compilation. Other OS's will use the arp_unsupported.go and recieve an error +// These syscalls are only supported on Linux, so this uses a build directive during compilation. Other OS's will use the arp_unsupported.go and receive an error package vip diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index e82fe281..41ce6e4d 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -1,6 +1,7 @@ -// It"s DHCP client implementation that refers to https://www.rfc-editor.org/rfc/rfc2131.html package vip +// DHCP client implementation that refers to https://www.rfc-editor.org/rfc/rfc2131.html + import ( "context" "fmt" @@ -16,7 +17,7 @@ import ( // Callback is a function called on certain events type Callback func(*nclient4.Lease) -// Client is a DHCP client, responsible for maintaining ipv4 lease for one specified interface +// DHCPClient is responsible for maintaining ipv4 lease for one specified interface type DHCPClient struct { iface *net.Interface lease *nclient4.Lease @@ -26,6 +27,7 @@ type DHCPClient struct { onBound Callback } +// NewDHCPClient returns a new DHCP Client. func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string, onBound Callback) *DHCPClient { return &DHCPClient{ iface: iface, @@ -163,10 +165,12 @@ func (c *DHCPClient) Start() { func (c *DHCPClient) request() (*nclient4.Lease, error) { broadcast, err := nclient4.New(c.iface.Name) - defer broadcast.Close() if err != nil { return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %w", c.iface.Name, err) } + + defer broadcast.Close() + return broadcast.Request(context.TODO()) } diff --git a/pkg/vip/dns.go b/pkg/vip/dns.go index c773c216..63d15c03 100644 --- a/pkg/vip/dns.go +++ b/pkg/vip/dns.go @@ -40,8 +40,13 @@ func (d *ipUpdater) Run(ctx context.Context) { } log.Infof("setting %s as an IP", ip) - d.vip.SetIP(ip) - d.vip.AddIP() + if err := d.vip.SetIP(ip); err != nil { + log.Errorf("setting %s as an IP: %v", ip, err) + } + + if err := d.vip.AddIP(); err != nil { + log.Errorf("error adding virtual IP: %v", err) + } } time.Sleep(3 * time.Second) diff --git a/pkg/vip/ndp.go b/pkg/vip/ndp.go index f0b52b64..73fec41e 100644 --- a/pkg/vip/ndp.go +++ b/pkg/vip/ndp.go @@ -9,12 +9,14 @@ import ( log "github.com/sirupsen/logrus" ) +// NdpResponder defines the parameters for the NDP connection. type NdpResponder struct { intf string hardwareAddr net.HardwareAddr conn *ndp.Conn } +// NewNDPResponder takes an ifaceName and returns a new NDP responder and error if encountered. func NewNDPResponder(ifaceName string) (*NdpResponder, error) { iface, err := net.InterfaceByName(ifaceName) if err != nil { @@ -35,10 +37,12 @@ func NewNDPResponder(ifaceName string) (*NdpResponder, error) { return ret, nil } +// Close closes the NDP responder connection. func (n *NdpResponder) Close() error { return n.conn.Close() } +// SendGratuitous broadcasts an NDP update or returns error if encountered. func (n *NdpResponder) SendGratuitous(address string) error { ip := net.ParseIP(address) if ip == nil { diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index e2dad316..3d3aaca5 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -227,7 +227,7 @@ func assertControlPlaneIsRoutable(controlPlaneVIP string, transportTimeout, even } transport := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // nolint } client := &http.Client{Transport: transport, Timeout: transportTimeout} Eventually(func() int { @@ -235,6 +235,7 @@ func assertControlPlaneIsRoutable(controlPlaneVIP string, transportTimeout, even if resp == nil { return -1 } + defer resp.Body.Close() return resp.StatusCode }, eventuallyTimeout).Should(Equal(http.StatusOK), "Failed to connect to VIP") } From 2cd9b36fac227e096070198a3781de32e9c68c7f Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 20 Oct 2021 15:08:09 +0100 Subject: [PATCH 157/542] Update ci.yaml --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 24b65bb5..067a1d9c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,6 +17,8 @@ jobs: uses: actions/setup-go@v2 with: go-version: '1.15' + - name: Install golangci-lint + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.42.1 - name: checks run: make check - name: test docker build From e2e2183e57a2e100720a7d15da3dd5ab6eba6fd4 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 20 Oct 2021 17:09:41 +0100 Subject: [PATCH 158/542] Update ci.yaml Moves from Go 1.15 to 1.16 --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 067a1d9c..a426b169 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: '1.15' + go-version: '1.16' - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.42.1 - name: checks From 843c3ebf940e4c1c33fb723f9df6b03ee863d2ae Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 20 Oct 2021 15:59:50 +0100 Subject: [PATCH 159/542] Removes local leaderElection fix --- go.mod | 20 +- go.sum | 83 +- pkg/cluster/clusterLeader.go | 2 +- pkg/leaderElection/OWNERS | 14 - pkg/leaderElection/healthzadaptor.go | 69 -- pkg/leaderElection/healthzadaptor_test.go | 177 ----- pkg/leaderElection/leaderelection.go | 392 ---------- pkg/leaderElection/leaderelection_test.go | 891 ---------------------- pkg/leaderElection/metrics.go | 110 --- 9 files changed, 49 insertions(+), 1709 deletions(-) delete mode 100644 pkg/leaderElection/OWNERS delete mode 100644 pkg/leaderElection/healthzadaptor.go delete mode 100644 pkg/leaderElection/healthzadaptor_test.go delete mode 100644 pkg/leaderElection/leaderelection.go delete mode 100644 pkg/leaderElection/leaderelection_test.go delete mode 100644 pkg/leaderElection/metrics.go diff --git a/go.mod b/go.mod index 4d1d696b..a4e36267 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/go-hclog v0.16.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-msgpack v1.1.5 // indirect @@ -18,14 +17,13 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e github.com/jpillora/backoff v1.0.0 - github.com/json-iterator/go v1.1.11 // indirect github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/magiconair/properties v1.8.5 // indirect github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect - github.com/onsi/ginkgo v1.11.0 - github.com/onsi/gomega v1.7.0 + github.com/onsi/ginkgo v1.14.0 + github.com/onsi/gomega v1.10.1 github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee github.com/packethost/packngo v0.13.0 github.com/pelletier/go-toml v1.9.0 // indirect @@ -43,19 +41,15 @@ require ( golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect - golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 // indirect google.golang.org/grpc v1.37.0 // indirect gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/api v0.21.0 - k8s.io/apimachinery v0.21.0 - k8s.io/client-go v0.21.0 - k8s.io/klog v1.0.0 - k8s.io/klog/v2 v2.8.0 - k8s.io/utils v0.0.0-20210305010621-2afb4311ab10 // indirect + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 + k8s.io/klog/v2 v2.9.0 sigs.k8s.io/kind v0.10.0 - sigs.k8s.io/structured-merge-diff/v4 v4.1.1 // indirect ) diff --git a/go.sum b/go.sum index 6134d7a4..832eaaa4 100644 --- a/go.sum +++ b/go.sum @@ -33,11 +33,11 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= @@ -143,8 +143,9 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= @@ -152,6 +153,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -174,15 +176,11 @@ github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -200,8 +198,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -229,6 +228,7 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -262,6 +262,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -317,7 +318,6 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/raft v1.3.1 h1:zDT8ke8y2aP4wf9zPTB2uSIeavJ3Hx/ceY4jxI2JxuY= github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= @@ -370,7 +370,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -440,6 +439,8 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -447,12 +448,16 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -577,7 +582,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -631,7 +635,6 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -706,6 +709,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -714,9 +718,9 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -755,14 +759,15 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -780,6 +785,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -794,13 +800,13 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -811,7 +817,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -819,8 +824,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -837,7 +842,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -980,7 +984,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -1013,26 +1016,23 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y= -k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA= -k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag= -k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210305010621-2afb4311ab10 h1:u5rPykqiCpL+LBfjRkXvnK71gOgIdmq3eHUEkPrbeTI= -k8s.io/utils v0.0.0-20210305010621-2afb4311ab10/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= @@ -1040,9 +1040,8 @@ sigs.k8s.io/kind v0.10.0 h1:Tm+QITIqdRd+efLOsxZHMAfLnr5K4e3/RH8MePspEXs= sigs.k8s.io/kind v0.10.0/go.mod h1:fb32zUw7ewC47bPwLnwhf47wd/vADtv3c38KP7sjIlo= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.1 h1:nYqY2A6oy37sKLYuSBXuQhbj4JVclzJK13BOIvJG5XU= -sigs.k8s.io/structured-merge-diff/v4 v4.1.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index f38d4c57..2e97913d 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -11,7 +11,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/kubevip" - leaderelection "github.com/kube-vip/kube-vip/pkg/leaderElection" "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/kube-vip/kube-vip/pkg/packet" @@ -24,6 +23,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" ) diff --git a/pkg/leaderElection/OWNERS b/pkg/leaderElection/OWNERS deleted file mode 100644 index 44d93f84..00000000 --- a/pkg/leaderElection/OWNERS +++ /dev/null @@ -1,14 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -approvers: -- mikedanese -- timothysc -reviewers: -- wojtek-t -- deads2k -- mikedanese -- gmarek -- eparis -- timothysc -- ingvagabund -- resouer diff --git a/pkg/leaderElection/healthzadaptor.go b/pkg/leaderElection/healthzadaptor.go deleted file mode 100644 index b9353729..00000000 --- a/pkg/leaderElection/healthzadaptor.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package leaderelection - -import ( - "net/http" - "sync" - "time" -) - -// HealthzAdaptor associates the /healthz endpoint with the LeaderElection object. -// It helps deal with the /healthz endpoint being set up prior to the LeaderElection. -// This contains the code needed to act as an adaptor between the leader -// election code the health check code. It allows us to provide health -// status about the leader election. Most specifically about if the leader -// has failed to renew without exiting the process. In that case we should -// report not healthy and rely on the kubelet to take down the process. -type HealthzAdaptor struct { - pointerLock sync.Mutex - le *LeaderElector - timeout time.Duration -} - -// Name returns the name of the health check we are implementing. -func (l *HealthzAdaptor) Name() string { - return "leaderElection" -} - -// Check is called by the healthz endpoint handler. -// It fails (returns an error) if we own the lease but had not been able to renew it. -func (l *HealthzAdaptor) Check(req *http.Request) error { - l.pointerLock.Lock() - defer l.pointerLock.Unlock() - if l.le == nil { - return nil - } - return l.le.Check(l.timeout) -} - -// SetLeaderElection ties a leader election object to a HealthzAdaptor -func (l *HealthzAdaptor) SetLeaderElection(le *LeaderElector) { - l.pointerLock.Lock() - defer l.pointerLock.Unlock() - l.le = le -} - -// NewLeaderHealthzAdaptor creates a basic healthz adaptor to monitor a leader election. -// timeout determines the time beyond the lease expiry to be allowed for timeout. -// checks within the timeout period after the lease expires will still return healthy. -func NewLeaderHealthzAdaptor(timeout time.Duration) *HealthzAdaptor { - result := &HealthzAdaptor{ - timeout: timeout, - } - return result -} diff --git a/pkg/leaderElection/healthzadaptor_test.go b/pkg/leaderElection/healthzadaptor_test.go deleted file mode 100644 index d92f1336..00000000 --- a/pkg/leaderElection/healthzadaptor_test.go +++ /dev/null @@ -1,177 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package leaderelection - -import ( - "context" - "fmt" - "testing" - "time" - - "net/http" - - "k8s.io/apimachinery/pkg/util/clock" - rl "k8s.io/client-go/tools/leaderelection/resourcelock" -) - -type fakeLock struct { - identity string -} - -// Get is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) Get(ctx context.Context) (ler *rl.LeaderElectionRecord, rawRecord []byte, err error) { - return nil, nil, nil -} - -// Create is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) Create(ctx context.Context, ler rl.LeaderElectionRecord) error { - return nil -} - -// Update is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) Update(ctx context.Context, ler rl.LeaderElectionRecord) error { - return nil -} - -// RecordEvent is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) RecordEvent(string) {} - -// Identity is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) Identity() string { - return fl.identity -} - -// Describe is a dummy to allow us to have a fakeLock for testing. -func (fl *fakeLock) Describe() string { - return "Dummy implementation of lock for testing" -} - -// TestLeaderElectionHealthChecker tests that the healthcheck for leader election handles its edge cases. -func TestLeaderElectionHealthChecker(t *testing.T) { - current := time.Now() - req := &http.Request{} - - tests := []struct { - description string - expected error - adaptorTimeout time.Duration - elector *LeaderElector - }{ - { - description: "call check before leader elector initialized", - expected: nil, - adaptorTimeout: time.Second * 20, - elector: nil, - }, - { - description: "call check when the lease is far expired", - expected: fmt.Errorf("failed election to renew leadership on lease %s", "foo"), - adaptorTimeout: time.Second * 20, - elector: &LeaderElector{ - config: LeaderElectionConfig{ - Lock: &fakeLock{identity: "healthTest"}, - LeaseDuration: time.Minute, - Name: "foo", - }, - observedRecord: rl.LeaderElectionRecord{ - HolderIdentity: "healthTest", - }, - observedTime: current, - clock: clock.NewFakeClock(current.Add(time.Hour)), - }, - }, - { - description: "call check when the lease is far expired but held by another server", - expected: nil, - adaptorTimeout: time.Second * 20, - elector: &LeaderElector{ - config: LeaderElectionConfig{ - Lock: &fakeLock{identity: "healthTest"}, - LeaseDuration: time.Minute, - Name: "foo", - }, - observedRecord: rl.LeaderElectionRecord{ - HolderIdentity: "otherServer", - }, - observedTime: current, - clock: clock.NewFakeClock(current.Add(time.Hour)), - }, - }, - { - description: "call check when the lease is not expired", - expected: nil, - adaptorTimeout: time.Second * 20, - elector: &LeaderElector{ - config: LeaderElectionConfig{ - Lock: &fakeLock{identity: "healthTest"}, - LeaseDuration: time.Minute, - Name: "foo", - }, - observedRecord: rl.LeaderElectionRecord{ - HolderIdentity: "healthTest", - }, - observedTime: current, - clock: clock.NewFakeClock(current), - }, - }, - { - description: "call check when the lease is expired but inside the timeout", - expected: nil, - adaptorTimeout: time.Second * 20, - elector: &LeaderElector{ - config: LeaderElectionConfig{ - Lock: &fakeLock{identity: "healthTest"}, - LeaseDuration: time.Minute, - Name: "foo", - }, - observedRecord: rl.LeaderElectionRecord{ - HolderIdentity: "healthTest", - }, - observedTime: current, - clock: clock.NewFakeClock(current.Add(time.Minute).Add(time.Second)), - }, - }, - } - - for _, test := range tests { - adaptor := NewLeaderHealthzAdaptor(test.adaptorTimeout) - if adaptor.le != nil { - t.Errorf("[%s] leaderChecker started with a LeaderElector %v", test.description, adaptor.le) - } - if test.elector != nil { - test.elector.config.WatchDog = adaptor - adaptor.SetLeaderElection(test.elector) - if adaptor.le == nil { - t.Errorf("[%s] adaptor failed to set the LeaderElector", test.description) - } - } - err := adaptor.Check(req) - if test.expected == nil { - if err == nil { - continue - } - t.Errorf("[%s] called check, expected no error but received \"%v\"", test.description, err) - } else { - if err == nil { - t.Errorf("[%s] called check and failed to received the expected error \"%v\"", test.description, test.expected) - } - if err.Error() != test.expected.Error() { - t.Errorf("[%s] called check, expected %v, received %v", test.description, test.expected, err) - } - } - } -} diff --git a/pkg/leaderElection/leaderelection.go b/pkg/leaderElection/leaderelection.go deleted file mode 100644 index 3755dade..00000000 --- a/pkg/leaderElection/leaderelection.go +++ /dev/null @@ -1,392 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package leaderelection implements leader election of a set of endpoints. -// It uses an annotation in the endpoints object to store the record of the -// election state. This implementation does not guarantee that only one -// client is acting as a leader (a.k.a. fencing). -// -// A client only acts on timestamps captured locally to infer the state of the -// leader election. The client does not consider timestamps in the leader -// election record to be accurate because these timestamps may not have been -// produced by a local clock. The implemention does not depend on their -// accuracy and only uses their change to indicate that another client has -// renewed the leader lease. Thus the implementation is tolerant to arbitrary -// clock skew, but is not tolerant to arbitrary clock skew rate. -// -// However the level of tolerance to skew rate can be configured by setting -// RenewDeadline and LeaseDuration appropriately. The tolerance expressed as a -// maximum tolerated ratio of time passed on the fastest node to time passed on -// the slowest node can be approximately achieved with a configuration that sets -// the same ratio of LeaseDuration to RenewDeadline. For example if a user wanted -// to tolerate some nodes progressing forward in time twice as fast as other nodes, -// the user could set LeaseDuration to 60 seconds and RenewDeadline to 30 seconds. -// -// While not required, some method of clock synchronization between nodes in the -// cluster is highly recommended. It's important to keep in mind when configuring -// this client that the tolerance to skew rate varies inversely to master -// availability. -// -// Larger clusters often have a more lenient SLA for API latency. This should be -// taken into account when configuring the client. The rate of leader transitions -// should be monitored and RetryPeriod and LeaseDuration should be increased -// until the rate is stable and acceptably low. It's important to keep in mind -// when configuring this client that the tolerance to API latency varies inversely -// to master availability. -// -// DISCLAIMER: this is an alpha API. This library will likely change significantly -// or even be removed entirely in subsequent releases. Depend on this API at -// your own risk. -package leaderelection - -import ( - "bytes" - "context" - "fmt" - "time" - - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - rl "k8s.io/client-go/tools/leaderelection/resourcelock" - - "k8s.io/klog" -) - -const ( - jitterFactor = 1.2 -) - -// NewLeaderElector creates a LeaderElector from a LeaderElectionConfig -func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) { - if lec.LeaseDuration <= lec.RenewDeadline { - return nil, fmt.Errorf("leaseDuration must be greater than renewDeadline") - } - if lec.RenewDeadline <= time.Duration(jitterFactor*float64(lec.RetryPeriod)) { - return nil, fmt.Errorf("renewDeadline must be greater than retryPeriod*JitterFactor") - } - if lec.LeaseDuration < 1 { - return nil, fmt.Errorf("leaseDuration must be greater than zero") - } - if lec.RenewDeadline < 1 { - return nil, fmt.Errorf("renewDeadline must be greater than zero") - } - if lec.RetryPeriod < 1 { - return nil, fmt.Errorf("retryPeriod must be greater than zero") - } - if lec.Callbacks.OnStartedLeading == nil { - return nil, fmt.Errorf("OnStartedLeading callback must not be nil") - } - if lec.Callbacks.OnStoppedLeading == nil { - return nil, fmt.Errorf("OnStoppedLeading callback must not be nil") - } - - if lec.Lock == nil { - return nil, fmt.Errorf("Lock must not be nil") - } - le := LeaderElector{ - config: lec, - clock: clock.RealClock{}, - metrics: globalMetricsFactory.newLeaderMetrics(), - } - le.metrics.leaderOff(le.config.Name) - return &le, nil -} - -// LeaderElectionConfig defines the configuration for the leaderElection -// nolint -type LeaderElectionConfig struct { - // Lock is the resource that will be used for locking - Lock rl.Interface - - // LeaseDuration is the duration that non-leader candidates will - // wait to force acquire leadership. This is measured against time of - // last observed ack. - // - // A client needs to wait a full LeaseDuration without observing a change to - // the record before it can attempt to take over. When all clients are - // shutdown and a new set of clients are started with different names against - // the same leader record, they must wait the full LeaseDuration before - // attempting to acquire the lease. Thus LeaseDuration should be as short as - // possible (within your tolerance for clock skew rate) to avoid a possible - // long waits in the scenario. - // - // Core clients default this value to 15 seconds. - LeaseDuration time.Duration - // RenewDeadline is the duration that the acting master will retry - // refreshing leadership before giving up. - // - // Core clients default this value to 10 seconds. - RenewDeadline time.Duration - // RetryPeriod is the duration the LeaderElector clients should wait - // between tries of actions. - // - // Core clients default this value to 2 seconds. - RetryPeriod time.Duration - - // Callbacks are callbacks that are triggered during certain lifecycle - // events of the LeaderElector - Callbacks LeaderCallbacks - - // WatchDog is the associated health checker - // WatchDog may be null if its not needed/configured. - WatchDog *HealthzAdaptor - - // ReleaseOnCancel should be set true if the lock should be released - // when the run context is cancelled. If you set this to true, you must - // ensure all code guarded by this lease has successfully completed - // prior to cancelling the context, or you may have two processes - // simultaneously acting on the critical path. - ReleaseOnCancel bool - - // Name is the name of the resource lock for debugging - Name string -} - -// LeaderCallbacks are callbacks that are triggered during certain -// lifecycle events of the LeaderElector. These are invoked asynchronously. -// -// possible future callbacks: -// * OnChallenge() -type LeaderCallbacks struct { - // OnStartedLeading is called when a LeaderElector client starts leading - OnStartedLeading func(context.Context) - // OnStoppedLeading is called when a LeaderElector client stops leading - OnStoppedLeading func() - // OnNewLeader is called when the client observes a leader that is - // not the previously observed leader. This includes the first observed - // leader when the client starts. - OnNewLeader func(identity string) -} - -// LeaderElector is a leader election client. -type LeaderElector struct { - config LeaderElectionConfig - // internal bookkeeping - observedRecord rl.LeaderElectionRecord - observedRawRecord []byte - observedTime time.Time - // used to implement OnNewLeader(), may lag slightly from the - // value observedRecord.HolderIdentity if the transition has - // not yet been reported. - reportedLeader string - - // clock is wrapper around time to allow for less flaky testing - clock clock.Clock - - metrics leaderMetricsAdapter - - // name is the name of the resource lock for debugging - // name string -} - -// Run starts the leader election loop -func (le *LeaderElector) Run(ctx context.Context) { - defer func() { - runtime.HandleCrash() - le.config.Callbacks.OnStoppedLeading() - }() - if !le.acquire(ctx) { - return // ctx signalled done - } - ctx, cancel := context.WithCancel(ctx) - defer cancel() - go le.config.Callbacks.OnStartedLeading(ctx) - le.renew(ctx) -} - -// RunOrDie starts a client with the provided config or panics if the config -// fails to validate. -func RunOrDie(ctx context.Context, lec LeaderElectionConfig) { - le, err := NewLeaderElector(lec) - if err != nil { - panic(err) - } - if lec.WatchDog != nil { - lec.WatchDog.SetLeaderElection(le) - } - le.Run(ctx) -} - -// GetLeader returns the identity of the last observed leader or returns the empty string if -// no leader has yet been observed. -func (le *LeaderElector) GetLeader() string { - return le.observedRecord.HolderIdentity -} - -// IsLeader returns true if the last observed leader was this client else returns false. -func (le *LeaderElector) IsLeader() bool { - return le.observedRecord.HolderIdentity == le.config.Lock.Identity() -} - -// acquire loops calling tryAcquireOrRenew and returns true immediately when tryAcquireOrRenew succeeds. -// Returns false if ctx signals done. -func (le *LeaderElector) acquire(ctx context.Context) bool { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - succeeded := false - desc := le.config.Lock.Describe() - klog.Infof("attempting to acquire leader lease %v...", desc) - wait.JitterUntil(func() { - succeeded = le.tryAcquireOrRenew(ctx) - le.maybeReportTransition() - if !succeeded { - klog.V(4).Infof("failed to acquire lease %v", desc) - return - } - le.config.Lock.RecordEvent("became leader") - le.metrics.leaderOn(le.config.Name) - klog.Infof("successfully acquired lease %v", desc) - cancel() - }, le.config.RetryPeriod, jitterFactor, true, ctx.Done()) - return succeeded -} - -// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails or ctx signals done. -func (le *LeaderElector) renew(ctx context.Context) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - wait.Until(func() { - timeoutCtx, timeoutCancel := context.WithTimeout(ctx, le.config.RenewDeadline) - defer timeoutCancel() - err := wait.PollImmediateUntil(le.config.RetryPeriod, func() (bool, error) { - return le.tryAcquireOrRenew(timeoutCtx), nil - }, timeoutCtx.Done()) - - le.maybeReportTransition() - desc := le.config.Lock.Describe() - if err == nil { - klog.V(5).Infof("successfully renewed lease %v", desc) - return - } - le.config.Lock.RecordEvent("stopped leading") - le.metrics.leaderOff(le.config.Name) - klog.Infof("failed to renew lease %v: %v", desc, err) - cancel() - }, le.config.RetryPeriod, ctx.Done()) - - // if we hold the lease, give it up - if le.config.ReleaseOnCancel { - le.release() - } -} - -// release attempts to release the leader lease if we have acquired it. -func (le *LeaderElector) release() bool { - if !le.IsLeader() { - return true - } - leaderElectionRecord := rl.LeaderElectionRecord{ - LeaseDurationSeconds: le.observedRecord.LeaseDurationSeconds, - LeaderTransitions: le.observedRecord.LeaderTransitions, - } - if err := le.config.Lock.Update(context.TODO(), leaderElectionRecord); err != nil { - klog.Errorf("Failed to release lock: %v", err) - return false - } - le.observedRecord = leaderElectionRecord - le.observedTime = le.clock.Now() - return true -} - -// tryAcquireOrRenew tries to acquire a leader lease if it is not already acquired, -// else it tries to renew the lease if it has already been acquired. Returns true -// on success else returns false. -func (le *LeaderElector) tryAcquireOrRenew(ctx context.Context) bool { - now := metav1.Now() - leaderElectionRecord := rl.LeaderElectionRecord{ - HolderIdentity: le.config.Lock.Identity(), - LeaseDurationSeconds: int(le.config.LeaseDuration / time.Second), - RenewTime: now, - AcquireTime: now, - } - - // 1. obtain or create the ElectionRecord - oldLeaderElectionRecord, oldLeaderElectionRawRecord, err := le.config.Lock.Get(ctx) - if err != nil { - if !errors.IsNotFound(err) { - klog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err) - return false - } - if err = le.config.Lock.Create(ctx, leaderElectionRecord); err != nil { - klog.Errorf("error initially creating leader election record: %v", err) - return false - } - le.observedRecord = leaderElectionRecord - le.observedTime = le.clock.Now() - return true - } - - // 2. Record obtained, check the Identity & Time - if !bytes.Equal(le.observedRawRecord, oldLeaderElectionRawRecord) { - le.observedRecord = *oldLeaderElectionRecord - le.observedRawRecord = oldLeaderElectionRawRecord - le.observedTime = le.clock.Now() - } - if len(oldLeaderElectionRecord.HolderIdentity) > 0 && - le.observedTime.Add(le.config.LeaseDuration).After(now.Time) && - !le.IsLeader() { - klog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity) - return false - } - - // 3. We're going to try to update. The leaderElectionRecord is set to it's default - // here. Let's correct it before updating. - if le.IsLeader() { - leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime - leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions - } else { - leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1 - } - - // update the lock itself - if err = le.config.Lock.Update(ctx, leaderElectionRecord); err != nil { - klog.Errorf("Failed to update lock: %v", err) - return false - } - - le.observedRecord = leaderElectionRecord - le.observedTime = le.clock.Now() - return true -} - -func (le *LeaderElector) maybeReportTransition() { - if le.observedRecord.HolderIdentity == le.reportedLeader { - return - } - le.reportedLeader = le.observedRecord.HolderIdentity - if le.config.Callbacks.OnNewLeader != nil { - go le.config.Callbacks.OnNewLeader(le.reportedLeader) - } -} - -// Check will determine if the current lease is expired by more than timeout. -func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error { - if !le.IsLeader() { - // Currently not concerned with the case that we are hot standby - return nil - } - // If we are more than timeout seconds after the lease duration that is past the timeout - // on the lease renew. Time to start reporting ourselves as unhealthy. We should have - // died but conditions like deadlock can prevent this. (See #70819) - if le.clock.Since(le.observedTime) > le.config.LeaseDuration+maxTolerableExpiredLease { - return fmt.Errorf("failed election to renew leadership on lease %s", le.config.Name) - } - - return nil -} diff --git a/pkg/leaderElection/leaderelection_test.go b/pkg/leaderElection/leaderelection_test.go deleted file mode 100644 index 8c22697a..00000000 --- a/pkg/leaderElection/leaderelection_test.go +++ /dev/null @@ -1,891 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package leaderelection - -import ( - "context" - "encoding/json" - "fmt" - "sync" - "testing" - "time" - - coordinationv1 "k8s.io/api/coordination/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/client-go/kubernetes/fake" - fakeclient "k8s.io/client-go/testing" - rl "k8s.io/client-go/tools/leaderelection/resourcelock" - "k8s.io/client-go/tools/record" -) - -func createLockObject(t *testing.T, objectType, namespace, name string, record *rl.LeaderElectionRecord) (obj runtime.Object) { - objectMeta := metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - } - if record != nil { - recordBytes, _ := json.Marshal(record) - objectMeta.Annotations = map[string]string{ - rl.LeaderElectionRecordAnnotationKey: string(recordBytes), - } - } - switch objectType { - case "endpoints": - obj = &corev1.Endpoints{ObjectMeta: objectMeta} - case "configmaps": - obj = &corev1.ConfigMap{ObjectMeta: objectMeta} - case "leases": - var spec coordinationv1.LeaseSpec - if record != nil { - spec = rl.LeaderElectionRecordToLeaseSpec(record) - } - obj = &coordinationv1.Lease{ObjectMeta: objectMeta, Spec: spec} - default: - t.Fatal("unexpected objType:" + objectType) - } - return -} - -// Will test leader election using endpoints as the resource -func TestTryAcquireOrRenewEndpoints(t *testing.T) { - testTryAcquireOrRenew(t, "endpoints") -} - -type Reactor struct { - verb string - objectType string - reaction fakeclient.ReactionFunc -} - -func testTryAcquireOrRenew(t *testing.T, objectType string) { - future := time.Now().Add(1000 * time.Hour) - past := time.Now().Add(-1000 * time.Hour) - - tests := []struct { - name string - observedRecord rl.LeaderElectionRecord - observedTime time.Time - reactors []Reactor - - expectSuccess bool - transitionLeader bool - outHolder string - }{ - { - name: "acquire from no object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - { - verb: "create", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - expectSuccess: true, - outHolder: "baz", - }, - { - name: "acquire from object without annotations", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), nil), nil - }, - }, - { - verb: "update", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from unled object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil - }, - }, - { - verb: "update", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from led, unacked object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "update", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedTime: past, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from empty led, acked object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: ""}), nil - }, - }, - { - verb: "update", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - observedTime: future, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "don't acquire from led, acked object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - }, - observedTime: future, - - expectSuccess: false, - outHolder: "bing", - }, - { - name: "renew already acquired object", - reactors: []Reactor{ - { - verb: "get", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - { - verb: "update", - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - observedTime: future, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "baz"}, - - expectSuccess: true, - outHolder: "baz", - }, - } - - for i := range tests { - test := &tests[i] - t.Run(test.name, func(t *testing.T) { - // OnNewLeader is called async so we have to wait for it. - var wg sync.WaitGroup - wg.Add(1) - var reportedLeader string - var lock rl.Interface - - objectMeta := metav1.ObjectMeta{Namespace: "foo", Name: "bar"} - resourceLockConfig := rl.ResourceLockConfig{ - Identity: "baz", - EventRecorder: &record.FakeRecorder{}, - } - c := &fake.Clientset{} - for _, reactor := range test.reactors { - c.AddReactor(reactor.verb, objectType, reactor.reaction) - } - c.AddReactor("*", "*", func(action fakeclient.Action) (bool, runtime.Object, error) { - t.Errorf("unreachable action. testclient called too many times: %+v", action) - return true, nil, fmt.Errorf("unreachable action") - }) - - switch objectType { - case "endpoints": - lock = &rl.EndpointsLock{ - EndpointsMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoreV1(), - } - case "configmaps": - lock = &rl.ConfigMapLock{ - ConfigMapMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoreV1(), - } - case "leases": - lock = &rl.LeaseLock{ - LeaseMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoordinationV1(), - } - } - - lec := LeaderElectionConfig{ - Lock: lock, - LeaseDuration: 10 * time.Second, - Callbacks: LeaderCallbacks{ - OnNewLeader: func(l string) { - defer wg.Done() - reportedLeader = l - }, - }, - } - observedRawRecord := GetRawRecordOrDie(t, objectType, test.observedRecord) - le := &LeaderElector{ - config: lec, - observedRecord: test.observedRecord, - observedRawRecord: observedRawRecord, - observedTime: test.observedTime, - clock: clock.RealClock{}, - } - if test.expectSuccess != le.tryAcquireOrRenew(context.Background()) { - t.Errorf("unexpected result of tryAcquireOrRenew: [succeeded=%v]", !test.expectSuccess) - } - - le.observedRecord.AcquireTime = metav1.Time{} - le.observedRecord.RenewTime = metav1.Time{} - if le.observedRecord.HolderIdentity != test.outHolder { - t.Errorf("expected holder:\n\t%+v\ngot:\n\t%+v", test.outHolder, le.observedRecord.HolderIdentity) - } - if len(test.reactors) != len(c.Actions()) { - t.Errorf("wrong number of api interactions") - } - if test.transitionLeader && le.observedRecord.LeaderTransitions != 1 { - t.Errorf("leader should have transitioned but did not") - } - if !test.transitionLeader && le.observedRecord.LeaderTransitions != 0 { - t.Errorf("leader should not have transitioned but did") - } - - le.maybeReportTransition() - wg.Wait() - if reportedLeader != test.outHolder { - t.Errorf("reported leader was not the new leader. expected %q, got %q", test.outHolder, reportedLeader) - } - }) - } -} - -// Will test leader election using configmap as the resource -func TestTryAcquireOrRenewConfigMaps(t *testing.T) { - testTryAcquireOrRenew(t, "configmaps") -} - -// Will test leader election using lease as the resource -func TestTryAcquireOrRenewLeases(t *testing.T) { - testTryAcquireOrRenew(t, "leases") -} - -func multiLockType(t *testing.T, objectType string) (primaryType, secondaryType string) { - switch objectType { - case rl.EndpointsLeasesResourceLock: - return rl.EndpointsResourceLock, rl.LeasesResourceLock - case rl.ConfigMapsLeasesResourceLock: - return rl.ConfigMapsResourceLock, rl.LeasesResourceLock - default: - t.Fatal("unexpected objType:" + objectType) - } - return -} - -func GetRawRecordOrDie(t *testing.T, objectType string, ler rl.LeaderElectionRecord) (ret []byte) { - var err error - switch objectType { - case "endpoints", "configmaps", "leases": - ret, err = json.Marshal(ler) - if err != nil { - t.Fatalf("lock %s get raw record %v failed: %v", objectType, ler, err) - } - case "endpointsleases", "configmapsleases": - recordBytes, err := json.Marshal(ler) - if err != nil { - t.Fatalf("lock %s get raw record %v failed: %v", objectType, ler, err) - } - ret = rl.ConcatRawRecord(recordBytes, recordBytes) - default: - t.Fatal("unexpected objType:" + objectType) - } - return -} - -func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) { - future := time.Now().Add(1000 * time.Hour) - past := time.Now().Add(-1000 * time.Hour) - primaryType, secondaryType := multiLockType(t, objectType) - tests := []struct { - name string - observedRecord rl.LeaderElectionRecord - observedRawRecord []byte - observedTime time.Time - reactors []Reactor - - expectSuccess bool - transitionLeader bool - outHolder string - }{ - { - name: "acquire from no object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - { - verb: "create", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - { - verb: "create", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - expectSuccess: true, - outHolder: "baz", - }, - { - name: "acquire from unled old object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - { - verb: "create", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from unled transition object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil - }, - }, - { - verb: "update", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - }, - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from led, unack old object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "create", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.CreateAction).GetObject(), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, primaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: past, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from led, unack transition object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "update", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: past, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "acquire from conflict led, ack transition object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: future, - - expectSuccess: false, - outHolder: rl.UnknownLeader, - }, - { - name: "acquire from led, unack unknown object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil - }, - }, - { - verb: "update", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}, - observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), - observedTime: past, - - expectSuccess: true, - transitionLeader: true, - outHolder: "baz", - }, - { - name: "don't acquire from led, ack old object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName()) - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, primaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: future, - - expectSuccess: false, - outHolder: "bing", - }, - { - name: "don't acquire from led, acked new object, observe new record", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, secondaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: future, - - expectSuccess: false, - outHolder: rl.UnknownLeader, - }, - { - name: "don't acquire from led, acked new object, observe transition record", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"}, - observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}), - observedTime: future, - - expectSuccess: false, - outHolder: "bing", - }, - { - name: "renew already required object", - reactors: []Reactor{ - { - verb: "get", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - { - verb: "update", - objectType: primaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - { - verb: "get", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil - }, - }, - { - verb: "update", - objectType: secondaryType, - reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) { - return true, action.(fakeclient.UpdateAction).GetObject(), nil - }, - }, - }, - observedRecord: rl.LeaderElectionRecord{HolderIdentity: "baz"}, - observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "baz"}), - observedTime: future, - - expectSuccess: true, - outHolder: "baz", - }, - } - - for i := range tests { - test := &tests[i] - t.Run(test.name, func(t *testing.T) { - // OnNewLeader is called async so we have to wait for it. - var wg sync.WaitGroup - wg.Add(1) - var reportedLeader string - var lock rl.Interface - - objectMeta := metav1.ObjectMeta{Namespace: "foo", Name: "bar"} - resourceLockConfig := rl.ResourceLockConfig{ - Identity: "baz", - EventRecorder: &record.FakeRecorder{}, - } - c := &fake.Clientset{} - for _, reactor := range test.reactors { - c.AddReactor(reactor.verb, reactor.objectType, reactor.reaction) - } - c.AddReactor("*", "*", func(action fakeclient.Action) (bool, runtime.Object, error) { - t.Errorf("unreachable action. testclient called too many times: %+v", action) - return true, nil, fmt.Errorf("unreachable action") - }) - - switch objectType { - case rl.EndpointsLeasesResourceLock: - lock = &rl.MultiLock{ - Primary: &rl.EndpointsLock{ - EndpointsMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoreV1(), - }, - Secondary: &rl.LeaseLock{ - LeaseMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoordinationV1(), - }, - } - case rl.ConfigMapsLeasesResourceLock: - lock = &rl.MultiLock{ - Primary: &rl.ConfigMapLock{ - ConfigMapMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoreV1(), - }, - Secondary: &rl.LeaseLock{ - LeaseMeta: objectMeta, - LockConfig: resourceLockConfig, - Client: c.CoordinationV1(), - }, - } - } - - lec := LeaderElectionConfig{ - Lock: lock, - LeaseDuration: 10 * time.Second, - Callbacks: LeaderCallbacks{ - OnNewLeader: func(l string) { - defer wg.Done() - reportedLeader = l - }, - }, - } - le := &LeaderElector{ - config: lec, - observedRecord: test.observedRecord, - observedRawRecord: test.observedRawRecord, - observedTime: test.observedTime, - clock: clock.RealClock{}, - } - if test.expectSuccess != le.tryAcquireOrRenew(context.Background()) { - t.Errorf("unexpected result of tryAcquireOrRenew: [succeeded=%v]", !test.expectSuccess) - } - - le.observedRecord.AcquireTime = metav1.Time{} - le.observedRecord.RenewTime = metav1.Time{} - if le.observedRecord.HolderIdentity != test.outHolder { - t.Errorf("expected holder:\n\t%+v\ngot:\n\t%+v", test.outHolder, le.observedRecord.HolderIdentity) - } - if len(test.reactors) != len(c.Actions()) { - t.Errorf("wrong number of api interactions") - } - if test.transitionLeader && le.observedRecord.LeaderTransitions != 1 { - t.Errorf("leader should have transitioned but did not") - } - if !test.transitionLeader && le.observedRecord.LeaderTransitions != 0 { - t.Errorf("leader should not have transitioned but did") - } - - le.maybeReportTransition() - wg.Wait() - if reportedLeader != test.outHolder { - t.Errorf("reported leader was not the new leader. expected %q, got %q", test.outHolder, reportedLeader) - } - }) - } -} - -// Will test leader election using endpointsleases as the resource -func TestTryAcquireOrRenewEndpointsLeases(t *testing.T) { - testTryAcquireOrRenewMultiLock(t, "endpointsleases") -} - -// Will test leader election using configmapsleases as the resource -func TestTryAcquireOrRenewConfigMapsLeases(t *testing.T) { - testTryAcquireOrRenewMultiLock(t, "configmapsleases") -} diff --git a/pkg/leaderElection/metrics.go b/pkg/leaderElection/metrics.go deleted file mode 100644 index 20c0311c..00000000 --- a/pkg/leaderElection/metrics.go +++ /dev/null @@ -1,110 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package leaderelection - -import ( - "sync" -) - -// This file provides abstractions for setting the provider (e.g., prometheus) -// of metrics. - -type leaderMetricsAdapter interface { - leaderOn(name string) - leaderOff(name string) -} - -// SwitchMetric represents a single numerical value that can arbitrarily go up -// and down. -type SwitchMetric interface { - On(name string) - Off(name string) -} - -type noopMetric struct{} - -func (noopMetric) On(name string) {} -func (noopMetric) Off(name string) {} - -// defaultLeaderMetrics expects the caller to lock before setting any metrics. -type defaultLeaderMetrics struct { - // leader's value indicates if the current process is the owner of name lease - leader SwitchMetric -} - -func (m *defaultLeaderMetrics) leaderOn(name string) { - if m == nil { - return - } - m.leader.On(name) -} - -func (m *defaultLeaderMetrics) leaderOff(name string) { - if m == nil { - return - } - m.leader.Off(name) -} - -type noMetrics struct{} - -func (noMetrics) leaderOn(name string) {} -func (noMetrics) leaderOff(name string) {} - -// MetricsProvider generates various metrics used by the leader election. -type MetricsProvider interface { - NewLeaderMetric() SwitchMetric -} - -type noopMetricsProvider struct{} - -// NewLeaderMetric returns a new SwitchMetric. -func (nmp noopMetricsProvider) NewLeaderMetric() SwitchMetric { - return noopMetric{} -} - -var globalMetricsFactory = leaderMetricsFactory{ - metricsProvider: noopMetricsProvider{}, -} - -type leaderMetricsFactory struct { - metricsProvider MetricsProvider - - onlyOnce sync.Once -} - -func (f *leaderMetricsFactory) setProvider(mp MetricsProvider) { - f.onlyOnce.Do(func() { - f.metricsProvider = mp - }) -} - -func (f *leaderMetricsFactory) newLeaderMetrics() leaderMetricsAdapter { - mp := f.metricsProvider - if mp == (noopMetricsProvider{}) { - return noMetrics{} - } - return &defaultLeaderMetrics{ - leader: mp.NewLeaderMetric(), - } -} - -// SetProvider sets the metrics provider for all subsequently created work -// queues. Only the first call has an effect. -func SetProvider(metricsProvider MetricsProvider) { - globalMetricsFactory.setProvider(metricsProvider) -} From 7a759e41f76b9fbeb7090d2cc4d31d02b7ef7005 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 22 Oct 2021 09:28:41 +0100 Subject: [PATCH 160/542] Replace IPVS as the API server LoadBalancer --- cmd/kube-vip-start.go | 17 -- cmd/kube-vip.go | 12 +- go.mod | 1 + go.sum | 16 ++ main.go | 4 +- pkg/cluster/cluster.go | 12 ++ pkg/cluster/clusterLeader.go | 160 +++++++++++----- pkg/cluster/clusterRaft.go | 293 ----------------------------- pkg/cluster/singleNode.go | 42 +---- pkg/kubevip/config_envvar.go | 14 -- pkg/kubevip/config_generator.go | 93 +-------- pkg/kubevip/config_types.go | 3 + pkg/loadbalancer/ipvs.go | 115 +++++++++++ pkg/loadbalancer/lb_connections.go | 129 ------------- pkg/loadbalancer/lb_http.go | 127 ------------- pkg/loadbalancer/lb_tcp.go | 61 ------ pkg/loadbalancer/lb_udp.go | 103 ---------- pkg/loadbalancer/manager.go | 78 -------- pkg/loadbalancer/port_forward.go | 101 ++++++++++ pkg/manager/manager_arp.go | 1 + pkg/manager/watcher.go | 93 +++++++++ 21 files changed, 465 insertions(+), 1010 deletions(-) delete mode 100644 pkg/cluster/clusterRaft.go create mode 100644 pkg/loadbalancer/ipvs.go delete mode 100644 pkg/loadbalancer/lb_connections.go delete mode 100644 pkg/loadbalancer/lb_http.go delete mode 100644 pkg/loadbalancer/lb_tcp.go delete mode 100644 pkg/loadbalancer/lb_udp.go delete mode 100644 pkg/loadbalancer/manager.go create mode 100644 pkg/loadbalancer/port_forward.go diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index f1173a92..d00a9d34 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -117,21 +114,7 @@ var kubeVipStart = &cobra.Command{ if err != nil { log.Fatalf("%v", err) } - } else { - - // // Start a multi-node (raft) cluster, this doesn't block so will wait on signal - err = newCluster.StartRaftCluster(&startConfig) - if err != nil { - log.Fatalf("%v", err) - } - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt) - - <-signalChan - - newCluster.Stop() } - } }, diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index fdae32aa..46fea08c 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -73,7 +73,9 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") - kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "listen port for the VIP") + kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "Port for the VIP") + kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6444, "loadbalancer port for the VIP") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") @@ -96,14 +98,6 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProjectID, "metalProjectID", "", "The ID of project already created within Equinix Metal") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") - // Load Balancer flags - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "lbEnable", false, "Enable a load-balancer on the VIP") - kubeVipCmd.PersistentFlags().BoolVar(&initLoadBalancer.BindToVip, "lbBindToVip", true, "Bind example load balancer to VIP") - kubeVipCmd.PersistentFlags().StringVar(&initLoadBalancer.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)") - kubeVipCmd.PersistentFlags().StringVar(&initLoadBalancer.Name, "lbName", "Kubeadm Load Balancer", "The name of a load balancer instance") - kubeVipCmd.PersistentFlags().IntVar(&initLoadBalancer.Port, "lbPort", 6443, "Port that load balancer will expose on") - kubeVipCmd.PersistentFlags().IntVar(&initLoadBalancer.BackendPort, "lbBackEndPort", 6444, "A port that all backends may be using (optional)") - // BGP flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableBGP, "bgp", false, "This will enable BGP support within kube-vip") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") diff --git a/go.mod b/go.mod index a4e36267..91424b2b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( github.com/armon/go-metrics v0.3.8 // indirect + github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 // indirect github.com/davecgh/go-spew v1.1.1 github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 diff --git a/go.sum b/go.sum index 832eaaa4..929f408a 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 h1:uI/fFG5+s/On/vH4eAaeYTKSliqmlnzzWL85zeI4zOM= +github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3/go.mod h1:4zyIiC//fAlPlMC9LYUmHPn8Ak/aj41FKFXuWoK8CvU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -335,12 +337,16 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= +github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= +github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -398,12 +404,17 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= +github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= +github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= +github.com/mdlayher/netlink v1.2.1 h1:Q5xDCtos3xv72vqzjuAh5Ns/IUlFfoy+948yBNSktTc= +github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= @@ -718,6 +729,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -797,7 +810,10 @@ golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/main.go b/main.go index 3bd6f4dc..9e20cb03 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main -import "github.com/kube-vip/kube-vip/cmd" +import ( + "github.com/kube-vip/kube-vip/cmd" +) // Version is populated from the Makefile and is tied to the release TAG var Version string diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 1d524a03..dd083093 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -3,6 +3,7 @@ package cluster import ( "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" + log "github.com/sirupsen/logrus" ) const leaderLogcount = 5 @@ -50,3 +51,14 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { } return network, nil } + +// Stop - Will stop the Cluster and release VIP if needed +func (cluster *Cluster) Stop() { + // Close the stop chanel, which will shut down the VIP (if needed) + close(cluster.stop) + + // Wait until the completed channel is closed, signallign all shutdown tasks completed + <-cluster.completed + + log.Info("Stopped") +} diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 2e97913d..0a71c6a9 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -9,6 +9,7 @@ import ( "syscall" "time" + "github.com/davecgh/go-spew/spew" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/loadbalancer" @@ -19,12 +20,18 @@ import ( "github.com/packethost/packngo" 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" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" + watchtools "k8s.io/client-go/tools/watch" ) const plunderLock = "plndr-cp-lock" @@ -32,6 +39,8 @@ const plunderLock = "plndr-cp-lock" // Manager degines the manager of the load-balancing services type Manager struct { KubernetesClient *kubernetes.Clientset + // This channel is used to signal a shutdown + SignalChan chan os.Signal } // NewManager will create a new managing object @@ -143,10 +152,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe log.Errorf("could not delete virtualIP: %v", err) } - // Managers for Vip load balancers and none-vip loadbalancers - nonVipLB := loadbalancer.LBManager{} - VipLB := loadbalancer.LBManager{} - // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { if bgpServer != nil { @@ -192,21 +197,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } } - if c.EnableLoadBalancer { - - // Iterate through all Configurations - if len(c.LoadBalancers) != 0 { - for x := range c.LoadBalancers { - // If the load balancer doesn't bind to the VIP - if !c.LoadBalancers[x].BindToVip { - err = nonVipLB.Add("", &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - } - } - } - } - } // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -223,7 +213,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { // we're notified when we start - log.Info("This node is starting with leadership of the cluster") + log.Info("This node is starting the leadership of the cluster") // setup ddns first // for first time, need to wait until IP is allocated from DHCP if cluster.Network.IsDDNS() { @@ -268,27 +258,22 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } if c.EnableLoadBalancer { - // Once we have the VIP running, start the load balancer(s) that bind to the VIP - for x := range c.LoadBalancers { - if c.LoadBalancers[x].BindToVip { - err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - - // Stop all load balancers associated with the VIP - err = VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - } - } + log.Infof("Starting IPVS LoadBalancer") + portForwarder := loadbalancer.NewServer(c.VIP, c.LoadBalancerPort) + // TODO + lb, err := loadbalancer.NewIPVSLB("1.2.3.4", 6444) + if err != nil { + log.Error(err) } + + go sm.LabelsWatcher(lb) + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-signalChan + log.Info("Stopping IPVS LoadBalancer") + portForwarder.Stop() + }() } if c.EnableARP { @@ -363,12 +348,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe } } - // Stop all load balancers associated with the VIP - err = VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - err = cluster.Network.DeleteIP() if err != nil { log.Warnf("%v", err) @@ -386,6 +365,97 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe return nil } +// present +// LabelsWatcher will watch for labels created on nodes +func (sm *Manager) LabelsWatcher(lb *loadbalancer.IPVSLoadBalancer) 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") + + labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"node-role.kubernetes.io/control-plane": ""}} + listOptions := metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + } + + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.KubernetesClient.CoreV1().Nodes().Watch(context.Background(), listOptions) + }, + }) + if err != nil { + return fmt.Errorf("error creating label watcher: %s", err.Error()) + } + + go func() { + <-sm.SignalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context + rw.Stop() + }() + + ch := rw.ResultChan() + //defer rw.Stop() + + for event := range ch { + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + } + //Find the node IP address (this isn't foolproof) + for x := range node.Status.Addresses { + + if node.Status.Addresses[x].Type == v1.NodeInternalIP { + err = lb.AddBackend(node.Status.Addresses[x].Address) + if err != nil { + log.Errorf("Add IPVS backend [%v]", err) + } + } + } + case watch.Deleted: + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + } + + //Find the node IP address (this isn't foolproof) + for x := range node.Status.Addresses { + + if node.Status.Addresses[x].Type == v1.NodeInternalIP { + err = lb.AddBackend(node.Status.Addresses[x].Address) + if err != nil { + log.Errorf("Del IPVS backend [%v]", err) + } + } + } + + log.Infof("Node [%s] has been deleted", node.Name) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Error("Error attempting to watch Kubernetes Nodes") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + + log.Infoln("Exiting Annotations watcher") + return nil + +} + // TODO - refactor an active machine func(), this will replace the singleNode code and have a single code block // func (cluster *Cluster) active(c *kubevip.Config) error { diff --git a/pkg/cluster/clusterRaft.go b/pkg/cluster/clusterRaft.go deleted file mode 100644 index 755968af..00000000 --- a/pkg/cluster/clusterRaft.go +++ /dev/null @@ -1,293 +0,0 @@ -package cluster - -import ( - "fmt" - "net" - "time" - - "github.com/hashicorp/raft" - "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/loadbalancer" - "github.com/kube-vip/kube-vip/pkg/vip" - log "github.com/sirupsen/logrus" -) - -// StartRaftCluster - Begins a running instance of the Raft cluster -func (cluster *Cluster) StartRaftCluster(c *kubevip.Config) error { - - // Create local configuration address - localAddress := fmt.Sprintf("%s:%d", c.LocalPeer.Address, c.LocalPeer.Port) - - // Begin the Raft configuration - config := raft.DefaultConfig() - config.LocalID = raft.ServerID(c.LocalPeer.ID) - logger := log.StandardLogger().Writer() - config.LogOutput = logger - - // Initialize communication - address, err := net.ResolveTCPAddr("tcp", localAddress) - if err != nil { - return err - } - - // Create transport - transport, err := raft.NewTCPTransport(localAddress, address, 3, 10*time.Second, logger) - if err != nil { - return err - } - - // Create Raft structures - snapshots := raft.NewInmemSnapshotStore() - logStore := raft.NewInmemStore() - stableStore := raft.NewInmemStore() - - // Cluster configuration - configuration := raft.Configuration{} - - // Add Local Peer - configuration.Servers = append(configuration.Servers, raft.Server{ - ID: raft.ServerID(c.LocalPeer.ID), - Address: raft.ServerAddress(fmt.Sprintf("%s:%d", c.LocalPeer.Address, c.LocalPeer.Port))}) - - // If we want to start a node as leader then we will not add any remote peers, this will leave this as a cluster of one - // The remotePeers will add themselves to the cluster as they're added - if !c.StartAsLeader { - for x := range c.RemotePeers { - // Make sure that we don't add in this server twice - if c.LocalPeer.Address != c.RemotePeers[x].Address { - - // Build the address from the peer configuration - peerAddress := fmt.Sprintf("%s:%d", c.RemotePeers[x].Address, c.RemotePeers[x].Port) - - // Set this peer into the raft configuration - configuration.Servers = append(configuration.Servers, raft.Server{ - ID: raft.ServerID(c.RemotePeers[x].ID), - Address: raft.ServerAddress(peerAddress)}) - } - } - log.Info("This node will attempt to start as Follower") - } else { - log.Info("This node will attempt to start as Leader") - } - - // Bootstrap cluster - if err := raft.BootstrapCluster(config, logStore, stableStore, snapshots, transport, configuration); err != nil { - return err - } - - // Create RAFT instance - raftServer, err := raft.NewRaft(config, cluster.stateMachine, logStore, stableStore, snapshots, transport) - if err != nil { - return err - } - - cluster.stop = make(chan bool, 1) - cluster.completed = make(chan bool, 1) - ticker := time.NewTicker(time.Second) - isLeader := c.StartAsLeader - - // (attempt to) Remove the virtual IP, incase it already exists - err = cluster.Network.DeleteIP() - if err != nil { - log.Errorf("error deleting virtual IP: %v", err) - } - - // leader log broadcast - this counter is used to stop flooding STDOUT with leader log entries - var leaderbroadcast int - // Managers for Vip load balancers and none-vip loadbalancers - nonVipLB := loadbalancer.LBManager{} - VipLB := loadbalancer.LBManager{} - - // Iterate through all Configurations - for x := range c.LoadBalancers { - // If the load balancer doesn't bind to the VIP - if !c.LoadBalancers[x].BindToVip { - err = nonVipLB.Add("", &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - } - } - } - - // On a cold start the node will sleep for 5 seconds to ensure that leader elections are complete - log.Infoln("This instance will wait approximately 5 seconds, from cold start to ensure cluster elections are complete") - time.Sleep(time.Second * 5) - - go func() { - for { - // Broadcast the current leader on this node if it's the correct time (every leaderLogcount * time.Second) - if leaderbroadcast == leaderLogcount { - log.Infof("The Node [%s] is leading", raftServer.Leader()) - // Reset the timer - leaderbroadcast = 0 - - // ensure that if this node is the leader, it is set as the leader - if localAddress == string(raftServer.Leader()) { - // Re-broadcast arp to ensure network stays up to date - if c.EnableARP { - // Gratuitous ARP, will broadcast to new MAC <-> IP - err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } - if !isLeader { - log.Infoln("This node is leading, but isnt the leader (correcting)") - isLeader = true - } - } else { - // (attempt to) Remove the virtual IP, incase it already exists to keep nodes clean - err := cluster.Network.DeleteIP() - if err != nil { - log.Errorf("could not delete virtualIP: %v", err) - } - isLeader = false - } - - } - leaderbroadcast++ - - select { - case leader := <-raftServer.LeaderCh(): - log.Infoln("New Election event") - if leader { - isLeader = true - - log.Info("This node is assuming leadership of the cluster") - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - - // Once we have the VIP running, start the load balancer(s) that bind to the VIP - - for x := range c.LoadBalancers { - - if c.LoadBalancers[x].BindToVip { - err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - log.Errorf("Dropping Leadership to another node in the cluster") - raftServer.LeadershipTransfer() - - // Stop all load balancers associated with the VIP - err = VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - } - } - } - - if c.EnableARP { - // Gratuitous ARP, will broadcast to new MAC <-> IP - err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } - } else { - isLeader = false - - log.Info("This node is becoming a follower within the cluster") - - // Stop all load balancers associated with the VIP - err = VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - } - - case <-ticker.C: - - if isLeader { - - result, err := cluster.Network.IsSet() - if err != nil { - log.WithFields(log.Fields{"error": err, "ip": cluster.Network.IP(), "interface": cluster.Network.Interface()}).Error("Could not check ip") - } - - if !result { - log.Error("This node is leader and is adopting the virtual IP") - - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - // Once we have the VIP running, start the load balancer(s) that bind to the VIP - - for x := range c.LoadBalancers { - - if c.LoadBalancers[x].BindToVip { - err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - } - } - } - if c.EnableARP { - // Gratuitous ARP, will broadcast to new MAC <-> IP - err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } - } - } - - case <-cluster.stop: - log.Info("[RAFT] Stopping this node") - log.Info("[LOADBALANCER] Stopping load balancers") - - // Stop all load balancers associated with the VIP - err = VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - // Stop all load balancers associated with the Host - err = nonVipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - if isLeader { - log.Info("[VIP] Releasing the Virtual IP") - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - } - - close(cluster.completed) - - return - } - } - }() - - log.Info("Started") - - return nil -} - -// Stop - Will stop the Cluster and release VIP if needed -func (cluster *Cluster) Stop() { - // Close the stop chanel, which will shut down the VIP (if needed) - close(cluster.stop) - - // Wait until the completed channel is closed, signallign all shutdown tasks completed - <-cluster.completed - - log.Info("Stopped") -} diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 88393b94..209db95c 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -9,7 +9,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -25,22 +24,6 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) - // Managers for Vip load balancers and none-vip loadbalancers - nonVipLB := loadbalancer.LBManager{} - VipLB := loadbalancer.LBManager{} - - // Iterate through all Configurations - for x := range c.LoadBalancers { - // If the load balancer doesn't bind to the VIP - if !c.LoadBalancers[x].BindToVip { - err := nonVipLB.Add("", &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - } - - } - } - if !disableVIP { err := cluster.Network.DeleteIP() if err != nil { @@ -52,16 +35,6 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro log.Warnf("%v", err) } - // Once we have the VIP running, start the load balancer(s) that bind to the VIP - for x := range c.LoadBalancers { - - if c.LoadBalancers[x].BindToVip { - err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) - if err != nil { - log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - } - } - } } if c.EnableARP { @@ -77,24 +50,11 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro for { select { case <-cluster.stop: - log.Info("[LOADBALANCER] Stopping load balancers") - - // Stop all load balancers associated with the VIP - err := VipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } - - // Stop all load balancers associated with the Host - err = nonVipLB.StopAll() - if err != nil { - log.Warnf("%v", err) - } if !disableVIP { log.Info("[VIP] Releasing the Virtual IP") - err = cluster.Network.DeleteIP() + err := cluster.Network.DeleteIP() if err != nil { log.Warnf("%v", err) } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 848f9692..9fd9a7b8 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -118,23 +118,9 @@ const ( //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" - //lbBindToVip defines if the load-balancer should bind ONLY to the virtual IP - lbBindToVip = "lb_bindtovip" - - //lbName defines the name of load-balancer - lbName = "lb_name" - - //lbType defines the type of load-balancer - lbType = "lb_type" - //lbPort defines the port of load-balancer lbPort = "lb_port" - //lbBackendPort defines a port that ALL backends are using - lbBackendPort = "lb_backendport" - - //lbBackends defines the backends of load-balancer - lbBackends = "lb_backends" //vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 9a0988e1..9ffb0580 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -365,87 +365,12 @@ func ParseEnvironment(c *Config) error { } c.EnableLoadBalancer = b // Load Balancer configuration - return parseEnvironmentLoadBalancer(c) + // return parseEnvironmentLoadBalancer(c) } return nil } -func parseEnvironmentLoadBalancer(c *Config) error { - // Check if an existing load-balancer configuration already exists - if len(c.LoadBalancers) == 0 { - c.LoadBalancers = append(c.LoadBalancers, LoadBalancer{}) - } - - // Find LoadBalancer Port - env := os.Getenv(lbPort) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.LoadBalancers[0].Port = int(i) - } - - // Find Type of LoadBalancer - env = os.Getenv(lbType) - if env != "" { - c.LoadBalancers[0].Type = env - } - - // Find Type of LoadBalancer Name - env = os.Getenv(lbName) - if env != "" { - c.LoadBalancers[0].Name = env - } - - // Find If LB should bind to Vip - env = os.Getenv(lbBindToVip) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.LoadBalancers[0].BindToVip = b - } - - // Find global backendport - env = os.Getenv(lbBackendPort) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.LoadBalancers[0].BackendPort = int(i) - } - - // Parse backends - env = os.Getenv(lbBackends) - if env != "" { - // TODO - perhaps make this optional? - // Remove existing backends - c.LoadBalancers[0].Backends = []BackEnd{} - - // Parse the remote peers (comma separated) - s := strings.Split(env, ",") - if len(s) == 0 { - return fmt.Errorf("The Backends List [%s] is unable to be parsed, should be in comma separated format
:", env) - } - for x := range s { - // Parse the each remote peer string in format
: - - be, err := ParseBackendConfig(s[x]) - if err != nil { - return err - } - - c.LoadBalancers[0].Backends = append(c.LoadBalancers[0].Backends, *be) - - } - } - return nil -} - // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" @@ -710,22 +635,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: lbEnable, Value: strconv.FormatBool(c.EnableLoadBalancer), }, - { - Name: lbBackendPort, - Value: fmt.Sprintf("%d", c.LoadBalancers[0].Port), - }, - { - Name: lbName, - Value: c.LoadBalancers[0].Name, - }, - { - Name: lbType, - Value: c.LoadBalancers[0].Type, - }, - { - Name: lbBindToVip, - Value: strconv.FormatBool(c.LoadBalancers[0].BindToVip), - }, } newEnvironment = append(newEnvironment, lb...) diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 20959660..0cc63b0a 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -69,6 +69,9 @@ type Config struct { // EnableLoadBalancer, provides the flexibility to make the load-balancer optional EnableLoadBalancer bool `yaml:"enableLoadBalancer"` + // Listen port for the IPVS Service + LoadBalancerPort int `yaml:"lbPort"` + // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go new file mode 100644 index 00000000..80e42d8f --- /dev/null +++ b/pkg/loadbalancer/ipvs.go @@ -0,0 +1,115 @@ +package loadbalancer + +import ( + "fmt" + "net" + "os" + + "github.com/cloudflare/ipvs" + log "github.com/sirupsen/logrus" +) + +/* +IPVS Architecture - for those that are interested + +There are going to be a large number of end users that are using a VIP that exists within the same subnet +as the back end servers. This unfortunately will result in "packet" confusion with the destingation and +source becoming messed up by the IPVS NAT. + +The solution is to perform two things ! + +First: +Set up kube-vip TCP port forwarder from the VIP:PORT to the IPVS:PORT + +Second: +Start up a node watcher and a IPVS load balancer, the node balancer is responsible for adding/removing +the nodes from the IPVS load-balancer. + +*/ + +const ( + ROUNDROBIN = "rr" +) + +type IPVSLoadBalancer struct { + client ipvs.Client + loadBalancerService ipvs.Service + Port int +} + +func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { + + // Create IPVS client + c, err := ipvs.New() + if err != nil { + return nil, fmt.Errorf("error creating IPVS client: %v", err) + } + + // Generate out API Server LoadBalancer instance + svc := ipvs.Service{ + Family: ipvs.INET, + Protocol: ipvs.TCP, + Port: uint16(port), + Address: ipvs.NewIP(net.ParseIP(address)), + Scheduler: ROUNDROBIN, + } + err = c.CreateService(svc) + // If we've an error it could be that the IPVS lb instance has been left from a previous leadership + if err == os.ErrExist { + log.Warnf("load balancer for API server already exists, attempting to remove and re-create") + + err = c.CreateService(svc) + if err != nil { + return nil, fmt.Errorf("error re-creating IPVS service: %v", err) + } + } else if err != nil { + return nil, fmt.Errorf("error creating IPVS service: %v", err) + } + + lb := &IPVSLoadBalancer{ + Port: port, + client: c, + loadBalancerService: svc, + } + // Return our created load-balancer + return lb, nil +} + +func (lb *IPVSLoadBalancer) RemoveIPVSLB() error { + err := lb.client.RemoveService(lb.loadBalancerService) + if err != nil { + return fmt.Errorf("error removing existing IPVS service: %v", err) + } + return nil + +} + +func (lb *IPVSLoadBalancer) AddBackend(address string) error { + dst := ipvs.Destination{ + Address: ipvs.NewIP(net.ParseIP(address)), + Port: 6443, + Family: ipvs.INET, + Weight: 1, + } + err := lb.client.CreateDestination(lb.loadBalancerService, dst) + // TODO: we either parse the IPVS configuration to see if a backend exists + // or if it already exists we just ignore this and continue ons + if err != nil && err != os.ErrExist { + return fmt.Errorf("error creating backend: %v", err) + } + return nil +} + +func (lb *IPVSLoadBalancer) RemoveBackend(address string) error { + dst := ipvs.Destination{ + Address: ipvs.NewIP(net.ParseIP(address)), + Port: 6443, + Family: ipvs.INET, + Weight: 1, + } + err := lb.client.RemoveDestination(lb.loadBalancerService, dst) + if err != nil { + return fmt.Errorf("error removing backend: %v", err) + } + return nil +} diff --git a/pkg/loadbalancer/lb_connections.go b/pkg/loadbalancer/lb_connections.go deleted file mode 100644 index 4a7ed227..00000000 --- a/pkg/loadbalancer/lb_connections.go +++ /dev/null @@ -1,129 +0,0 @@ -package loadbalancer - -import ( - "io" - "net" - "sync" - "time" - - "github.com/kube-vip/kube-vip/pkg/kubevip" - log "github.com/sirupsen/logrus" -) - -// 1. Load balancer port is exposed -// 2. We listen -// 3. On connection we connect to an endpoint -// [loop] -// 4. We read from the load balancer port -// 5. We write traffic to the endpoint -// 6. We read response from endpoint -// 7. We write response to load balancer -// [goto loop] - -func persistentConnection(frontendConnection net.Conn, lb *kubevip.LoadBalancer) { - - var endpoint net.Conn - defer frontendConnection.Close() - // Makes sure we close the connections to the endpoint when we've completed - - // Set a timeout for connecting to an endpoint - dialer := net.Dialer{Timeout: time.Millisecond * 500} - for { - - // Connect to Endpoint - ep, err := lb.ReturnEndpointAddr() - if err != nil { - return - } - - // We now dial to an endpoint with a timeout of half a second - // TODO - make this adjustable - endpoint, err = dialer.Dial("tcp", ep) - if err != nil { - log.Debugf("%v", err) - log.Warnf("[%s]---X [FAILED] X-->[%s]", frontendConnection.RemoteAddr(), ep) - } else { - log.Debugf("[%s]---->[ACCEPT]---->[%s]", frontendConnection.RemoteAddr(), ep) - defer endpoint.Close() - break - } - } - - wg := &sync.WaitGroup{} - wg.Add(1) - - // Begin copying incoming (frontend -> to an endpoint) - go func() { - bytes, err := io.Copy(endpoint, frontendConnection) - log.Debugf("[%d] bytes of data sent to endpoint", bytes) - if err != nil { - log.Warnf("Error sending data to endpoint [%s] [%v]", endpoint.RemoteAddr(), err) - } - wg.Done() - }() - // go func() { - // Begin copying receiving (endpoint -> back to frontend) - bytes, err := io.Copy(frontendConnection, endpoint) - log.Debugf("[%d] bytes of data sent to client", bytes) - if err != nil { - log.Warnf("Error sending data to frontend [%s] [%s]", frontendConnection.RemoteAddr(), err) - } - // wg.Done() - // endpoint.Close() - // }() - wg.Wait() -} - -func persistentUDPConnection(frontendConnection net.Conn, lb *kubevip.LoadBalancer) { - - var endpoint net.Conn - defer frontendConnection.Close() - // Makes sure we close the connections to the endpoint when we've completed - - // Set a timeout for connecting to an endpoint - dialer := net.Dialer{Timeout: time.Millisecond * 500} - for { - - // Connect to Endpoint - ep, err := lb.ReturnEndpointAddr() - if err != nil { - return - } - - // We now dial to an endpoint with a timeout of half a second - // TODO - make this adjustable - endpoint, err = dialer.Dial("udp", ep) - if err != nil { - log.Debugf("%v", err) - log.Warnf("[%s]---X [FAILED] X-->[%s]", frontendConnection.RemoteAddr(), ep) - } else { - log.Debugf("[%s]---->[ACCEPT]---->[%s]", frontendConnection.RemoteAddr(), ep) - defer endpoint.Close() - break - } - } - - wg := &sync.WaitGroup{} - wg.Add(1) - - // Begin copying incoming (frontend -> to an endpoint) - go func() { - bytes, err := io.Copy(endpoint, frontendConnection) - log.Debugf("[%d] bytes of data sent to endpoint", bytes) - if err != nil { - log.Warnf("Error sending data to endpoint [%s] [%v]", endpoint.RemoteAddr(), err) - } - wg.Done() - }() - // go func() { - // Begin copying receiving (endpoint -> back to frontend) - bytes, err := io.Copy(frontendConnection, endpoint) - log.Debugf("[%d] bytes of data sent to client", bytes) - if err != nil { - log.Warnf("Error sending data to frontend [%s] [%s]", frontendConnection.RemoteAddr(), err) - } - // wg.Done() - // endpoint.Close() - // }() - wg.Wait() -} diff --git a/pkg/loadbalancer/lb_http.go b/pkg/loadbalancer/lb_http.go deleted file mode 100644 index 57477206..00000000 --- a/pkg/loadbalancer/lb_http.go +++ /dev/null @@ -1,127 +0,0 @@ -package loadbalancer - -import ( - "context" - "fmt" - "net/http" - "net/http/httputil" - "net/url" - "time" - - "github.com/kube-vip/kube-vip/pkg/kubevip" - log "github.com/sirupsen/logrus" -) - -func (lb *LBInstance) startHTTP(bindAddress string) error { - log.Infof("Starting TCP Load Balancer for service [%s]", lb.instance.Name) - - // Validate the back end URLS - err := kubevip.ValidateBackEndURLS(&lb.instance.Backends) - if err != nil { - return err - } - - frontEnd := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port) - - handler := func(w http.ResponseWriter, req *http.Request) { - // parse the url - url, _ := url.Parse(lb.instance.ReturnEndpointURL().String()) - - // create the reverse proxy - proxy := httputil.NewSingleHostReverseProxy(url) - - // Update the headers to allow for SSL redirection - req.URL.Host = url.Host - req.URL.Scheme = url.Scheme - req.Header.Set("X-Forwarded-Host", req.Host) - req.Host = url.Host - - //Print out the response (if debug logging) - if log.GetLevel() == log.DebugLevel { - fmt.Printf("Host:\t%s\n", req.Host) - fmt.Printf("Request:\t%s\n", req.Method) - fmt.Printf("URI:\t%s\n", req.RequestURI) - - for key, value := range req.Header { - fmt.Println("Header:", key, "Value:", value) - } - } - - // Note that ServeHttp is non blocking and uses a go routine under the hood - proxy.ServeHTTP(w, req) - } - - mux := http.NewServeMux() - mux.HandleFunc("/", handler) - log.Infof("Starting server listening [%s]", frontEnd) - - server := &http.Server{Addr: frontEnd, Handler: mux} - - go func() { - if err := server.ListenAndServe(); err != nil { - log.Fatalf("error starting http server: %v", err) - } - }() - - // If the stop channel is closed then the server will be gracefully shut down - <-lb.stop - log.Infof("Stopping the load balancer [%s] bound to [%s] with 5sec timeout", lb.instance.Name, frontEnd) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if err := server.Shutdown(ctx); err != nil { - return err - } - close(lb.stopped) - return nil -} - -//StartHTTP - begins the HTTP load balancer -func StartHTTP(lb *kubevip.LoadBalancer, address string) error { - log.Infof("Starting TCP Load Balancer for service [%s]", lb.Name) - - // Validate the back end URLS - err := kubevip.ValidateBackEndURLS(&lb.Backends) - if err != nil { - return err - } - - frontEnd := fmt.Sprintf("%s:%d", address, lb.Port) - - handler := func(w http.ResponseWriter, req *http.Request) { - // parse the url - url, _ := url.Parse(lb.ReturnEndpointURL().String()) - - // create the reverse proxy - proxy := httputil.NewSingleHostReverseProxy(url) - - // Update the headers to allow for SSL redirection - req.URL.Host = url.Host - req.URL.Scheme = url.Scheme - req.Header.Set("X-Forwarded-Host", req.Host) - req.Host = url.Host - - //Print out the response (if debug logging) - if log.GetLevel() == log.DebugLevel { - fmt.Printf("Host:\t%s\n", req.Host) - fmt.Printf("Request:\t%s\n", req.Method) - fmt.Printf("URI:\t%s\n", req.RequestURI) - - for key, value := range req.Header { - fmt.Println("Header:", key, "Value:", value) - } - } - - // Note that ServeHttp is non blocking and uses a go routine under the hood - proxy.ServeHTTP(w, req) - } - - mux := http.NewServeMux() - mux.HandleFunc("/", handler) - log.Infof("Starting server listening [%s]", frontEnd) - if err := http.ListenAndServe(frontEnd, mux); err != nil { - log.Fatalf("error serving: %v", err) - } - // Should never get here - return nil -} diff --git a/pkg/loadbalancer/lb_tcp.go b/pkg/loadbalancer/lb_tcp.go deleted file mode 100644 index a2b6c6e8..00000000 --- a/pkg/loadbalancer/lb_tcp.go +++ /dev/null @@ -1,61 +0,0 @@ -package loadbalancer - -import ( - "fmt" - "io" - "net" - "time" - - log "github.com/sirupsen/logrus" -) - -// StartTCP a TCP load balancer server instane -func (lb *LBInstance) startTCP(bindAddress string) error { - fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port) - log.Infof("Starting TCP Load Balancer for service [%s]", fullAddress) - - laddr, err := net.ResolveTCPAddr("tcp", fullAddress) - if nil != err { - log.Errorln(err) - } - l, err := net.ListenTCP("tcp", laddr) - if nil != err { - return fmt.Errorf("Unable to bind [%s]", err.Error()) - } - go func() { - for { - select { - - case <-lb.stop: - log.Debugln("Closing listener") - - // We've closed the stop channel - err = l.Close() - if err != nil { - return - } - // Close the stopped channel as the listener has been stopped - close(lb.stopped) - default: - - err = l.SetDeadline(time.Now().Add(200 * time.Millisecond)) - if err != nil { - log.Errorf("Error setting TCP deadline [%v]", err) - } - fd, err := l.Accept() - if err != nil { - // Check it it's an accept timeout - if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { - continue - } else if err != io.EOF { - log.Errorf("TCP Accept error [%s]", err) - } - } - go persistentConnection(fd, lb.instance) - } - } - }() - log.Infof("Load Balancer [%s] started", lb.instance.Name) - - return nil -} diff --git a/pkg/loadbalancer/lb_udp.go b/pkg/loadbalancer/lb_udp.go deleted file mode 100644 index 378df896..00000000 --- a/pkg/loadbalancer/lb_udp.go +++ /dev/null @@ -1,103 +0,0 @@ -package loadbalancer - -import ( - "fmt" - "net" - - log "github.com/sirupsen/logrus" -) - -// StartTCP a TCP load balancer server instane -func (lb *LBInstance) startUDP(bindAddress string) error { - fullAddress := fmt.Sprintf("%s:%d", bindAddress, lb.instance.Port) - log.Infof("Starting UDP Load Balancer for service [%s]", fullAddress) - - laddr, err := net.ResolveUDPAddr("udp", fullAddress) - if nil != err { - log.Errorln(err) - } - l, err := net.ListenUDP("udp", laddr) - if nil != err { - return fmt.Errorf("Unable to bind [%s]", err.Error()) - } - //stopListener := make(chan bool) - - go func() { - for { - select { - - case <-lb.stop: - log.Debugln("Closing listener") - - // We've closed the stop channel - err = l.Close() - if err != nil { - return - } - // Close the stopped channel as the listener has been stopped - close(lb.stopped) - default: - - // err = l.SetDeadline(time.Now().Add(200 * time.Millisecond)) - // if err != nil { - // log.Errorf("Error setting TCP deadline", err) - // } - // fd, err := l.Accept() - // if err != nil { - // // Check it it's an accept timeout - // if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { - // continue - // } else if err != io.EOF { - // log.Errorf("TCP Accept error [%s]", err) - // } - // } - go persistentUDPConnection(l, lb.instance) - } - } - }() - log.Infof("Load Balancer [%s] started", lb.instance.Name) - - // go func() { - // <-lb.stop - // log.Debugln("Closing listener") - - // // We've closed the stop channel - // err = l.Close() - // if err != nil { - // return - // } - // // Close the stopped channel as the listener has been stopped - // close(stopListener) - // }() - - // // Create a listener per CPU - // // TODO - make this customisable? - - // //for i := 0; i < runtime.NumCPU(); i++ { - // go persistentUDPConnection(l, lb.instance) - // //} - - //<-stopListener // hang until an error - - log.Infof("Load Balancer [%s] started", lb.instance.Name) - - return nil -} - -// func listen(connection *net.UDPConn, quit chan bool) { -// buffer := make([]byte, 1024) -// n, remoteAddr, err := 0, new(net.UDPAddr), error(nil) -// for err == nil { - -// //TODO - - -// n, remoteAddr, err = connection.ReadFromUDP(buffer) -// // you might copy out the contents of the packet here, to -// // `var r myapp.Request`, say, and `go handleRequest(r)` (or -// // send it down a channel) to free up the listening -// // goroutine. you do *need* to copy then, though, -// // because you've only made one buffer per listen(). -// fmt.Println("from", remoteAddr, "-", buffer[:n]) -// } -// fmt.Println("listener failed - ", err) -// } diff --git a/pkg/loadbalancer/manager.go b/pkg/loadbalancer/manager.go deleted file mode 100644 index 550d4359..00000000 --- a/pkg/loadbalancer/manager.go +++ /dev/null @@ -1,78 +0,0 @@ -package loadbalancer - -import ( - "fmt" - "strings" - - "github.com/kube-vip/kube-vip/pkg/kubevip" - log "github.com/sirupsen/logrus" -) - -//LBInstance - manages the state of load balancer instances -type LBInstance struct { - stop chan bool // Asks LB to stop - stopped chan bool // LB is stopped - instance *kubevip.LoadBalancer // pointer to a LB instance - // mux sync.Mutex -} - -//LBManager - will manage a number of load blancer instances -type LBManager struct { - loadBalancer []LBInstance -} - -//Add - handles the building of the load balancers -func (lm *LBManager) Add(bindAddress string, lb *kubevip.LoadBalancer) error { - newLB := LBInstance{ - stop: make(chan bool, 1), - stopped: make(chan bool, 1), - instance: lb, - } - - switch strings.ToLower(lb.Type) { - case "tcp": - err := newLB.startTCP(bindAddress) - if err != nil { - return err - } - case "udp": - err := newLB.startUDP(bindAddress) - if err != nil { - return err - } - case "http": - err := newLB.startHTTP(bindAddress) - if err != nil { - return err - } - default: - return fmt.Errorf("Unknown Load Balancer type [%s]", lb.Type) - } - - lm.loadBalancer = append(lm.loadBalancer, newLB) - return nil -} - -//StopAll - handles the building of the load balancers -func (lm *LBManager) StopAll() error { - log.Debugf("Stopping [%d] loadbalancer instances", len(lm.loadBalancer)) - for x := range lm.loadBalancer { - err := lm.loadBalancer[x].Stop() - if err != nil { - return err - } - } - // Reset the loadbalancer entries - lm.loadBalancer = nil - return nil -} - -//Stop - handles the building of the load balancers -func (l *LBInstance) Stop() error { - - close(l.stop) - - <-l.stopped - log.Infof("Load Balancer instance [%s] has stopped", l.instance.Name) - return nil -} diff --git a/pkg/loadbalancer/port_forward.go b/pkg/loadbalancer/port_forward.go new file mode 100644 index 00000000..17653c4b --- /dev/null +++ b/pkg/loadbalancer/port_forward.go @@ -0,0 +1,101 @@ +package loadbalancer + +import ( + "fmt" + "io" + "net" + "os" + "sync" + "time" +) + +type Server struct { + listener *net.TCPListener + quit chan bool + exited chan bool +} + +func NewServer(listenVIP string, listenPort int) *Server { + addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", listenVIP, listenPort)) + // TODO: return nil, error and decide how to handle it in the calling function + if err != nil { + fmt.Println("Failed to resolve address", err.Error()) + os.Exit(1) + } + + // TODO: return nil, error and decide how to handle it in the calling function + listener, err := net.ListenTCP("tcp", addr) + if err != nil { + fmt.Println("Failed to create listener", err.Error()) + os.Exit(1) + } + + // TODO: do not use this syntax, add the field names + srv := &Server{ + listener, + make(chan bool), + make(chan bool), + } + // TODO: no need to export Serve as it is only called internally + go srv.Serve() + return srv +} + +func (srv *Server) Serve() { + var handlers sync.WaitGroup + for { + select { + case <-srv.quit: + fmt.Println("Shutting down...") + srv.listener.Close() + handlers.Wait() + close(srv.exited) + return + default: + srv.listener.SetDeadline(time.Now().Add(1e9)) + conn, err := srv.listener.Accept() + if err != nil { + if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { + continue + } + fmt.Println("Failed to accept connection:", err.Error()) + } + handlers.Add(1) + go func() { + // FIXME: handle returned error here (just log it) + // FIXME: determine ID (why?) + srv.handleConnection(conn, 0) + handlers.Done() + }() + } + } +} + +func (srv *Server) handleConnection(conn net.Conn, id int) error { + fmt.Println("new client") + + proxy, err := net.Dial("tcp", fmt.Sprintf("1.2.3.4:6444")) + if err != nil { + return err + } + + fmt.Println("proxy connected") + go copyIO(conn, proxy) + go copyIO(proxy, conn) + return nil +} + +func copyIO(src, dest net.Conn) { + defer src.Close() + defer dest.Close() + io.Copy(src, dest) + +} +func (srv *Server) Stop() { + fmt.Println("Stop requested") + // XXX: You cannot use the same channel in two directions. + // The order of operations on the channel is undefined. + close(srv.quit) + <-srv.exited + fmt.Println("Stopped successfully") +} diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 68cc730b..7eb36ff8 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -66,6 +66,7 @@ func (sm *Manager) startARP() error { clusterManager := &cluster.Manager{ KubernetesClient: sm.clientSet, + SignalChan: sm.signalChan, } go func() { diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 665f979d..8f3a6c16 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -10,6 +10,7 @@ import ( "sync" "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -292,3 +293,95 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er return bgpConfig, bgpPeer, nil } + +// This file handles the watching of node annotations for configuration, it will exit once the annotations are +// present +// LabelsWatcher will watch for labels created on nodes +func (sm *Manager) LabelsWatcher(lb *loadbalancer.IPVSLoadBalancer) 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") + + labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"node-role.kubernetes.io/control-plane": ""}} + listOptions := metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + } + + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Nodes().Watch(context.Background(), listOptions) + }, + }) + if err != nil { + return fmt.Errorf("error creating label watcher: %s", err.Error()) + } + + go func() { + <-sm.signalChan + log.Info("Received termination, signaling shutdown") + // Cancel the context + rw.Stop() + }() + + ch := rw.ResultChan() + //defer rw.Stop() + + for event := range ch { + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + } + //Find the node IP address (this isn't foolproof) + for x := range node.Status.Addresses { + + if node.Status.Addresses[x].Type == v1.NodeInternalIP { + err = lb.AddBackend(node.Status.Addresses[x].Address) + if err != nil { + log.Errorf("Add IPVS backend [%v]", err) + } + } + } + case watch.Deleted: + node, ok := event.Object.(*v1.Node) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + } + + //Find the node IP address (this isn't foolproof) + for x := range node.Status.Addresses { + + if node.Status.Addresses[x].Type == v1.NodeInternalIP { + err = lb.AddBackend(node.Status.Addresses[x].Address) + if err != nil { + log.Errorf("Del IPVS backend [%v]", err) + } + } + } + + log.Infof("Node [%s] has been deleted", node.Name) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Error("Error attempting to watch Kubernetes Nodes") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + + log.Infoln("Exiting Annotations watcher") + return nil + +} From 6c759fcd7450aa371650669e0c40e6a01aa71311 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 22 Oct 2021 15:53:59 +0100 Subject: [PATCH 161/542] Lint fixes --- go.mod | 2 +- go.sum | 1 + pkg/cluster/cluster.go | 9 +++---- pkg/cluster/clusterLeader.go | 11 +++++---- pkg/kubevip/config_envvar.go | 1 - pkg/kubevip/config_generator.go | 4 ++++ pkg/loadbalancer/port_forward.go | 40 +++++++++++++++++++++----------- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 91424b2b..d02c1187 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/armon/go-metrics v0.3.8 // indirect - github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 // indirect + github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 github.com/davecgh/go-spew v1.1.1 github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 diff --git a/go.sum b/go.sum index 929f408a..5159dc4c 100644 --- a/go.sum +++ b/go.sum @@ -346,6 +346,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= +github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943 h1:REP5ibuxEIcBcG837UAei093pVqmOPm/tw0TbUd18YI= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index dd083093..e42b89a0 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -6,14 +6,11 @@ import ( log "github.com/sirupsen/logrus" ) -const leaderLogcount = 5 - // Cluster - The Cluster object manages the state of the cluster for a particular node type Cluster struct { - stateMachine FSM - stop chan bool - completed chan bool - Network vip.Network + stop chan bool + completed chan bool + Network vip.Network } // InitCluster - Will attempt to initialise all of the required settings for the cluster diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 0a71c6a9..6bbbc50f 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -134,10 +134,6 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // Add Notification for SIGTERM (sent from Kubernetes) signal.Notify(signalChan, syscall.SIGTERM) - // Add Notification for SIGKILL (sent from Kubernetes) - //nolint - signal.Notify(signalChan, syscall.SIGKILL) - go func() { <-signalChan log.Info("Received termination, signaling shutdown") @@ -267,7 +263,12 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe log.Error(err) } - go sm.LabelsWatcher(lb) + go func() { + err = sm.LabelsWatcher(lb) + if err != nil { + log.Errorf("Error watching node labels [%s]", err) + } + }() // Shutdown function that will wait on this signal, unless we call it ourselves go func() { <-signalChan diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 9fd9a7b8..fb3e919f 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -121,7 +121,6 @@ const ( //lbPort defines the port of load-balancer lbPort = "lb_port" - //vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 9ffb0580..2aff92c8 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -635,6 +635,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: lbEnable, Value: strconv.FormatBool(c.EnableLoadBalancer), }, + { + Name: lbPort, + Value: fmt.Sprintf("%d", c.LoadBalancerPort), + }, } newEnvironment = append(newEnvironment, lb...) diff --git a/pkg/loadbalancer/port_forward.go b/pkg/loadbalancer/port_forward.go index 17653c4b..cc0c9626 100644 --- a/pkg/loadbalancer/port_forward.go +++ b/pkg/loadbalancer/port_forward.go @@ -7,12 +7,15 @@ import ( "os" "sync" "time" + + log "github.com/sirupsen/logrus" ) type Server struct { - listener *net.TCPListener - quit chan bool - exited chan bool + listener *net.TCPListener + listenPort int + quit chan bool + exited chan bool } func NewServer(listenVIP string, listenPort int) *Server { @@ -32,9 +35,10 @@ func NewServer(listenVIP string, listenPort int) *Server { // TODO: do not use this syntax, add the field names srv := &Server{ - listener, - make(chan bool), - make(chan bool), + listener: listener, + listenPort: listenPort, + quit: make(chan bool), + exited: make(chan bool), } // TODO: no need to export Serve as it is only called internally go srv.Serve() @@ -52,7 +56,10 @@ func (srv *Server) Serve() { close(srv.exited) return default: - srv.listener.SetDeadline(time.Now().Add(1e9)) + err := srv.listener.SetDeadline(time.Now().Add(1e9)) + if err != nil { + log.Errorf("Error configuring listner [%v]", err) + } conn, err := srv.listener.Accept() if err != nil { if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { @@ -62,19 +69,21 @@ func (srv *Server) Serve() { } handlers.Add(1) go func() { - // FIXME: handle returned error here (just log it) - // FIXME: determine ID (why?) - srv.handleConnection(conn, 0) + + err = srv.handleConnection(conn) + if err != nil { + log.Errorf("Error handling connection [%v]", err) + } handlers.Done() }() } } } -func (srv *Server) handleConnection(conn net.Conn, id int) error { +func (srv *Server) handleConnection(conn net.Conn) error { fmt.Println("new client") - proxy, err := net.Dial("tcp", fmt.Sprintf("1.2.3.4:6444")) + proxy, err := net.Dial("tcp", fmt.Sprintf("1.2.3.4:%d", srv.listenPort)) if err != nil { return err } @@ -88,9 +97,12 @@ func (srv *Server) handleConnection(conn net.Conn, id int) error { func copyIO(src, dest net.Conn) { defer src.Close() defer dest.Close() - io.Copy(src, dest) - + _, err := io.Copy(src, dest) + if err != nil { + log.Errorf("Error copying data [%v]", err) + } } + func (srv *Server) Stop() { fmt.Println("Stop requested") // XXX: You cannot use the same channel in two directions. From cf122a323990fe82e919172a6c7f94f79167b8f2 Mon Sep 17 00:00:00 2001 From: Mike Nabhan <13139061+mikenabhan@users.noreply.github.com> Date: Sun, 24 Oct 2021 18:03:38 -0600 Subject: [PATCH 162/542] Fix spelling in documentation --- docs/usage/k3s/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 04b8ad04..62cd61a8 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -46,7 +46,7 @@ To generate the manifest we have two options! We can generate the manifest from curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml ``` -## Step 3.2 Genereate from container image +## Step 3.2 Generate from container image ### containerd `alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` From 9b65c1e63c743229e39d17f10d2de5bed04d4e6e Mon Sep 17 00:00:00 2001 From: Steve Sloka Date: Fri, 22 Oct 2021 14:13:08 -0400 Subject: [PATCH 163/542] Refactor the Kubernetes client generation into a single place inside a new k8s package. Signed-off-by: Steve Sloka --- .gitignore | 1 + Makefile | 2 +- cmd/kube-vip-kubeadm.go | 11 +----- pkg/cluster/clusterLeader.go | 38 ++++++------------ pkg/k8s/client.go | 38 ++++++++++++++++++ pkg/manager/manager.go | 74 +++++++++++++++++------------------ pkg/service/manager.go | 42 +++----------------- testing/e2e/e2e_suite_test.go | 3 ++ testing/e2e/e2e_test.go | 3 ++ 9 files changed, 99 insertions(+), 113 deletions(-) create mode 100644 .gitignore create mode 100644 pkg/k8s/client.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..258fffdc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +./idea/ \ No newline at end of file diff --git a/Makefile b/Makefile index 0cab2b98..bacb3933 100644 --- a/Makefile +++ b/Makefile @@ -104,4 +104,4 @@ manifests: @-rm ./kube-vip e2e-tests: - E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -v -p testing/e2e + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -tags=e2e -v -p testing/e2e diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index d618a283..d3e7bf7b 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -6,13 +6,12 @@ import ( "net" "os" + "github.com/kube-vip/kube-vip/pkg/k8s" "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" ) // kubeadm adds two subcommands for managing a vip during a kubeadm init/join @@ -95,13 +94,7 @@ var kubeKubeadmJoin = &cobra.Command{ // We will use kubeconfig in order to find all the master nodes // use the current context in kubeconfig - config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) - if err != nil { - log.Fatal(err.Error()) - } - - // create the clientset - clientset, err := kubernetes.NewForConfig(config) + clientset, err := k8s.NewClientset(kubeConfigPath, false, "") if err != nil { log.Fatal(err.Error()) } diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 2e97913d..eb9cdce0 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -10,6 +10,7 @@ import ( "time" "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/k8s" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/kube-vip/kube-vip/pkg/packet" @@ -21,8 +22,6 @@ import ( log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" ) @@ -36,27 +35,12 @@ type Manager struct { // NewManager will create a new managing object func NewManager(path string, inCluster bool, port int) (*Manager, error) { - var clientset *kubernetes.Clientset - if inCluster { - // This will attempt to load the configuration when running within a POD - cfg, err := rest.InClusterConfig() - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) - } - clientset, err = kubernetes.NewForConfig(cfg) + var hostname string - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) - } - // use the current context in kubeconfig - } else { - if path == "" { - path = filepath.Join(os.Getenv("HOME"), ".kube", "config") - } - config, err := clientcmd.BuildConfigFromFlags("", path) - if err != nil { - panic(err.Error()) - } + // If the path passed is empty and not running in the cluster, + // attempt to look for a kubeconfig in the default HOME dir. + if len(path) == 0 && !inCluster { + path = filepath.Join(os.Getenv("HOME"), ".kube", "config") // We modify the config so that we can always speak to the correct host id, err := os.Hostname() @@ -64,12 +48,12 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { return nil, err } - config.Host = fmt.Sprintf("%s:%v", id, port) - clientset, err = kubernetes.NewForConfig(config) + hostname = fmt.Sprintf("%s:%v", id, port) + } - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) - } + clientset, err := k8s.NewClientset(path, inCluster, hostname) + if err != nil { + return nil, fmt.Errorf("error creating a new k8s clientset: %v", err) } return &Manager{ diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go new file mode 100644 index 00000000..9be3848f --- /dev/null +++ b/pkg/k8s/client.go @@ -0,0 +1,38 @@ +package k8s + +import ( + "fmt" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +// NewClientset takes an optional configPath and creates a new clientset. +// If the configPath is not specified, and inCluster is true, then an +// InClusterConfig is used. +// Also takes a hostname which allow for overriding the config's hostname +// before generating a client. +func NewClientset(configPath string, inCluster bool, hostname string) (*kubernetes.Clientset, error) { + config, err := restConfig(configPath, inCluster) + if err != nil { + panic(err.Error()) + } + + if len(hostname) > 0 { + config.Host = hostname + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) + } + return clientset, nil +} + +func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { + if kubeconfig != "" && !inCluster { + return clientcmd.BuildConfigFromFlags("", kubeconfig) + } + return rest.InClusterConfig() +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 19a2018d..02831c42 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -9,17 +9,17 @@ import ( "strings" "syscall" - "github.com/kamhlos/upnp" - "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" + "github.com/kube-vip/kube-vip/pkg/k8s" + "github.com/kamhlos/upnp" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" + "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" ) const plunderLock = "plndr-svcs-lock" @@ -76,40 +76,36 @@ type Instance struct { // New will create a new managing object func New(configMap string, config *kubevip.Config) (*Manager, error) { - var clientset *kubernetes.Clientset - var configPath string + var clientset *kubernetes.Clientset var cfg *rest.Config var err error - configPath = "/etc/kubernetes/admin.conf" - if fileExists(configPath) { - cfg, err = clientcmd.BuildConfigFromFlags("", configPath) + adminConfigPath := "/etc/kubernetes/admin.conf" + homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") + + switch { + case fileExists(adminConfigPath): + clientset, err = k8s.NewClientset(adminConfigPath, false, "") if err != nil { - return nil, err + return nil, fmt.Errorf("could not create k8s clientset from external file: %q: %v", adminConfigPath, err) } - log.Debugf("Using external Kubernetes configuration from file [%s]", configPath) - } else { - // Second check in home directory for kube config - configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config") - if fileExists(configPath) { - log.Debugf("Using external Kubernetes configuration from home file [%s]", configPath) - cfg, err = clientcmd.BuildConfigFromFlags("", configPath) - if err != nil { - return nil, err - } - } else { - cfg, err = rest.InClusterConfig() - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) - } - log.Debugf("Using the internal Kubernetes token") + log.Debugf("Using external Kubernetes configuration from file [%s]", adminConfigPath) + case fileExists(homeConfigPath): + clientset, err = k8s.NewClientset(homeConfigPath, false, "") + if err != nil { + return nil, fmt.Errorf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) + } + log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + default: + clientset, err = k8s.NewClientset("", true, "") + if err != nil { + return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err) } + log.Debug("Using external Kubernetes configuration from incluster config.") } - clientset, err = kubernetes.NewForConfig(cfg) - - // If this is a control pane host it will likely have started as a static pod or wont have the + // If this is a control pane host it will likely have started as a static pod or won't have the // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. if config.EnableControlPane { @@ -186,14 +182,6 @@ func returnNameSpace() (string, error) { return "", fmt.Errorf("Unable to find Namespace") } -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} - func (sm *Manager) parseAnnotations() error { if sm.config.Annotations == "" { log.Debugf("No Node annotations to parse") @@ -206,3 +194,11 @@ func (sm *Manager) parseAnnotations() error { } return nil } + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 3082a5f9..69a448bd 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -4,30 +4,23 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" "strings" "github.com/kamhlos/upnp" - "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" + "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" ) const plunderLock = "plunder-lock" -// OutSideCluster allows the controller to be started using a local kubeConfig for testing -var OutSideCluster bool - var signalChan chan os.Signal -// Manager degines the manager of the load-balancing services +// Manager defines the manager of the load-balancing services type Manager struct { clientSet *kubernetes.Clientset configMap string @@ -75,32 +68,7 @@ type Instance struct { } // NewManager will create a new managing object -func NewManager(configMap string, config *kubevip.Config) (*Manager, error) { - var clientset *kubernetes.Clientset - if !OutSideCluster { - // This will attempt to load the configuration when running within a POD - cfg, err := rest.InClusterConfig() - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client config: %s", err.Error()) - } - clientset, err = kubernetes.NewForConfig(cfg) - - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) - } - // use the current context in kubeconfig - } else { - config, err := clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config")) - if err != nil { - panic(err.Error()) - } - clientset, err = kubernetes.NewForConfig(config) - - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) - } - } - +func NewManager(configMap string, config *kubevip.Config, clientset *kubernetes.Clientset) (*Manager, error) { return &Manager{ clientSet: clientset, configMap: configMap, diff --git a/testing/e2e/e2e_suite_test.go b/testing/e2e/e2e_suite_test.go index 0efc2189..6ac6be60 100644 --- a/testing/e2e/e2e_suite_test.go +++ b/testing/e2e/e2e_suite_test.go @@ -1,3 +1,6 @@ +//go:build e2e +// +build e2e + package e2e_test import ( diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 3d3aaca5..68e7171f 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -1,3 +1,6 @@ +//go:build e2e +// +build e2e + package e2e_test import ( From e1bfcb1aa678a743fa83bc7290872da0d94ac228 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 26 Oct 2021 13:47:13 +0100 Subject: [PATCH 164/542] Tidying up of redundant code, fixes to fwdtype lb --- cmd/kube-vip-kubeadm.go | 33 --------- cmd/kube-vip.go | 23 +++---- pkg/cluster/clusterLeader.go | 18 ++--- pkg/kubevip/config_generator.go | 2 - pkg/loadbalancer/ipvs.go | 25 ++++--- pkg/loadbalancer/port_forward.go | 113 ------------------------------- pkg/manager/manager_arp.go | 2 +- pkg/manager/watcher.go | 93 ------------------------- 8 files changed, 33 insertions(+), 276 deletions(-) delete mode 100644 pkg/loadbalancer/port_forward.go diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index d618a283..d6dcde7e 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -3,7 +3,6 @@ package cmd import ( "context" "fmt" - "net" "os" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -137,35 +136,3 @@ var kubeKubeadmJoin = &cobra.Command{ fmt.Println(cfg) }, } - -func autoGenLocalPeer() (*kubevip.RaftPeer, error) { - // hostname // address // defaultport - h, err := os.Hostname() - if err != nil { - return nil, err - } - - var a string - addrs, err := net.InterfaceAddrs() - if err != nil { - return nil, err - } - for _, address := range addrs { - // check the address type and if it is not a loopback the display it - if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { - if ipnet.IP.To16() != nil { - a = ipnet.IP.String() - break - } - } - } - if a == "" { - return nil, fmt.Errorf("unable to find local address") - } - return &kubevip.RaftPeer{ - ID: h, - Address: a, - Port: 10000, - }, nil - -} diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 46fea08c..b8e463dd 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -61,24 +61,18 @@ var kubeVipCmd = &cobra.Command{ func init() { - localpeer, err := autoGenLocalPeer() - if err != nil { - log.Fatalln(err) - } - initConfig.LocalPeer = *localpeer - //initConfig.Peers = append(initConfig.Peers, *localpeer) + // Basic flags kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "Port for the VIP") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") + + // LoadBalancer flags + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS") kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6444, "loadbalancer port for the VIP") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") - kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") // Clustering type (leaderElection) @@ -87,10 +81,6 @@ func init() { kubeVipCmd.PersistentFlags().IntVar(&initConfig.RenewDeadline, "leaseRenewDuration", 3, "Length of time a Kubernetes leader can attempt to renew its lease") kubeVipCmd.PersistentFlags().IntVar(&initConfig.RetryPeriod, "leaseRetry", 1, "Number of times the host will retry to hold a lease") - // Clustering type (raft) - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AddPeersAsBackends, "addPeersToLB", true, "Add raft peers to the load-balancer") - // Packet flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableMetal, "metal", false, "This will use the Equinix Metal API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalAPIKey, "metalKey", "", "The API token for authenticating with the Equinix Metal API") @@ -99,6 +89,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // BGP flags + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableBGP, "bgp", false, "This will enable BGP support within kube-vip") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)") @@ -109,6 +100,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.BGPPeerConfig.MultiHop, "multihop", false, "This will enable BGP multihop support") kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma separated BGP Peer, format: address:as:password:multihop") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") // Control plane specific flags kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") @@ -119,6 +111,7 @@ func init() { // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") + // Behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index 6bbbc50f..b55e5c13 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -256,15 +256,14 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe if c.EnableLoadBalancer { log.Infof("Starting IPVS LoadBalancer") - portForwarder := loadbalancer.NewServer(c.VIP, c.LoadBalancerPort) - // TODO - lb, err := loadbalancer.NewIPVSLB("1.2.3.4", 6444) + + lb, err := loadbalancer.NewIPVSLB(c.VIP, c.LoadBalancerPort) if err != nil { - log.Error(err) + log.Errorf("Error creating IPVS LoadBalancer [%s]", err) } go func() { - err = sm.LabelsWatcher(lb) + err = sm.NodeWatcher(lb) if err != nil { log.Errorf("Error watching node labels [%s]", err) } @@ -272,8 +271,11 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe // Shutdown function that will wait on this signal, unless we call it ourselves go func() { <-signalChan + err = lb.RemoveIPVSLB() + if err != nil { + log.Errorf("Error stopping IPVS LoadBalancer [%s]", err) + } log.Info("Stopping IPVS LoadBalancer") - portForwarder.Stop() }() } @@ -366,9 +368,7 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe return nil } -// present -// LabelsWatcher will watch for labels created on nodes -func (sm *Manager) LabelsWatcher(lb *loadbalancer.IPVSLoadBalancer) error { +func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer) 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") diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 2aff92c8..28caa47a 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -364,8 +364,6 @@ func ParseEnvironment(c *Config) error { return err } c.EnableLoadBalancer = b - // Load Balancer configuration - // return parseEnvironmentLoadBalancer(c) } return nil diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index 80e42d8f..fb24fc53 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -3,7 +3,7 @@ package loadbalancer import ( "fmt" "net" - "os" + "strings" "github.com/cloudflare/ipvs" log "github.com/sirupsen/logrus" @@ -55,9 +55,12 @@ func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { } err = c.CreateService(svc) // If we've an error it could be that the IPVS lb instance has been left from a previous leadership - if err == os.ErrExist { + if err != nil && strings.Contains(err.Error(), "file exists") { log.Warnf("load balancer for API server already exists, attempting to remove and re-create") - + err = c.RemoveService(svc) + if err != nil { + return nil, fmt.Errorf("error re-creating IPVS service: %v", err) + } err = c.CreateService(svc) if err != nil { return nil, fmt.Errorf("error re-creating IPVS service: %v", err) @@ -86,15 +89,17 @@ func (lb *IPVSLoadBalancer) RemoveIPVSLB() error { func (lb *IPVSLoadBalancer) AddBackend(address string) error { dst := ipvs.Destination{ - Address: ipvs.NewIP(net.ParseIP(address)), - Port: 6443, - Family: ipvs.INET, - Weight: 1, + Address: ipvs.NewIP(net.ParseIP(address)), + Port: 6443, + Family: ipvs.INET, + Weight: 1, + FwdMethod: ipvs.Local, } + err := lb.client.CreateDestination(lb.loadBalancerService, dst) - // TODO: we either parse the IPVS configuration to see if a backend exists - // or if it already exists we just ignore this and continue ons - if err != nil && err != os.ErrExist { + // Swallow error of existing back end, the node watcher may attempt to apply + // the same back end multiple times + if err != nil && !strings.Contains(err.Error(), "file exists") { return fmt.Errorf("error creating backend: %v", err) } return nil diff --git a/pkg/loadbalancer/port_forward.go b/pkg/loadbalancer/port_forward.go deleted file mode 100644 index cc0c9626..00000000 --- a/pkg/loadbalancer/port_forward.go +++ /dev/null @@ -1,113 +0,0 @@ -package loadbalancer - -import ( - "fmt" - "io" - "net" - "os" - "sync" - "time" - - log "github.com/sirupsen/logrus" -) - -type Server struct { - listener *net.TCPListener - listenPort int - quit chan bool - exited chan bool -} - -func NewServer(listenVIP string, listenPort int) *Server { - addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", listenVIP, listenPort)) - // TODO: return nil, error and decide how to handle it in the calling function - if err != nil { - fmt.Println("Failed to resolve address", err.Error()) - os.Exit(1) - } - - // TODO: return nil, error and decide how to handle it in the calling function - listener, err := net.ListenTCP("tcp", addr) - if err != nil { - fmt.Println("Failed to create listener", err.Error()) - os.Exit(1) - } - - // TODO: do not use this syntax, add the field names - srv := &Server{ - listener: listener, - listenPort: listenPort, - quit: make(chan bool), - exited: make(chan bool), - } - // TODO: no need to export Serve as it is only called internally - go srv.Serve() - return srv -} - -func (srv *Server) Serve() { - var handlers sync.WaitGroup - for { - select { - case <-srv.quit: - fmt.Println("Shutting down...") - srv.listener.Close() - handlers.Wait() - close(srv.exited) - return - default: - err := srv.listener.SetDeadline(time.Now().Add(1e9)) - if err != nil { - log.Errorf("Error configuring listner [%v]", err) - } - conn, err := srv.listener.Accept() - if err != nil { - if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() { - continue - } - fmt.Println("Failed to accept connection:", err.Error()) - } - handlers.Add(1) - go func() { - - err = srv.handleConnection(conn) - if err != nil { - log.Errorf("Error handling connection [%v]", err) - } - handlers.Done() - }() - } - } -} - -func (srv *Server) handleConnection(conn net.Conn) error { - fmt.Println("new client") - - proxy, err := net.Dial("tcp", fmt.Sprintf("1.2.3.4:%d", srv.listenPort)) - if err != nil { - return err - } - - fmt.Println("proxy connected") - go copyIO(conn, proxy) - go copyIO(proxy, conn) - return nil -} - -func copyIO(src, dest net.Conn) { - defer src.Close() - defer dest.Close() - _, err := io.Copy(src, dest) - if err != nil { - log.Errorf("Error copying data [%v]", err) - } -} - -func (srv *Server) Stop() { - fmt.Println("Stop requested") - // XXX: You cannot use the same channel in two directions. - // The order of operations on the channel is undefined. - close(srv.quit) - <-srv.exited - fmt.Println("Stopped successfully") -} diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 7eb36ff8..cf670138 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -79,7 +79,7 @@ func (sm *Manager) startARP() error { } }() - // Check if we're also starting the services, if now we can sit and wait on the closing channel and return here + // 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") diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 8f3a6c16..665f979d 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -10,7 +10,6 @@ import ( "sync" "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -293,95 +292,3 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er return bgpConfig, bgpPeer, nil } - -// This file handles the watching of node annotations for configuration, it will exit once the annotations are -// present -// LabelsWatcher will watch for labels created on nodes -func (sm *Manager) LabelsWatcher(lb *loadbalancer.IPVSLoadBalancer) 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") - - labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"node-role.kubernetes.io/control-plane": ""}} - listOptions := metav1.ListOptions{ - LabelSelector: labels.Set(labelSelector.MatchLabels).String(), - } - - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Nodes().Watch(context.Background(), listOptions) - }, - }) - if err != nil { - return fmt.Errorf("error creating label watcher: %s", err.Error()) - } - - go func() { - <-sm.signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context - rw.Stop() - }() - - ch := rw.ResultChan() - //defer rw.Stop() - - for event := range ch { - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - node, ok := event.Object.(*v1.Node) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") - } - //Find the node IP address (this isn't foolproof) - for x := range node.Status.Addresses { - - if node.Status.Addresses[x].Type == v1.NodeInternalIP { - err = lb.AddBackend(node.Status.Addresses[x].Address) - if err != nil { - log.Errorf("Add IPVS backend [%v]", err) - } - } - } - case watch.Deleted: - node, ok := event.Object.(*v1.Node) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") - } - - //Find the node IP address (this isn't foolproof) - for x := range node.Status.Addresses { - - if node.Status.Addresses[x].Type == v1.NodeInternalIP { - err = lb.AddBackend(node.Status.Addresses[x].Address) - if err != nil { - log.Errorf("Del IPVS backend [%v]", err) - } - } - } - - log.Infof("Node [%s] has been deleted", node.Name) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Error("Error attempting to watch Kubernetes Nodes") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - default: - } - } - - log.Infoln("Exiting Annotations watcher") - return nil - -} From 81975220c6b12b869efcffd8d4fcaa41981bddc3 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 26 Oct 2021 13:52:25 +0100 Subject: [PATCH 165/542] Fixed missing import --- pkg/cluster/clusterLeader.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeader.go index a2579b57..f48678b7 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeader.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/leaderelection" "k8s.io/client-go/tools/leaderelection/resourcelock" watchtools "k8s.io/client-go/tools/watch" From 08d38f55205be154a76289305f048a068bacff6d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 26 Oct 2021 15:03:00 +0100 Subject: [PATCH 166/542] Final fixes to the IPVS work --- cmd/kube-vip.go | 5 +++-- pkg/kubevip/config_generator.go | 9 +++++++++ pkg/manager/manager.go | 25 +++++++++---------------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index b8e463dd..edd6e6b6 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -195,8 +195,6 @@ var kubeVipManager = &cobra.Command{ Use: "manager", Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { - // Set the logging level for all subsequent functions - log.SetLevel(log.Level(logLevel)) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) @@ -204,6 +202,9 @@ var kubeVipManager = &cobra.Command{ log.Fatalln(err) } + // Set the logging level for all subsequent functions + log.SetLevel(log.Level(logLevel)) + if initConfig.Interface == "" { log.Infof("No interface is specified for VIP in config, auto-detecting default Interface") defaultIF, err := vip.GetDefaultGatewayInterface() diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 28caa47a..c624abaf 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -366,6 +366,15 @@ func ParseEnvironment(c *Config) error { c.EnableLoadBalancer = b } + // Find loadbalancer port + env = os.Getenv(lbPort) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.LoadBalancerPort = int(i) + } return nil } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 02831c42..8980f68c 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -19,7 +19,6 @@ import ( "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" ) const plunderLock = "plndr-svcs-lock" @@ -78,7 +77,6 @@ type Instance struct { func New(configMap string, config *kubevip.Config) (*Manager, error) { var clientset *kubernetes.Clientset - var cfg *rest.Config var err error adminConfigPath := "/etc/kubernetes/admin.conf" @@ -86,7 +84,14 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { switch { case fileExists(adminConfigPath): - clientset, err = k8s.NewClientset(adminConfigPath, false, "") + if config.EnableControlPane { + // If this is a control pane host it will likely have started as a static pod or won't have the + // VIP up before trying to connect to the API server, we set the API endpoint to this machine to + // ensure connectivity. + clientset, err = k8s.NewClientset(adminConfigPath, false, fmt.Sprintf("kubernetes:%v", config.Port)) + } else { + clientset, err = k8s.NewClientset(adminConfigPath, false, "") + } if err != nil { return nil, fmt.Errorf("could not create k8s clientset from external file: %q: %v", adminConfigPath, err) } @@ -105,18 +110,6 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { log.Debug("Using external Kubernetes configuration from incluster config.") } - // If this is a control pane host it will likely have started as a static pod or won't have the - // VIP up before trying to connect to the API server, we set the API endpoint to this machine to - // ensure connectivity. - if config.EnableControlPane { - log.Debugf("Modifying address of Kubernetes server to \"kubernetes\" (internal hostname)") - cfg.Host = fmt.Sprintf("kubernetes:%v", config.Port) - clientset, err = kubernetes.NewForConfig(cfg) - } - if err != nil { - return nil, fmt.Errorf("error creating kubernetes client: %s", err.Error()) - } - return &Manager{ clientSet: clientset, configMap: configMap, @@ -179,7 +172,7 @@ func returnNameSpace() (string, error) { } return "", err } - return "", fmt.Errorf("Unable to find Namespace") + return "", fmt.Errorf("unable to find Namespace") } func (sm *Manager) parseAnnotations() error { From a79d5e61e930fa7bb4a0acdf648ecf5bd64fd934 Mon Sep 17 00:00:00 2001 From: Christian Rebischke Date: Sat, 30 Oct 2021 03:29:32 +0200 Subject: [PATCH 167/542] update images Signed-off-by: Christian Rebischke --- docs/install_daemonset/index.md | 4 ++-- docs/install_static/index.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 4d6c2a19..b56dfb1d 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -41,10 +41,10 @@ This section only covers generating a simple *BGP* configuration, as the main fo The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.9 vip"` #### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.9"` ### BGP Example diff --git a/docs/install_static/index.md b/docs/install_static/index.md index b94b6cb7..1de2fb32 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -32,10 +32,10 @@ This section details creating a number of manifests for various use cases The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.9 vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.9"` ## ARP From 0cef76ff4a6da6470cb7fc9b4fc2479924cb9618 Mon Sep 17 00:00:00 2001 From: Dirkco du Plessis Date: Sat, 30 Oct 2021 10:40:25 +0100 Subject: [PATCH 168/542] Add hostAliases to kube-vip-arp-ds.yaml on v0.3.9 Signed-off-by: Dirkco du Plessis --- docs/manifests/v0.3.9/kube-vip-arp-ds.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml index 24552ab2..82328330 100644 --- a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml +++ b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml @@ -54,6 +54,10 @@ spec: - NET_ADMIN - NET_RAW - SYS_TIME + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 hostNetwork: true serviceAccountName: kube-vip updateStrategy: {} From 35f7d816f437f4de5f35fbb994f0530a2dff2f02 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sun, 7 Nov 2021 14:56:48 +0000 Subject: [PATCH 169/542] Removes duplicated code and tidies function names --- cmd/kube-vip-start.go | 2 +- go.mod | 7 - go.sum | 41 --- ...sterLeader.go => clusterLeaderElection.go} | 224 +------------ pkg/cluster/service.go | 309 ++++++++++++++++++ pkg/cluster/singleNode.go | 113 +------ pkg/cluster/state.go | 39 --- pkg/manager/manager_arp.go | 41 ++- pkg/manager/manager_bgp.go | 39 ++- 9 files changed, 363 insertions(+), 452 deletions(-) rename pkg/cluster/{clusterLeader.go => clusterLeaderElection.go} (58%) create mode 100644 pkg/cluster/service.go delete mode 100644 pkg/cluster/state.go diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index d00a9d34..1a17ce2d 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -110,7 +110,7 @@ var kubeVipStart = &cobra.Command{ } // Leader Cluster will block - err = newCluster.StartLeaderCluster(&startConfig, cm, bgpServer) + err = newCluster.StartCluster(&startConfig, cm, bgpServer) if err != nil { log.Fatalf("%v", err) } diff --git a/go.mod b/go.mod index d02c1187..96ac1884 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,11 @@ module github.com/kube-vip/kube-vip go 1.14 require ( - github.com/armon/go-metrics v0.3.8 // indirect github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 github.com/davecgh/go-spew v1.1.1 - github.com/fatih/color v1.10.0 // indirect github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect - github.com/hashicorp/go-hclog v0.16.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.0 // indirect - github.com/hashicorp/go-msgpack v1.1.5 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/raft v1.3.1 github.com/imdario/mergo v0.3.12 // indirect github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e github.com/jpillora/backoff v1.0.0 diff --git a/go.sum b/go.sum index 5159dc4c..28d0c264 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -68,9 +66,6 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-metrics v0.3.8 h1:oOxq3KPj0WhCuy50EhzwiyMyG2ovRQZpZLXQuOh2a/M= -github.com/armon/go-metrics v0.3.8/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -93,8 +88,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 h1:uI/fFG5+s/On/vH4eAaeYTKSliqmlnzzWL85zeI4zOM= @@ -152,8 +145,6 @@ github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+ github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -286,39 +277,24 @@ github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoP github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.16.0 h1:uCeOEwSWGMwhJUdpUjk+1cVKIEfGu2/1nFXukimi2MU= -github.com/hashicorp/go-hclog v0.16.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= -github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= -github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/raft v1.3.1 h1:zDT8ke8y2aP4wf9zPTB2uSIeavJ3Hx/ceY4jxI2JxuY= -github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -351,7 +327,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -391,13 +366,8 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -485,9 +455,6 @@ github.com/packethost/packngo v0.13.0 h1:VIeDY/Uju53v8LAKxiqTrfR9jkpX5PhWdnQC0h3 github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -507,12 +474,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= @@ -524,18 +489,15 @@ github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlPDGM= github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -605,7 +567,6 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -763,7 +724,6 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -854,7 +814,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= diff --git a/pkg/cluster/clusterLeader.go b/pkg/cluster/clusterLeaderElection.go similarity index 58% rename from pkg/cluster/clusterLeader.go rename to pkg/cluster/clusterLeaderElection.go index f48678b7..0b371942 100644 --- a/pkg/cluster/clusterLeader.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -16,8 +16,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/loadbalancer" "github.com/kube-vip/kube-vip/pkg/packet" - "github.com/kube-vip/kube-vip/pkg/vip" - "github.com/packethost/packngo" log "github.com/sirupsen/logrus" @@ -70,8 +68,8 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { }, nil } -// StartLeaderCluster - Begins a running instance of the Raft cluster -func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error { +// StartCluster - Begins a running instance of the Raft cluster +func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error { id, err := os.Hostname() if err != nil { @@ -192,131 +190,12 @@ func (cluster *Cluster) StartLeaderCluster(c *kubevip.Config, sm *Manager, bgpSe RetryPeriod: time.Duration(c.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - // we're notified when we start - log.Info("This node is starting the leadership of the cluster") - // setup ddns first - // for first time, need to wait until IP is allocated from DHCP - if cluster.Network.IsDDNS() { - if err := cluster.StartDDNS(ctxDNS); err != nil { - log.Error(err) - } - } - - // start the dns updater if address is dns - if cluster.Network.IsDNS() { - log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) - ipUpdater := vip.NewIPUpdater(cluster.Network) - ipUpdater.Run(ctxDNS) - } - - err = cluster.Network.AddIP() + // As we're leading lets start the vip service + err = cluster.vipService(c, sm, bgpServer, ctxArp, ctxDNS) if err != nil { - log.Warnf("%v", err) - } - - if c.EnableMetal { - // We're not using Packet with BGP - if !c.EnableBGP { - // Attempt to attach the EIP in the standard manner - log.Debugf("Attaching the Packet EIP through the API to this host") - err = packet.AttachEIP(packetClient, c, id) - if err != nil { - log.Error(err) - } - } - } - - 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.IP(), c.VIPCIDR) - log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) - - err = bgpServer.AddHost(cidrVip) - if err != nil { - log.Error(err) - } - } - - if c.EnableLoadBalancer { - - log.Infof("Starting IPVS LoadBalancer") - - lb, err := loadbalancer.NewIPVSLB(c.VIP, c.LoadBalancerPort) - if err != nil { - log.Errorf("Error creating IPVS LoadBalancer [%s]", err) - } - - go func() { - err = sm.NodeWatcher(lb) - if err != nil { - log.Errorf("Error watching node labels [%s]", err) - } - }() - // Shutdown function that will wait on this signal, unless we call it ourselves - go func() { - <-signalChan - err = lb.RemoveIPVSLB() - if err != nil { - log.Errorf("Error stopping IPVS LoadBalancer [%s]", err) - } - log.Info("Stopping IPVS LoadBalancer") - }() + log.Errorf("Error starting the VIP service on the leader [%s]", err) } - if c.EnableARP { - ctxArp, cancelArp = context.WithCancel(context.Background()) - - ipString := cluster.Network.IP() - - var ndp *vip.NdpResponder - if vip.IsIPv6(ipString) { - ndp, err = vip.NewNDPResponder(c.Interface) - if err != nil { - log.Fatalf("failed to create new NDP Responder") - } - } - - go func(ctx context.Context) { - if ndp != nil { - defer ndp.Close() - } - - for { - select { - case <-ctx.Done(): // if cancel() execute - return - default: - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } - - if vip.IsIPv4(ipString) { - // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address - err := vip.ARPSendGratuitous(ipString, c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } else { - // Gratuitous NDP, will broadcast new MAC <-> IPv6 address - err := ndp.SendGratuitous(ipString) - if err != nil { - log.Warnf("%v", err) - } - } - } - time.Sleep(3 * time.Second) - } - }(ctxArp) - } }, OnStoppedLeading: func() { // we can do cleanup here @@ -440,96 +319,3 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer) error { return nil } - -// TODO - refactor an active machine func(), this will replace the singleNode code and have a single code block - -// func (cluster *Cluster) active(c *kubevip.Config) error { -// // we're notified when we start -// log.Info("This node is starting with leadership of the cluster") -// // setup ddns first -// // for first time, need to wait until IP is allocated from DHCP -// if cluster.Network.IsDDNS() { -// if err := cluster.StartDDNS(ctxDns); err != nil { -// log.Error(err) -// } -// } - -// // start the dns updater if address is dns -// if cluster.Network.IsDNS() { -// log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) -// ipUpdater := vip.NewIPUpdater(cluster.Network) -// ipUpdater.Run(ctxDns) -// } - -// err := cluster.Network.AddIP() -// if err != nil { -// log.Warnf("%v", err) -// } - -// if c.EnablePacket { -// // We're not using Packet with BGP -// if !c.EnableBGP { -// // Attempt to attach the EIP in the standard manner -// log.Debugf("Attaching the Packet EIP through the API to this host") -// err = packet.AttachEIP(packetClient, c, id) -// if err != nil { -// log.Error(err) -// } -// } -// } - -// 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.IP(), c.VIPCIDR) -// log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) - -// err = bgpServer.AddHost(cidrVip) -// if err != nil { -// log.Error(err) -// } -// } - -// if c.EnableLoadBalancer { -// // Once we have the VIP running, start the load balancer(s) that bind to the VIP -// for x := range c.LoadBalancers { - -// if c.LoadBalancers[x].BindToVip == true { -// err = VipLB.Add(cluster.Network.IP(), &c.LoadBalancers[x]) -// if err != nil { -// log.Warnf("Error creating loadbalancer [%s] type [%s] -> error [%s]", c.LoadBalancers[x].Name, c.LoadBalancers[x].Type, err) - -// // Stop all load balancers associated with the VIP -// err = VipLB.StopAll() -// if err != nil { -// log.Warnf("%v", err) -// } - -// err = cluster.Network.DeleteIP() -// if err != nil { -// log.Warnf("%v", err) -// } -// } -// } -// } -// } - -// if c.EnableARP == true { -// ctxArp, cancelArp = context.WithCancel(context.Background()) - -// go func(ctx context.Context) { -// for { -// select { -// case <-ctx.Done(): // if cancel() execute -// return -// default: -// // Gratuitous ARP, will broadcast to new MAC <-> IP -// err = vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) -// if err != nil { -// log.Warnf("%v", err) -// } -// } -// time.Sleep(3 * time.Second) -// } -// }(ctxArp) -// } -// } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go new file mode 100644 index 00000000..89974552 --- /dev/null +++ b/pkg/cluster/service.go @@ -0,0 +1,309 @@ +package cluster + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/loadbalancer" + "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/vip" + "github.com/packethost/packngo" + log "github.com/sirupsen/logrus" +) + +func (cluster *Cluster) vipService(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, ctxArp, ctxDNS context.Context) error { + id, err := os.Hostname() + if err != nil { + return err + } + // If Packet is enabled then we can begin our preparation work + var packetClient *packngo.Client + if c.EnableMetal { + if c.ProviderConfig != "" { + key, project, err := packet.GetPacketConfig(c.ProviderConfig) + if err != nil { + log.Error(err) + } else { + // Set the environment variable with the key for the project + os.Setenv("PACKET_AUTH_TOKEN", key) + // Update the configuration with the project key + c.MetalProjectID = project + } + } + packetClient, err := packngo.NewClient() + if err != nil { + log.Error(err) + } + + // We're using Packet with BGP, popuplate the Peer information from the API + if c.EnableBGP { + log.Infoln("Looking up the BGP configuration from packet") + err = packet.BGPLookup(packetClient, c) + if err != nil { + log.Error(err) + } + } + } + + // // use a Go context so we can tell the arp loop code when we + // // want to step down + // ctxArp, cancelArp := context.WithCancel(context.Background()) + // defer cancelArp() + + // // use a Go context so we can tell the dns loop code when we + // // want to step down + // ctxDNS, cancelDNS := context.WithCancel(context.Background()) + // defer cancelDNS() + + // listen for interrupts or the Linux SIGTERM signal and cancel + // our context, which the leader election code will observe and + // step down + signalChan := make(chan os.Signal, 1) + // Add Notification for Userland interrupt + signal.Notify(signalChan, syscall.SIGINT) + + // Add Notification for SIGTERM (sent from Kubernetes) + signal.Notify(signalChan, syscall.SIGTERM) + + if cluster.Network.IsDDNS() { + if err := cluster.StartDDNS(ctxDNS); err != nil { + log.Error(err) + } + } + + // start the dns updater if address is dns + if cluster.Network.IsDNS() { + log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) + ipUpdater := vip.NewIPUpdater(cluster.Network) + ipUpdater.Run(ctxDNS) + } + + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + + if c.EnableMetal { + // We're not using Packet with BGP + if !c.EnableBGP { + // Attempt to attach the EIP in the standard manner + log.Debugf("Attaching the Packet EIP through the API to this host") + err = packet.AttachEIP(packetClient, c, id) + if err != nil { + log.Error(err) + } + } + } + + 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.IP(), c.VIPCIDR) + log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) + + err = bgpServer.AddHost(cidrVip) + if err != nil { + log.Error(err) + } + } + + if c.EnableLoadBalancer { + + log.Infof("Starting IPVS LoadBalancer") + + lb, err := loadbalancer.NewIPVSLB(c.VIP, c.LoadBalancerPort) + if err != nil { + log.Errorf("Error creating IPVS LoadBalancer [%s]", err) + } + + go func() { + err = sm.NodeWatcher(lb) + if err != nil { + log.Errorf("Error watching node labels [%s]", err) + } + }() + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-signalChan + err = lb.RemoveIPVSLB() + if err != nil { + log.Errorf("Error stopping IPVS LoadBalancer [%s]", err) + } + log.Info("Stopping IPVS LoadBalancer") + }() + } + + if c.EnableARP { + //ctxArp, cancelArp = context.WithCancel(context.Background()) + + ipString := cluster.Network.IP() + + var ndp *vip.NdpResponder + if vip.IsIPv6(ipString) { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } + } + + go func(ctx context.Context) { + if ndp != nil { + defer ndp.Close() + } + + for { + select { + case <-ctx.Done(): // if cancel() execute + return + default: + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + } + + if vip.IsIPv4(ipString) { + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address + err := vip.ARPSendGratuitous(ipString, c.Interface) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } + } + } + time.Sleep(3 * time.Second) + } + }(ctxArp) + } + return nil +} + +// StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle +func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) error { + // Start a kube-vip loadbalancer service + log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) + + // use a Go context so we can tell the arp loop code when we + // want to step down + //nolint + ctxArp, cancelArp := context.WithCancel(context.Background()) + defer cancelArp() + + cluster.stop = make(chan bool, 1) + cluster.completed = make(chan bool, 1) + + err := cluster.Network.DeleteIP() + if err != nil { + log.Warnf("Attempted to clean existing VIP => %v", err) + } + + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + + if c.EnableARP { + ctxArp, cancelArp = context.WithCancel(context.Background()) + + ipString := cluster.Network.IP() + + var ndp *vip.NdpResponder + if vip.IsIPv6(ipString) { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } + } + go func(ctx context.Context) { + if ndp != nil { + defer ndp.Close() + } + + for { + + select { + case <-ctx.Done(): // if cancel() execute + return + default: + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + } + + if vip.IsIPv4(ipString) { + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address + err := vip.ARPSendGratuitous(ipString, c.Interface) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } + } + } + time.Sleep(3 * time.Second) + } + }(ctxArp) + } + + 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.IP(), c.VIPCIDR) + log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) + err = bgp.AddHost(cidrVip) + if err != nil { + log.Error(err) + } + } + + go func() { + //nolint + for { + select { + case <-cluster.stop: + // Stop the Arp context if it is running + cancelArp() + + log.Info("[LOADBALANCER] Stopping load balancers") + log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) + err = cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) + } + + close(cluster.completed) + return + } + } + }() + log.Infoln("Started Load Balancer and Virtual IP") + return nil +} diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 209db95c..54767852 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -2,8 +2,6 @@ package cluster import ( "context" - "fmt" - "time" log "github.com/sirupsen/logrus" @@ -68,115 +66,16 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro return nil } -// StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle -func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) error { - // Start a kube-vip loadbalancer service - log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) - +func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp.Server) error { // use a Go context so we can tell the arp loop code when we // want to step down - //nolint ctxArp, cancelArp := context.WithCancel(context.Background()) defer cancelArp() - cluster.stop = make(chan bool, 1) - cluster.completed = make(chan bool, 1) - - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("Attempted to clean existing VIP => %v", err) - } - - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - - if c.EnableARP { - ctxArp, cancelArp = context.WithCancel(context.Background()) - - ipString := cluster.Network.IP() - - var ndp *vip.NdpResponder - if vip.IsIPv6(ipString) { - ndp, err = vip.NewNDPResponder(c.Interface) - if err != nil { - log.Fatalf("failed to create new NDP Responder") - } - } - go func(ctx context.Context) { - if ndp != nil { - defer ndp.Close() - } - - for { - - select { - case <-ctx.Done(): // if cancel() execute - return - default: - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } - - if vip.IsIPv4(ipString) { - // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address - err := vip.ARPSendGratuitous(ipString, c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } else { - // Gratuitous NDP, will broadcast new MAC <-> IPv6 address - err := ndp.SendGratuitous(ipString) - if err != nil { - log.Warnf("%v", err) - } - } - } - time.Sleep(3 * time.Second) - } - }(ctxArp) - } - - 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.IP(), c.VIPCIDR) - log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) - err = bgp.AddHost(cidrVip) - if err != nil { - log.Error(err) - } - } - - go func() { - //nolint - for { - select { - case <-cluster.stop: - // Stop the Arp context if it is running - cancelArp() - - log.Info("[LOADBALANCER] Stopping load balancers") - log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } + // use a Go context so we can tell the dns loop code when we + // want to step down + ctxDNS, cancelDNS := context.WithCancel(context.Background()) + defer cancelDNS() - close(cluster.completed) - return - } - } - }() - log.Infoln("Started Load Balancer and Virtual IP") - return nil + return cluster.vipService(c, sm, bgp, ctxArp, ctxDNS) } diff --git a/pkg/cluster/state.go b/pkg/cluster/state.go deleted file mode 100644 index e212fbe4..00000000 --- a/pkg/cluster/state.go +++ /dev/null @@ -1,39 +0,0 @@ -package cluster - -import ( - "io" - - "github.com/hashicorp/raft" -) - -// FSM - Finite State Machine for Raft -type FSM struct { -} - -// Apply - TODO -func (fsm FSM) Apply(log *raft.Log) interface{} { - return nil -} - -// Restore - TODO -func (fsm FSM) Restore(snap io.ReadCloser) error { - return nil -} - -// Snapshot - TODO, returns an empty snapshot -func (fsm FSM) Snapshot() (raft.FSMSnapshot, error) { - return Snapshot{}, nil -} - -// Snapshot - -type Snapshot struct { -} - -// Persist - -func (snapshot Snapshot) Persist(sink raft.SnapshotSink) error { - return nil -} - -// Release - -func (snapshot Snapshot) Release() { -} diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index cf670138..93152915 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -8,8 +8,7 @@ import ( "time" "github.com/kamhlos/upnp" - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/vip" + "github.com/kube-vip/kube-vip/pkg/cluster" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection" @@ -27,10 +26,10 @@ func (sm *Manager) startARP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // use a Go context so we can tell the dns loop code when we - // want to step down - ctxDNS, cancelDNS := context.WithCancel(context.Background()) - defer cancelDNS() + // // use a Go context so we can tell the dns loop code when we + // // want to step down + // ctxDNS, cancelDNS := context.WithCancel(context.Background()) + // defer cancelDNS() // Shutdown function that will wait on this signal, unless we call it ourselves go func() { @@ -49,20 +48,20 @@ func (sm *Manager) startARP() error { return err } - // setup ddns first - // for first time, need to wait until IP is allocated from DHCP - if cpCluster.Network.IsDDNS() { - if err := cpCluster.StartDDNS(ctxDNS); err != nil { - log.Error(err) - } - } - - // start the dns updater if address is dns - if cpCluster.Network.IsDNS() { - log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) - ipUpdater := vip.NewIPUpdater(cpCluster.Network) - ipUpdater.Run(ctxDNS) - } + // // setup ddns first + // // for first time, need to wait until IP is allocated from DHCP + // if cpCluster.Network.IsDDNS() { + // if err := cpCluster.StartDDNS(ctxDNS); err != nil { + // log.Error(err) + // } + // } + + // // start the dns updater if address is dns + // if cpCluster.Network.IsDNS() { + // log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) + // ipUpdater := vip.NewIPUpdater(cpCluster.Network) + // ipUpdater.Run(ctxDNS) + // } clusterManager := &cluster.Manager{ KubernetesClient: sm.clientSet, @@ -70,7 +69,7 @@ func (sm *Manager) startARP() error { } go func() { - err := cpCluster.StartLeaderCluster(sm.config, clusterManager, nil) + err := cpCluster.StartCluster(sm.config, clusterManager, nil) if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index ac04f130..9b66c959 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -8,7 +8,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/packet" - "github.com/kube-vip/kube-vip/pkg/vip" "github.com/packethost/packngo" log "github.com/sirupsen/logrus" ) @@ -59,9 +58,9 @@ func (sm *Manager) startBGP() error { defer cancel() // use a Go context so we can tell the dns loop code when we - // want to step down - ctxDNS, cancelDNS := context.WithCancel(context.Background()) - defer cancelDNS() + // // want to step down + // ctxDNS, cancelDNS := context.WithCancel(context.Background()) + // defer cancelDNS() // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { @@ -89,22 +88,28 @@ func (sm *Manager) startBGP() error { if err != nil { return err } - // setup ddns first - // for first time, need to wait until IP is allocated from DHCP - if cpCluster.Network.IsDDNS() { - if err := cpCluster.StartDDNS(ctxDNS); err != nil { - log.Error(err) - } + // // setup ddns first + // // for first time, need to wait until IP is allocated from DHCP + // if cpCluster.Network.IsDDNS() { + // if err := cpCluster.StartDDNS(ctxDNS); err != nil { + // log.Error(err) + // } + // } + + // // start the dns updater if address is dns + // if cpCluster.Network.IsDNS() { + // log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) + // ipUpdater := vip.NewIPUpdater(cpCluster.Network) + // ipUpdater.Run(ctxDNS) + // } + + clusterManager := &cluster.Manager{ + KubernetesClient: sm.clientSet, + SignalChan: sm.signalChan, } - // start the dns updater if address is dns - if cpCluster.Network.IsDNS() { - log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) - ipUpdater := vip.NewIPUpdater(cpCluster.Network) - ipUpdater.Run(ctxDNS) - } go func() { - err = cpCluster.StartLoadBalancerService(sm.config, sm.bgpServer) + err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer) if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance From c0a5c7a762fce7b074d36e6c73f7d2d3ac002f53 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 8 Nov 2021 12:17:53 +0000 Subject: [PATCH 170/542] Removal of more duplicate code --- pkg/cluster/clusterLeaderElection.go | 4 +-- pkg/cluster/service.go | 42 ++-------------------------- pkg/cluster/singleNode.go | 5 ++-- pkg/manager/manager_arp.go | 22 +-------------- pkg/manager/manager_bgp.go | 21 +------------- 5 files changed, 9 insertions(+), 85 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 0b371942..8ed0ded1 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -68,7 +68,7 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { }, nil } -// StartCluster - Begins a running instance of the Raft cluster +// StartCluster - Begins a running instance of the Leader Election cluster func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error { id, err := os.Hostname() @@ -191,7 +191,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { // As we're leading lets start the vip service - err = cluster.vipService(c, sm, bgpServer, ctxArp, ctxDNS) + err = cluster.vipService(c, sm, bgpServer, ctxArp, ctxDNS, packetClient) if err != nil { log.Errorf("Error starting the VIP service on the leader [%s]", err) } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 89974552..7b48f782 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -17,49 +17,11 @@ import ( log "github.com/sirupsen/logrus" ) -func (cluster *Cluster) vipService(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, ctxArp, ctxDNS context.Context) error { +func (cluster *Cluster) vipService(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, ctxArp, ctxDNS context.Context, packetClient *packngo.Client) error { id, err := os.Hostname() if err != nil { return err } - // If Packet is enabled then we can begin our preparation work - var packetClient *packngo.Client - if c.EnableMetal { - if c.ProviderConfig != "" { - key, project, err := packet.GetPacketConfig(c.ProviderConfig) - if err != nil { - log.Error(err) - } else { - // Set the environment variable with the key for the project - os.Setenv("PACKET_AUTH_TOKEN", key) - // Update the configuration with the project key - c.MetalProjectID = project - } - } - packetClient, err := packngo.NewClient() - if err != nil { - log.Error(err) - } - - // We're using Packet with BGP, popuplate the Peer information from the API - if c.EnableBGP { - log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, c) - if err != nil { - log.Error(err) - } - } - } - - // // use a Go context so we can tell the arp loop code when we - // // want to step down - // ctxArp, cancelArp := context.WithCancel(context.Background()) - // defer cancelArp() - - // // use a Go context so we can tell the dns loop code when we - // // want to step down - // ctxDNS, cancelDNS := context.WithCancel(context.Background()) - // defer cancelDNS() // listen for interrupts or the Linux SIGTERM signal and cancel // our context, which the leader election code will observe and @@ -220,7 +182,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } if c.EnableARP { - ctxArp, cancelArp = context.WithCancel(context.Background()) + //ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 54767852..5deee119 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -3,6 +3,7 @@ package cluster import ( "context" + "github.com/packethost/packngo" log "github.com/sirupsen/logrus" "github.com/kube-vip/kube-vip/pkg/bgp" @@ -66,7 +67,7 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro return nil } -func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp.Server) error { +func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp.Server, packetClient *packngo.Client) error { // use a Go context so we can tell the arp loop code when we // want to step down ctxArp, cancelArp := context.WithCancel(context.Background()) @@ -77,5 +78,5 @@ func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp ctxDNS, cancelDNS := context.WithCancel(context.Background()) defer cancelDNS() - return cluster.vipService(c, sm, bgp, ctxArp, ctxDNS) + return cluster.vipService(c, sm, bgp, ctxArp, ctxDNS, packetClient) } diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 93152915..b5558837 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -8,7 +8,7 @@ import ( "time" "github.com/kamhlos/upnp" - "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/cluster" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/leaderelection" @@ -26,11 +26,6 @@ func (sm *Manager) startARP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // // use a Go context so we can tell the dns loop code when we - // // want to step down - // ctxDNS, cancelDNS := context.WithCancel(context.Background()) - // defer cancelDNS() - // Shutdown function that will wait on this signal, unless we call it ourselves go func() { <-sm.signalChan @@ -48,21 +43,6 @@ func (sm *Manager) startARP() error { return err } - // // setup ddns first - // // for first time, need to wait until IP is allocated from DHCP - // if cpCluster.Network.IsDDNS() { - // if err := cpCluster.StartDDNS(ctxDNS); err != nil { - // log.Error(err) - // } - // } - - // // start the dns updater if address is dns - // if cpCluster.Network.IsDNS() { - // log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) - // ipUpdater := vip.NewIPUpdater(cpCluster.Network) - // ipUpdater.Run(ctxDNS) - // } - clusterManager := &cluster.Manager{ KubernetesClient: sm.clientSet, SignalChan: sm.signalChan, diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 9b66c959..2c2522a5 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -57,11 +57,6 @@ func (sm *Manager) startBGP() error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // use a Go context so we can tell the dns loop code when we - // // want to step down - // ctxDNS, cancelDNS := context.WithCancel(context.Background()) - // defer cancelDNS() - // Defer a function to check if the bgpServer has been created and if so attempt to close it defer func() { if sm.bgpServer != nil { @@ -88,20 +83,6 @@ func (sm *Manager) startBGP() error { if err != nil { return err } - // // setup ddns first - // // for first time, need to wait until IP is allocated from DHCP - // if cpCluster.Network.IsDDNS() { - // if err := cpCluster.StartDDNS(ctxDNS); err != nil { - // log.Error(err) - // } - // } - - // // start the dns updater if address is dns - // if cpCluster.Network.IsDNS() { - // log.Infof("starting the DNS updater for the address %s", cpCluster.Network.DNSName()) - // ipUpdater := vip.NewIPUpdater(cpCluster.Network) - // ipUpdater.Run(ctxDNS) - // } clusterManager := &cluster.Manager{ KubernetesClient: sm.clientSet, @@ -109,7 +90,7 @@ func (sm *Manager) startBGP() error { } go func() { - err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer) + err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer, packetClient) if err != nil { log.Errorf("Control Pane Error [%v]", err) // Trigger the shutdown of this manager instance From a75a53c47efdfcc0b0a07c8f4a59fc1285df9eec Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 8 Nov 2021 12:21:31 +0000 Subject: [PATCH 171/542] lint fix ! --- pkg/cluster/clusterLeaderElection.go | 2 +- pkg/cluster/service.go | 2 +- pkg/cluster/singleNode.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 8ed0ded1..c1038bef 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -191,7 +191,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { // As we're leading lets start the vip service - err = cluster.vipService(c, sm, bgpServer, ctxArp, ctxDNS, packetClient) + err = cluster.vipService(ctxArp, ctxDNS, c, sm, bgpServer, packetClient) if err != nil { log.Errorf("Error starting the VIP service on the leader [%s]", err) } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 7b48f782..6cfada76 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -17,7 +17,7 @@ import ( log "github.com/sirupsen/logrus" ) -func (cluster *Cluster) vipService(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, ctxArp, ctxDNS context.Context, packetClient *packngo.Client) error { +func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Config, sm *Manager, bgpServer *bgp.Server, packetClient *packngo.Client) error { id, err := os.Hostname() if err != nil { return err diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index 5deee119..c8440b38 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -78,5 +78,5 @@ func (cluster *Cluster) StartVipService(c *kubevip.Config, sm *Manager, bgp *bgp ctxDNS, cancelDNS := context.WithCancel(context.Background()) defer cancelDNS() - return cluster.vipService(c, sm, bgp, ctxArp, ctxDNS, packetClient) + return cluster.vipService(ctxArp, ctxDNS, c, sm, bgp, packetClient) } From 27e889e8a6b6a4db8492f3c2621fa53bc4e25872 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 9 Nov 2021 11:42:07 +0000 Subject: [PATCH 172/542] Docs for upcoming 0.4 release --- docs/architecture/index.md | 129 ++++++++++++++++++------------- docs/flags/index.md | 4 + docs/index.md | 1 + docs/install_daemonset/index.md | 10 +++ docs/install_static/index.md | 14 +++- docs/usage/EquinixMetal/index.md | 14 +++- docs/usage/k3s/index.md | 17 +++- docs/usage/kind/index.md | 23 ++++-- docs/usage/on-prem/index.md | 33 ++++---- 9 files changed, 162 insertions(+), 83 deletions(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 6145e18b..b59e7fcf 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -19,8 +19,6 @@ The `kube-vip` service builds a multi-node or multi-pod cluster to provide High- When using ARP or layer2 it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) -It is also possible to use [raft](https://en.wikipedia.org/wiki/Raft_(computer_science) clustering technology, but this approach has largely been superseded by leader election especially when running in cluster. - ### Virtual IP The leader within the cluster will assume the **vip** and will have it bound to the selected interface that is declared within the configuration. When the leader changes it will evacuate the **vip** first or in failure scenarios the **vip** will be directly assumed by the next elected leader. @@ -56,80 +54,105 @@ Request timeout for icmp_seq 150 ### Load Balancing -Within a Kubernetes cluster, the load-balancing is managed by the `plndr-cloud-provider` which watches all service that are created, and for those of `type=LoadBalancer` will create the configuration for `kube-vip` to consume. +Kube-Vip has the capability to provide a HA address for both the Kubernetes control plane and for a Kubernetes service, it recently implemented support for "actual" load-balancing for the control plane to distribute API requests across control-plane nodes. + +#### Kubernetes Service Load-Balancing + +The following is required in the kube-vip yaml to enable services: + +``` + - name: svc_enable + value: "true" +``` + +This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: -#### Load Balancing (Inside a cluster) +1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` +2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` +3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. +4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. +5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. +6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. +7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. +8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. -When using `type=LoadBalancer` within a Kubernetes cluster `kube-vip` will assign the VIP to the leader (when using ARP) or to all running Pods (when using BGP). When traffic is directed to a node with the VIP then the rules configured by `kube-proxy` will redirect the traffic to one of the pods running in the service. +#### Control Plane Load-Balancing (> 0.4) -#### Load Balancing (Outside a cluster) +**NOTE** in it's initial release IPVS load-balancing is configured for having the VIP in the same subnet as the control-plane nodes, NAT based load-balancing will appear soon. -Within the configuration of `kube-vip` multiple load-balancers can be created, below is the example load-balancer for a Kubernetes Control-plane: +To enable control-plane load balancing, the following is required in the kube-vip yaml to enable control plane load-balancing. ``` -loadBalancers: -- name: Kubernetes Control Plane - type: tcp - port: 6443 - bindToVip: true - backends: - - port: 6444 - address: 192.168.0.70 - - port: 6444 - address: 192.168.0.71 - - port: 6444 - address: 192.168.0.72 + - name : lb_enable + value: "true" ``` +The load balancing is provided through IPVS (IP Virtual Server) and provides a layer-4 (TCP Port) based round-robin across all of the control plane nodes. By default the load balancer will listen on the default 6443 port as the Kubernetes API server. +**Note:** The IPVS virtual server lives in kernel space and doesn't create an "actual" service that listens on port 6443, this allows the kernel to parse packets before they're sent to an actual TCP port. This is important to know because it means we don't have any port conflicts having the IPVS load-balancer listening on the same port as the API server on the same host. -The above load balancer will create an instance that listens on port `6443` and will forward traffic to the array of backend addresses. If the load-balancer type is `tcp` then the backends will be IP addresses, however if the backend is set to `http` then the backends should be URLs: +The load balancer port can be customised with the following snippet in the yaml. ``` - type: http - port: 6443 - bindToVip: true - backends: - - port: 6444 - address: https://192.168.0.70 + - name: lb_port + value: "6443" ``` -Additionally the load-balancing within `kibe-vip` has two modes of operation: +**How it works!** -`bindToVip: false` - will result in every node in the cluster binding all load-balancer port(s) to all interfaces on the host itself +Once the `lb_enable` is set to true kube-vip will do the following: -`bindToVip: true` - The load-balancer will only **bind** to the VIP address. + - In Layer 2 it will create an IPVS service on the leader + - In Layer 3 all nodes will create an IPVS service + - It will start a Kubernetes node watcher for nodes with the control plane label + - It will add/delete them as they're added and removed from the cluster +#### Debugging control plane load-balancing -## Components within a Kubernetes Cluster + In order to inspect what is happening we will need to install the `ipvsadm` tool. -The `kube-vip` kubernetes load-balancer requires a number of components in order to function: +##### View the configuration -- The Plunder Cloud Provider -> [https://github.com/kube-vip/plndr-cloud-provider](https://github.com/kube-vip/plndr-cloud-provider) -- The Kube-Vip Deployment -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) +The command `sudo ipvsadm -ln` will display the load balancer configuration. -### Architecture overview - -![kubernetes-vip-architecture.png](kubernetes-vip-architecture.png) +``` + $ sudo ipvsadm -ln +IP Virtual Server version 1.2.1 (size=4096) +Prot LocalAddress:Port Scheduler Flags + -> RemoteAddress:Port Forward Weight ActiveConn InActConn +TCP 192.168.0.40:6443 rr + -> 192.168.0.41:6443 Local 1 4 0 + -> 192.168.0.42:6443 Local 1 3 0 + -> 192.168.0.43:6443 Local 1 3 0 +``` -### Plunder Cloud Provider +##### Watch things interact with the API server -The cloud provider works like all Kubernetes cloud providers and is built using the Kubernetes cloud-provider SDK. It's role is to provide the same cloud "like" services one would expect from services such as AWS / Azure / GCP etc.. in that when a user requests functionality then the cloud provider can speak natively to the underlying vendor and provision the required service +The command `watch sudo ipvsadm -lnc` will auto-refresh the connections to the load-balancer. -e.g. _In AWS when requesting a Kubernetes LoadBalancer, the cloud provider will provision an **ELB**_ +``` +$ watch sudo ipvsadm -lnc + +... + +sudo ipvsadm -lnc k8s01: Tue Nov 9 11:39:39 2021 + +IPVS connection entries +pro expire state source virtual destination +TCP 14:49 ESTABLISHED 192.168.0.42:37090 192.168.0.40:6443 192.168.0.41:6443 +TCP 14:55 ESTABLISHED 192.168.0.45:46510 192.168.0.40:6443 192.168.0.41:6443 +TCP 14:54 ESTABLISHED 192.168.0.43:39602 192.168.0.40:6443 192.168.0.43:6443 +TCP 14:58 ESTABLISHED 192.168.0.44:50458 192.168.0.40:6443 192.168.0.42:6443 +TCP 14:32 ESTABLISHED 192.168.0.43:39648 192.168.0.40:6443 192.168.0.42:6443 +TCP 14:58 ESTABLISHED 192.168.0.40:55944 192.168.0.40:6443 192.168.0.41:6443 +TCP 14:54 ESTABLISHED 192.168.0.42:36950 192.168.0.40:6443 192.168.0.41:6443 +TCP 14:42 ESTABLISHED 192.168.0.44:50488 192.168.0.40:6443 192.168.0.43:6443 +TCP 14:53 ESTABLISHED 192.168.0.45:46528 192.168.0.40:6443 192.168.0.43:6443 +TCP 14:49 ESTABLISHED 192.168.0.40:56040 192.168.0.40:6443 192.168.0.42:6443 +``` -The `Plunder cloud Provider` is *currently* only designed to intercept the creation of LoadBalancers and translate that into a `kube-vip` load balancer. +## Components within a Kubernetes Cluster -It is configured by a `configMap` within the `kube-system` namespace that contains the ranges of addresses that the other `kube-vip` load-balancers can use, it will also manage the allocation of addresses and then build the configMap configurations in these namespaces for consumption by `kube-vip`. The IP addresses for each namespace should be in the structure `cidr-` followed by the cidr range for the address pool. +The `kube-vip` kubernetes load-balancer requires a number of components in order to function: -**Example `ConfigMap`** +- The Kube-Vip Cloud Provider -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) +- The Kube-Vip Deployment -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) -``` -apiVersion: v1 -kind: ConfigMap -metadata: - name: plndr - namespace: kube-system -data: - cidr-default: 192.168.0.200/29 - cidr-plunder: 192.168.0.210/29 - cidr-testing: 192.168.0.220/29 -``` diff --git a/docs/flags/index.md b/docs/flags/index.md index df45e82c..519e9d95 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -18,6 +18,8 @@ These flags are typically used in manifest generation. | |`--address`|`` or ``|| | |`--interface`|``|| | |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| +| |`--enableLoadBalancer`|Enables IPVS load balancer|| +| |`--lbPort`|6443|The port that the api server will load-balanced on| |**Services**|||| | |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| |**Kubernetes**|||| @@ -66,6 +68,8 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | |`address`|`` or ``|| | |`vip_interface`|``|| | |`vip_leaderelection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| +| |`lb_enable`|Enables IPVS LoadBalancer|Will watch Kubernetes nodes and add them to the IPVS load-balancer| +| |`lb_port`|6443|The IPVS port that will be used to load-balance control plane requests| |**Services**|||| | |`vip_cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| |**LeaderElection**|||| diff --git a/docs/index.md b/docs/index.md index 62764183..facebd2a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -20,6 +20,7 @@ Kube-Vip was originally created to provide a HA solution for the Kubernetes cont - Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) - Control Plane HA with kubeadm (static Pods) - Control Plane HA with K3s/and others (daemonsets) +- Control Plane LoadBalancing with IPVS (kube-vip > 0.4) - Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2) - Service LoadBalancer using multiple nodes with BGP - Service LoadBalancer address pools per namespace or global diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 4d6c2a19..3bc17c51 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -38,6 +38,16 @@ This section only covers generating a simple *BGP* configuration, as the main fo ### Configure to use a container runtime +#### Get latest version + + We can parse the GitHub API to find the latest version (or we can set this manually) + +`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` + +or manually: + +`export KVVERSION=vx.x.x` + The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. #### containerd diff --git a/docs/install_static/index.md b/docs/install_static/index.md index b94b6cb7..d4686118 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -29,13 +29,23 @@ This section details creating a number of manifests for various use cases ## Configure to use a container runtime +### Get latest version + + We can parse the GitHub API to find the latest version (or we can set this manually) + +`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` + +or manually: + +`export KVVERSION=vx.x.x` + The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` ## ARP diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index fbb64609..eab30549 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -8,13 +8,23 @@ When deploying Kubernetes with Equinix Metal with the `--controlplane` functiona ## Configure to use a container runtime +### Get latest version + + We can parse the GitHub API to find the latest version (or we can set this manually) + +`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` + +or manually: + +`export KVVERSION=vx.x.x` + The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` ## Creating HA clusters in Equinix Metal diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 62cd61a8..78e57ade 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -48,11 +48,24 @@ curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee ## Step 3.2 Generate from container image + +### Get latest version + + We can parse the GitHub API to find the latest version (or we can set this manually) + +`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` + +or manually: + +`export KVVERSION=vx.x.x` + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + ### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.8 vip /kube-vip"` +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` ``` diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index 8d32c456..ce78959f 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -28,16 +28,23 @@ kubectl create configmap --namespace kube-system kubevip --from-literal range-gl ## Install kube-vip -Set the correct `alias` for `kube-vip` -``` -alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.8" -``` +### Get latest version -Install Kube-vip deamonset inside of KIND + We can parse the GitHub API to find the latest version (or we can set this manually) -``` -kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - -``` +`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` + +or manually: + +`export KVVERSION=vx.x.x` + +The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. + +### containerd +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` + +### Docker +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` ## Test diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index f2c0f362..a5aebb61 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -2,19 +2,6 @@ We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. -## Flow - -This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: - -1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` -3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. -4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. -6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. -7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. -8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. - ## CCM We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. @@ -24,7 +11,15 @@ We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anythin The below instructions *should just work* on Kubernetes regardless of architecture (Linux Operating System is the only requirement) - you can quickly install the "latest" components: -**Install the `kube-vip-cloud-provider`** +### Create the RBAC settings + +As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` + +### Install the `kube-vip-cloud-provider` ``` $ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml @@ -53,9 +48,15 @@ Creating services of `type: LoadBalancer` in *any namespace* will now take addre ## The Detailed guide -### Deploy the Kube-vip Cloud Provider +### Create the RBAC settings + +As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` -**Install the `kube-vip-cloud-provider`** +### Install the `kube-vip-cloud-provider` ``` $ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml From 4c1fd117d5d9f27773e08b0b5595e17578a1cd00 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 9 Nov 2021 12:53:41 +0000 Subject: [PATCH 173/542] Fix manifests and old generator --- docs/index.md | 2 +- docs/install_daemonset/index.md | 31 ++-- docs/install_static/index.md | 132 ++++++++++++++++++ docs/manifests/v0.3.9/kube-vip-arp-ds.yaml | 8 +- docs/manifests/v0.3.9/kube-vip-arp.yaml | 4 +- docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml | 4 +- docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml | 4 +- docs/manifests/v0.3.9/kube-vip-bgp.yaml | 10 +- docs/usage/kind/index.md | 6 + pkg/kubevip/config_envvar.go | 12 -- pkg/kubevip/config_generator.go | 83 ----------- 11 files changed, 169 insertions(+), 127 deletions(-) diff --git a/docs/index.md b/docs/index.md index facebd2a..afc5c016 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,7 +71,7 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we - The Kube-Vip Cloud Provider Repository -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) - The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) - +- The Kube-Vip RBAC (required for the daemonset) -> [https://kube-vip.io/manifests/rbac.yaml](https://kube-vip.io/manifests/rbac.yaml) ## Copyright © 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All right reserved diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 00d0b3e7..cb83ae07 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -50,11 +50,11 @@ or manually: The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. -#### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:v0.3.9 vip"` +### containerd +`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` -#### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:v0.3.9"` +### Docker +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` ### BGP Example @@ -64,7 +64,7 @@ This configuration will create a manifest that will start `kube-vip` providing * **Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. -**Note 2** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. +**Note 3** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. `export INTERFACE=lo` @@ -99,16 +99,26 @@ spec: labels: name: kube-vip-ds spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/master + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists containers: - args: - manager env: - name: vip_arp value: "false" - - name: vip_interface - value: lo - name: port value: "6443" + - name: vip_interface + value: ens192 - name: vip_cidr value: "32" - name: cp_enable @@ -132,7 +142,7 @@ spec: value: 192.168.0.10:65000::false,192.168.0.11:65000::false - name: vip_address value: 192.168.0.40 - image: 'ghcr.io/kube-vip/kube-vip:' + image: ghcr.io/kube-vip/kube-vip:v0.3.9 imagePullPolicy: Always name: kube-vip resources: {} @@ -143,12 +153,11 @@ spec: - NET_RAW - SYS_TIME hostNetwork: true - nodeSelector: - node-role.kubernetes.io/master: "true" serviceAccountName: kube-vip tolerations: - effect: NoSchedule - key: node-role.kubernetes.io/master + operator: Exists + - effect: NoExecute operator: Exists updateStrategy: {} status: diff --git a/docs/install_static/index.md b/docs/install_static/index.md index f3914b41..0670fd17 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -63,6 +63,71 @@ kube-vip manifest pod \ --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml ``` +### Example manifest + +``` +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: ens192 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.40 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} +``` + ## BGP This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. @@ -81,4 +146,71 @@ kube-vip manifest pod \ --localAS 65000 \ --bgpRouterID 192.168.0.2 \ --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml +``` + +### Example Manifest + +``` +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: ens192 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: bgp_enable + value: "true" + - name: bgp_routerid + value: 192.168.0.2 + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: bgp_peers + value: 192.168.0.10:65000::false,192.168.0.11:65000::false + - name: vip_address + value: 192.168.0.40 + image: ghcr.io/kube-vip/kube-vip:v0.3.9 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} ``` \ No newline at end of file diff --git a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml index 82328330..6707f2ab 100644 --- a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml +++ b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml @@ -20,10 +20,10 @@ spec: env: - name: vip_arp value: "true" - - name: vip_interface - value: eth0 - name: port value: "6443" + - name: vip_interface + value: eth0 - name: vip_cidr value: "32" - name: cp_enable @@ -54,10 +54,6 @@ spec: - NET_ADMIN - NET_RAW - SYS_TIME - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 hostNetwork: true serviceAccountName: kube-vip updateStrategy: {} diff --git a/docs/manifests/v0.3.9/kube-vip-arp.yaml b/docs/manifests/v0.3.9/kube-vip-arp.yaml index 17d0e3b2..a89e85aa 100644 --- a/docs/manifests/v0.3.9/kube-vip-arp.yaml +++ b/docs/manifests/v0.3.9/kube-vip-arp.yaml @@ -11,10 +11,10 @@ spec: env: - name: vip_arp value: "true" - - name: vip_interface - value: eth0 - name: port value: "6443" + - name: vip_interface + value: eth0 - name: vip_cidr value: "32" - name: cp_enable diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml index e7f977ce..b630984f 100644 --- a/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml +++ b/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml @@ -20,10 +20,10 @@ spec: env: - name: vip_arp value: "false" - - name: vip_interface - value: eth0 - name: port value: "6443" + - name: vip_interface + value: eth0 - name: vip_cidr value: "32" - name: cp_enable diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml index e13d519d..bb593623 100644 --- a/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml +++ b/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml @@ -20,10 +20,10 @@ spec: env: - name: vip_arp value: "false" - - name: vip_interface - value: eth0 - name: port value: "6443" + - name: vip_interface + value: eth0 - name: vip_cidr value: "32" - name: cp_enable diff --git a/docs/manifests/v0.3.9/kube-vip-bgp.yaml b/docs/manifests/v0.3.9/kube-vip-bgp.yaml index 5c9d78db..b60149f8 100644 --- a/docs/manifests/v0.3.9/kube-vip-bgp.yaml +++ b/docs/manifests/v0.3.9/kube-vip-bgp.yaml @@ -11,10 +11,10 @@ spec: env: - name: vip_arp value: "false" - - name: vip_interface - value: eth0 - name: port value: "6443" + - name: vip_interface + value: eth0 - name: vip_cidr value: "32" - name: cp_enable @@ -25,12 +25,6 @@ spec: value: "false" - name: svc_enable value: "true" - - name: vip_startleader - value: "false" - - name: vip_addpeerstolb - value: "true" - - name: vip_localpeer - value: code:192.168.0.22:10000 - name: bgp_enable value: "true" - name: bgp_routerid diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index ce78959f..f3915dd6 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -46,6 +46,12 @@ The easiest method to generate a manifest is using the container itself, below w ### Docker `alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` +## Deploy Kube-vip as a deamonset + +``` +kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - +``` + ## Test ``` diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index fb3e919f..d8481496 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -59,18 +59,6 @@ const ( //vipStartLeader - will start this instance as the leader of the cluster vipStartLeader = "vip_startleader" - //vipPeers defines the configuration of raft peer(s) - vipPeers = "vip_peers" - - //vipLocalPeer defines the configuration of the local raft peer - vipLocalPeer = "vip_localpeer" - - //vipRemotePeers defines the configuration of the local raft peer - // vipRemotePeers = "vip_remotepeers" - - //vipAddPeersToLB defines that RAFT peers should be added to the load-balancer - vipAddPeersToLB = "vip_addpeerstolb" - //vipPacket defines that the packet API will be used for EIP vipPacket = "vip_packet" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index c624abaf..c3ef4e51 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "strconv" - "strings" "github.com/ghodss/yaml" "github.com/kube-vip/kube-vip/pkg/bgp" @@ -196,50 +195,6 @@ func ParseEnvironment(c *Config) error { c.EnableARP = b } - //Removal of separate peer - env = os.Getenv(vipLocalPeer) - if env != "" { - // Parse the string in format :
: - peer, err := ParsePeerConfig(env) - if err != nil { - return err - } - c.LocalPeer = *peer - } - - env = os.Getenv(vipPeers) - if env != "" { - // TODO - perhaps make this optional? - // Remove existing peers - c.RemotePeers = []RaftPeer{} - - // Parse the remote peers (comma separated) - s := strings.Split(env, ",") - if len(s) == 0 { - return fmt.Errorf("The Remote Peer List [%s] is unable to be parsed, should be in comma separated format :
:", env) - } - for x := range s { - // Parse the each remote peer string in format :
: - peer, err := ParsePeerConfig(s[x]) - if err != nil { - return err - } - - c.RemotePeers = append(c.RemotePeers, *peer) - - } - } - - // Find Add Peers as Backends - env = os.Getenv(vipAddPeersToLB) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.AddPeersAsBackends = b - } - // BGP Server options env = os.Getenv(bgpEnable) if env != "" { @@ -497,23 +452,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newEnvironment = append(newEnvironment, leaderElection...) - } else { - // Generate Raft configuration - raft := []corev1.EnvVar{ - { - Name: vipStartLeader, - Value: strconv.FormatBool(c.StartAsLeader), - }, - { - Name: vipAddPeersToLB, - Value: strconv.FormatBool(c.AddPeersAsBackends), - }, - { - Name: vipLocalPeer, - Value: fmt.Sprintf("%s:%s:%d", c.LocalPeer.ID, c.LocalPeer.Address, c.LocalPeer.Port), - }, - } - newEnvironment = append(newEnvironment, raft...) } // If we're specifying an annotation configuration @@ -663,27 +601,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }) } - // Parse peers into a comma separated string - if len(c.RemotePeers) != 0 { - var peers string - for x := range c.RemotePeers { - if x != 0 { - peers = fmt.Sprintf("%s,%s:%s:%d", peers, c.RemotePeers[x].ID, c.RemotePeers[x].Address, c.RemotePeers[x].Port) - - } else { - peers = fmt.Sprintf("%s:%s:%d", c.RemotePeers[x].ID, c.RemotePeers[x].Address, c.RemotePeers[x].Port) - - } - //peers = fmt.Sprintf("%s,%s:%s:%d", peers, c.RemotePeers[x].ID, c.RemotePeers[x].Address, c.RemotePeers[x].Port) - //fmt.Sprintf("", peers) - } - peerEnvirontment := corev1.EnvVar{ - Name: vipPeers, - Value: peers, - } - newEnvironment = append(newEnvironment, peerEnvirontment) - } - newManifest := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", From 7b79084ae2ed97a0d1a32a90eb83da092ef4c048 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 9 Nov 2021 13:01:23 +0000 Subject: [PATCH 174/542] New release v0.4.0 --- Makefile | 4 +- cmd/kube-vip.go | 2 +- docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml | 69 +++++++++++++++ docs/manifests/v0.4.0/kube-vip-arp-ds.yaml | 65 ++++++++++++++ docs/manifests/v0.4.0/kube-vip-arp-lb.yaml | 65 ++++++++++++++ docs/manifests/v0.4.0/kube-vip-arp.yaml | 61 ++++++++++++++ docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml | 74 ++++++++++++++++ docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml | 84 +++++++++++++++++++ docs/manifests/v0.4.0/kube-vip-bgp.yaml | 62 ++++++++++++++ 9 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-arp-ds.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-arp-lb.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-arp.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml create mode 100644 docs/manifests/v0.4.0/kube-vip-bgp.yaml diff --git a/Makefile b/Makefile index bacb3933..bf4222ac 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.3.9 +VERSION := v0.4.0 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) @@ -97,8 +97,10 @@ manifests: @make build @mkdir -p ./docs/manifests/$(VERSION)/ @./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services > ./docs/manifests/$(VERSION)/kube-vip-arp.yaml + @./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --enableLoadBalancer > ./docs/manifests/$(VERSION)/kube-vip-arp-lb.yaml @./kube-vip manifest pod --interface eth0 --vip 192.168.0.1 --bgp --controlplane --services > ./docs/manifests/$(VERSION)/kube-vip-bgp.yaml @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster > ./docs/manifests/$(VERSION)/kube-vip-arp-ds.yaml + @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --arp --leaderElection --controlplane --services --inCluster --enableLoadBalancer > ./docs/manifests/$(VERSION)/kube-vip-arp-ds-lb.yaml @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster > ./docs/manifests/$(VERSION)/kube-vip-bgp-ds.yaml @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster --provider-config /etc/cloud-sa/cloud-sa.json > ./docs/manifests/$(VERSION)/kube-vip-bgp-em-ds.yaml @-rm ./kube-vip diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index edd6e6b6..0013344a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -71,7 +71,7 @@ func init() { // LoadBalancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS") - kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6444, "loadbalancer port for the VIP") + kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6443, "loadbalancer port for the VIP") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") diff --git a/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml b/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml new file mode 100644 index 00000000..7cadd030 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: lb_enable + value: "true" + - name: lb_port + value: "6443" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml b/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml new file mode 100644 index 00000000..00b1e2b1 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml b/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml new file mode 100644 index 00000000..7e8d8596 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml @@ -0,0 +1,65 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: lb_enable + value: "true" + - name: lb_port + value: "6443" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.4.0/kube-vip-arp.yaml b/docs/manifests/v0.4.0/kube-vip-arp.yaml new file mode 100644 index 00000000..6ce06718 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-arp.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml b/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml new file mode 100644 index 00000000..af9749a4 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml new file mode 100644 index 00000000..0472555c --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: provider_config + value: /etc/cloud-sa/cloud-sa.json + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/cloud-sa + name: cloud-sa-volume + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - name: cloud-sa-volume + secret: + secretName: metal-cloud-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.0/kube-vip-bgp.yaml b/docs/manifests/v0.4.0/kube-vip-bgp.yaml new file mode 100644 index 00000000..c7a1a367 --- /dev/null +++ b/docs/manifests/v0.4.0/kube-vip-bgp.yaml @@ -0,0 +1,62 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + From b11b9ba396044c9858162d2ce3991da137a511a0 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 10 Nov 2021 15:59:35 +0000 Subject: [PATCH 175/542] Allows setting an API server port --- pkg/cluster/clusterLeaderElection.go | 6 +++--- pkg/cluster/service.go | 2 +- pkg/loadbalancer/ipvs.go | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index c1038bef..38249fa7 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -231,7 +231,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * return nil } -func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer) error { +func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) 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") @@ -271,7 +271,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer) error { for x := range node.Status.Addresses { if node.Status.Addresses[x].Type == v1.NodeInternalIP { - err = lb.AddBackend(node.Status.Addresses[x].Address) + err = lb.AddBackend(node.Status.Addresses[x].Address, port) if err != nil { log.Errorf("Add IPVS backend [%v]", err) } @@ -287,7 +287,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer) error { for x := range node.Status.Addresses { if node.Status.Addresses[x].Type == v1.NodeInternalIP { - err = lb.AddBackend(node.Status.Addresses[x].Address) + err = lb.RemoveBackend(node.Status.Addresses[x].Address, port) if err != nil { log.Errorf("Del IPVS backend [%v]", err) } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 6cfada76..a2ab70b9 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -84,7 +84,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co } go func() { - err = sm.NodeWatcher(lb) + err = sm.NodeWatcher(lb, c.Port) if err != nil { log.Errorf("Error watching node labels [%s]", err) } diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index fb24fc53..58038567 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -87,10 +87,10 @@ func (lb *IPVSLoadBalancer) RemoveIPVSLB() error { } -func (lb *IPVSLoadBalancer) AddBackend(address string) error { +func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { dst := ipvs.Destination{ Address: ipvs.NewIP(net.ParseIP(address)), - Port: 6443, + Port: uint16(port), Family: ipvs.INET, Weight: 1, FwdMethod: ipvs.Local, @@ -105,10 +105,10 @@ func (lb *IPVSLoadBalancer) AddBackend(address string) error { return nil } -func (lb *IPVSLoadBalancer) RemoveBackend(address string) error { +func (lb *IPVSLoadBalancer) RemoveBackend(address string, port int) error { dst := ipvs.Destination{ Address: ipvs.NewIP(net.ParseIP(address)), - Port: 6443, + Port: uint16(port), Family: ipvs.INET, Weight: 1, } From f5a2bd8e59a175f23b39f457a028119261405b19 Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Sun, 21 Nov 2021 19:23:00 -0500 Subject: [PATCH 176/542] Extensive linting, corrections, expansions Signed-off-by: Chip Zoller --- docs/architecture/index.md | 22 ++--- docs/flags/index.md | 170 ++++++++++++++++---------------- docs/hybrid/index.md | 101 +++++++++---------- docs/index.md | 37 +++---- docs/install_daemonset/index.md | 20 ++-- docs/install_static/index.md | 76 +++++++------- docs/usage/on-prem/index.md | 148 ++++++++++----------------- 7 files changed, 270 insertions(+), 304 deletions(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index b59e7fcf..65c0b641 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -1,13 +1,13 @@ # **kube-vip** architecture -This section covers two parts of the architecture: +This section covers two parts of the architecture: 1. The technical capabilities of `kube-vip` 2. The components to build a load-balancing service within [Kubernetes](https://kubernetes.io) The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expanded to provide the same functionality for applications within a Kubernetes cluster. -Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`,`ppc64le`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). +Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`,`ppc64le`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). ## Technologies @@ -29,7 +29,7 @@ When the **vip** moves from one host to another any host that has been using the (Optional) The `kube-vip` can be configured to broadcast a [gratuitous arp](https://wiki.wireshark.org/Gratuitous_ARP) that will typically immediately notify all local hosts that the `vip <-> MAC` has changed. -**Below** we can see that the failover is typically done within a few seconds as the ARP broadcast is recieved. +**Below** we can see that the failover is typically done within a few seconds as the ARP broadcast is received. ``` 64 bytes from 192.168.0.75: icmp_seq=146 ttl=64 time=0.258 ms @@ -54,7 +54,7 @@ Request timeout for icmp_seq 150 ### Load Balancing -Kube-Vip has the capability to provide a HA address for both the Kubernetes control plane and for a Kubernetes service, it recently implemented support for "actual" load-balancing for the control plane to distribute API requests across control-plane nodes. +Kube-Vip has the capability to provide a HA address for both the Kubernetes control plane and for a Kubernetes service, it recently implemented support for "actual" load-balancing for the control plane to distribute API requests across control-plane nodes. #### Kubernetes Service Load-Balancing @@ -86,7 +86,8 @@ To enable control-plane load balancing, the following is required in the kube-vi - name : lb_enable value: "true" ``` -The load balancing is provided through IPVS (IP Virtual Server) and provides a layer-4 (TCP Port) based round-robin across all of the control plane nodes. By default the load balancer will listen on the default 6443 port as the Kubernetes API server. + +The load balancing is provided through IPVS (IP Virtual Server) and provides a layer-4 (TCP Port) based round-robin across all of the control plane nodes. By default the load balancer will listen on the default 6443 port as the Kubernetes API server. **Note:** The IPVS virtual server lives in kernel space and doesn't create an "actual" service that listens on port 6443, this allows the kernel to parse packets before they're sent to an actual TCP port. This is important to know because it means we don't have any port conflicts having the IPVS load-balancer listening on the same port as the API server on the same host. The load balancer port can be customised with the following snippet in the yaml. @@ -100,14 +101,14 @@ The load balancer port can be customised with the following snippet in the yaml. Once the `lb_enable` is set to true kube-vip will do the following: - - In Layer 2 it will create an IPVS service on the leader - - In Layer 3 all nodes will create an IPVS service - - It will start a Kubernetes node watcher for nodes with the control plane label - - It will add/delete them as they're added and removed from the cluster +- In Layer 2 it will create an IPVS service on the leader +- In Layer 3 all nodes will create an IPVS service +- It will start a Kubernetes node watcher for nodes with the control plane label +- It will add/delete them as they're added and removed from the cluster #### Debugging control plane load-balancing - In order to inspect what is happening we will need to install the `ipvsadm` tool. + In order to inspect what is happening we will need to install the `ipvsadm` tool. ##### View the configuration @@ -155,4 +156,3 @@ The `kube-vip` kubernetes load-balancer requires a number of components in order - The Kube-Vip Cloud Provider -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) - The Kube-Vip Deployment -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) - diff --git a/docs/flags/index.md b/docs/flags/index.md index 519e9d95..3766e7f2 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -2,95 +2,95 @@ ## Flags -These flags are typically used in manifest generation. +These flags are typically used in the `kube-vip` manifest generation process. -| Category | Flag | Usage | Notes | -|--------------|------|-------|-------| -|**Troubleshooting** |||| -| |`--log`|default 4|Set to `5` for debugging logs| -|**Mode** |||| -| |`--controlPlane`|Enables `kube-vip` control-plane functionality|| -| |`--services`|Enables `kube-vip` to watch services of type:LoadBalancer|| -|**Vip Config** |||| -| |`--arp`|Enables ARP brodcasts from Leader|| -| |`--bgp`|Enables BGP peering from `kube-vip`|| -| |`--vip`|``|(deprecated)| -| |`--address`|`` or ``|| -| |`--interface`|``|| -| |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| -| |`--enableLoadBalancer`|Enables IPVS load balancer|| -| |`--lbPort`|6443|The port that the api server will load-balanced on| -|**Services**|||| -| |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| -|**Kubernetes**|||| -| |`--inCluster`|Defaults to looking inside the Pod for the token|| -| |`--taint`|Enables a taint, stopping control plane daemonset being on workers|| -|**LeaderElection**|||| -| |`--leaseDuration`|default 5|Seconds a lease is held for| -| |`--leaseRenewDuration`|default 3|Seconds a leader can attempt to renew the lease| -| |`--leaseRetry`|default 1|Number of times the leader will hold the lease for| -| |`--namespace`|"kube-vip"|The namespace where the lease will reside| -|**BGP**|||| -| |`--bgpRouterID`|``|Typically the address of the local node| -| |`--localAS`|default 65000|The AS we peer from| -| |`--bgppeers`|``|Comma seperate list of BGP peers| -| |`--peerAddress`|``|Address of a single BGP Peer| -| |`--peerAS`|default 65000|AS of a single BGP Peer| -| |`--peerPass`|""| Password to work with a single BGP Peer| -| |`--multiHop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| -| |`--sourceif`|Source Interface| Determines which interface BGP should peer _from_| -| |`--sourceip`|Source Address| Determines which IP address BGP should peer _from_| -| |`--annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| -|**Equinix Metal**|||(May be deprecated)| -| |`--metal`|Enables Equinix Metal API calls|| -| |`--metalKey`|Equinix Metal API token|| -| |`--metalProject`|Equinix Metal Project (Name)|| -| |`--metalProjectID`|Equinix Metal Project (UUID)|| -| |`--provider-config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| +| Category | Flag | Usage | Notes | +| ------------------- | ---------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| **Troubleshooting** | | | | +| | `--log` | default 4 | Set to `5` for debugging logs | +| **Mode** | | | | +| | `--controlplane` | Enables `kube-vip` control plane functionality | | +| | `--services` | Enables `kube-vip` to watch services of type `LoadBalancer` | | +| **VIP Config** | | | | +| | `--arp` | Enables ARP broadcasts from Leader | | +| | `--bgp` | Enables BGP peering from `kube-vip` | | +| | `--vip` | `` | (deprecated) | +| | `--address` | `` or `` | | +| | `--interface` | `` | | +| | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | +| | `--enableLoadBalancer` | Enables IPVS load balancer | | +| | `--lbPort` | 6443 | The port that the api server will load-balanced on | +| **Services** | | | | +| | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | +| **Kubernetes** | | | | +| | `--inCluster` | Defaults to looking inside the Pod for the token | | +| | `--taint` | Enables a taint, stopping control plane DaemonSet being on workers | | +| **LeaderElection** | | | | +| | `--leaseDuration` | default 5 | Seconds a lease is held for | +| | `--leaseRenewDuration` | default 3 | Seconds a leader can attempt to renew the lease | +| | `--leaseRetry` | default 1 | Number of times the leader will hold the lease for | +| | `--namespace` | "kube-vip" | The namespace where the lease will reside | +| **BGP** | | | | +| | `--bgpRouterID` | `` | Typically the address of the local node | +| | `--localAS` | default 65000 | The AS we peer from | +| | `--bgppeers` | `` | Comma separated list of BGP peers | +| | `--peerAddress` | `` | Address of a single BGP Peer | +| | `--peerAS` | default 65000 | AS of a single BGP Peer | +| | `--peerPass` | "" | Password to work with a single BGP Peer | +| | `--multiHop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | +| | `--sourceif` | Source Interface | Determines which interface BGP should peer _from_ | +| | `--sourceip` | Source Address | Determines which IP address BGP should peer _from_ | +| | `--annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | +| **Equinix Metal** | | | (May be deprecated) | +| | `--metal` | Enables Equinix Metal API calls | | +| | `--metalKey` | Equinix Metal API token | | +| | `--metalProject` | Equinix Metal Project (Name) | | +| | `--metalProjectID` | Equinix Metal Project (UUID) | | +| | `--provider-config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | ## Environment Variables -These environment variables are usually part of a kube-vip manifest. +These environment variables are usually part of a `kube-vip` manifest and used when running the `kube-vip` Pod. More environment variables can be read through the `pkg/kubevip/config_envvar.go` file. -| Category | Environment Variable | Usage | Notes | -|--------------|------|-------|-------| -|**Troubleshooting** |||| -| |`vip_loglevel`|default 4|Set to `5` for debugging logs| -|**Mode** |||| -| |`cp_enable`|Enables `kube-vip` control-plane functionality|| -| |`svc_enable`|Enables `kube-vip` to watch services of `type:LoadBalancer`|| -|**Vip Config** |||| -| |`vip_arp`|Enables ARP brodcasts from Leader|| -| |`bgp_enable`|Enables BGP peering from `kube-vip`|| -| |`vip_address`|``|(deprecated)| -| |`address`|`` or ``|| -| |`vip_interface`|``|| -| |`vip_leaderelection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| -| |`lb_enable`|Enables IPVS LoadBalancer|Will watch Kubernetes nodes and add them to the IPVS load-balancer| -| |`lb_port`|6443|The IPVS port that will be used to load-balance control plane requests| -|**Services**|||| -| |`vip_cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| -|**LeaderElection**|||| -| |`vip_leaseduration`|default 5|Seconds a lease is held for| -| |`vip_renewdeadline`|default 3|Seconds a leader can attempt to renew the lease| -| |`vip_retryperiod`|default 1|Number of times the leader will hold the lease for| -| |`cp_namespace`|"kube-vip"|The namespace where the lease will reside| -|**BGP**|||| -| |`bgp_routerid`|``|Typically the address of the local node| -| |`bgp_as`|default 65000|The AS we peer from| -| |`bgp_peers`|``|Comma seperate list of BGP peers| -| |`bgp_peeraddress`|``|Address of a single BGP Peer| -| |`bgp_peeras`|default 65000|AS of a single BGP Peer| -| |`bgp_peerpass`|""| Password to work with a single BGP Peer| -| |`bgp_multihop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| -| |`bgp_sourceif`|Source Interface| Determines which interface BGP should peer _from_| -| |`bgp_sourceip`|Source Address| Determines which IP address BGP should peer _from_| -| |`annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| -|**Equinix Metal**|||(May be deprecated)| -| |`vip_packet`|Enables Equinix Metal API calls|| -| |`PACKET_AUTH_TOKEN`|Equinix Metal API token|| -| |`vip_packetproject`|Equinix Metal Project (Name)|| -| |`vip_packetprojectid`|Equinix Metal Project (UUID)|| -| |`provider_config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| \ No newline at end of file +| Category | Environment Variable | Usage | Notes | +| ------------------- | --------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------- | +| **Troubleshooting** | | | | +| | `vip_loglevel` | default 4 | Set to `5` for debugging logs | +| **Mode** | | | | +| | `cp_enable` | Enables `kube-vip` control plane functionality | | +| | `svc_enable` | Enables `kube-vip` to watch Services of type `LoadBalancer` | | +| **VIP Config** | | | | +| | `vip_arp` | Enables ARP broadcasts from Leader | | +| | `bgp_enable` | Enables BGP peering from `kube-vip` | | +| | `vip_address` | `` | (deprecated) | +| | `address` | `` or `` | | +| | `vip_interface` | `` | | +| | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | +| | `lb_enable` | Enables IPVS LoadBalancer | Will watch Kubernetes nodes and add them to the IPVS load-balancer | +| | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | +| **Services** | | | | +| | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | +| **LeaderElection** | | | | +| | `vip_leaseduration` | default 5 | Seconds a lease is held for | +| | `vip_renewdeadline` | default 3 | Seconds a leader can attempt to renew the lease | +| | `vip_retryperiod` | default 1 | Number of times the leader will hold the lease for | +| | `cp_namespace` | "kube-vip" | The namespace where the lease will reside | +| **BGP** | | | | +| | `bgp_routerid` | `` | Typically the address of the local node | +| | `bgp_as` | default 65000 | The AS we peer from | +| | `bgp_peers` | `` | Comma separated list of BGP peers | +| | `bgp_peeraddress` | `` | Address of a single BGP Peer | +| | `bgp_peeras` | default 65000 | AS of a single BGP Peer | +| | `bgp_peerpass` | "" | Password to work with a single BGP Peer | +| | `bgp_multihop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | +| | `bgp_sourceif` | Source Interface | Determines which interface BGP should peer _from_ | +| | `bgp_sourceip` | Source Address | Determines which IP address BGP should peer _from_ | +| | `annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | +| **Equinix Metal** | | | (May be deprecated) | +| | `vip_packet` | Enables Equinix Metal API calls | | +| | `PACKET_AUTH_TOKEN` | Equinix Metal API token | | +| | `vip_packetproject` | Equinix Metal Project (Name) | | +| | `vip_packetprojectid` | Equinix Metal Project (UUID) | | +| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | \ No newline at end of file diff --git a/docs/hybrid/index.md b/docs/hybrid/index.md index c1823e94..f83fbea9 100644 --- a/docs/hybrid/index.md +++ b/docs/hybrid/index.md @@ -1,45 +1,46 @@ -# Using `kube-vip` in Hybrid Mode +# Using kube-vip in Hybrid Mode We can deploy kube-vip in two different methods, which completely depends on your use-case and method for installing Kubernetes: - Static Pods (hybrid) - Daemonset (hybrid, requires taint) -## **Prerequisites** +## Prerequisites In order for `kube-vip` to be able to speak with the Kubernetes API server, we need to be able to resolve the hostname within the pod. In order to ensure this will work as expected the `/etc/hosts` file should have the `hostname` of the server within it. The `/etc/hosts` file is passed into the running container and will ensure that the pod isn't "confused" by any Kubernetes networking. ## Kubernetes Services (`type:LoadBalancer`) -To learn more about how `kube-vip` in hybrid works with the LoadBalancer services within a kubernetes cluster the documentation is [here](./services/). To get `kube-vip` deployed read on ! +To learn more about how `kube-vip` in hybrid works with the LoadBalancer services within a kubernetes cluster the documentation is [here](./services/). To get `kube-vip` deployed read on! ## Static Pods -Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. +Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. The sequence of events for this to work follows: + 1. Generate a `kube-vip` manifest in the static pods manifest folder 2. Run `kubeadm init`, this generates the manifests for the control plane and wait to connect to the VIP 3. The `kubelet` will parse and execute all manifest, including the `kube-vip` manifest 4. `kube-vip` starts and advertises our VIP -5. The `kubeadm init` finishes succesfully. +5. The `kubeadm init` finishes successfully. ## Daemonset Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a daemonset for all control plane nodes. -# Deploying `kube-vip` +## Deploying `kube-vip` The simplest method for generating the Kubernetes manifests is with `kube-vip` itself.. The subcommand `manifest pod|daemonset` can be used to generate specific types of Kubernetes manifests for use in a cluster. These subcommands can be configured with additional flags to enable/disable BGP/ARP/LeaderElection and a host of other options. Both Examples will use the same Architecture: -#### Infrastructure architecture +## Infrastructure architecture The infrastructure for our example HA Kubernetes cluster is as follows: -| Node | Address | -|----------------|------------| +| Node | Address | +| -------------- | --------- | | VIP | 10.0.0.40 | | controlPlane01 | 10.0.0.41 | | controlPlane02 | 10.0.0.42 | @@ -56,45 +57,45 @@ The details for creating a static pod are available [here](./static/) When using `kube-vip` as a daemonset the details are available [here](./daemonset/) -# Kube-Vip flag reference - -| Category | Flag | Usage | Notes | -|--------------|------|-------|-------| -|**Mode** |||| -| |`--controlPlane`|Enables `kube-vip` control-plane functionality|| -| |`--services`|Enables `kube-vip` to watch services of type:LoadBalancer|| -|**Vip Config** |||| -| |`--arp`|Enables ARP brodcasts from Leader|| -| |`--bgp`|Enables BGP peering from `kube-vip`|| -| |`--vip`|``|(deprecated)| -| |`--address`|`` or ``|| -| |`--interface`|``|| -| |`--leaderElection`|Enables Kubernetes LeaderElection|Used by ARP, as only the leader can broadcast| -|**Services**|||| -| |`--cidr`|Defaults "32"|Used when advertising BGP addresses (typically as `x.x.x.x/32`)| -|**Kubernetes**|||| -| |`--inCluster`|Defaults to looking inside the Pod for the token|| -| |`--taint`|Enables a taint, stopping control plane daemonset being on workers|| -|**LeaderElection**|||| -| |`--leaseDuration`|default 5|Seconds a lease is held for| -| |`--leaseRenewDuration`|default 3|Seconds a leader can attempt to renew the lease| -| |`--leaseRetry`|default 1|Number of times the leader will hold the lease for| -| |`--namespace`|"kube-vip"|The namespace where the lease will reside| -|**BGP**|||| -| |`--bgpRouterID`|``|Typically the address of the local node| -| |`--localAS`|default 65000|The AS we peer from| -| |`--bgppeers`|``|Comma seperate list of BGP peers| -| |`--peerAddress`|``|Address of a single BGP Peer| -| |`--peerAS`|default 65000|AS of a single BGP Peer| -| |`--peerPass`|""| Password to work with a single BGP Peer| -| |`--multiHop`|Enables eBGP MultiHop| Enable multiHop with a single BGP Peer| -| |`--annotaions`|``|Startup will be paused until the node annotaions contain the BGP configuration| -|**Equinix Metal**|||(May be deprecated)| -| |`--metal`|Enables Equinix Metal API calls|| -| |`--metalKey`|Equinix Metal API token|| -| |`--metalProject`|Equinix Metal Project (Name)|| -| |`--metalProjectID`|Equinix Metal Project (UUID)|| -| |`--provider-config`|Path to the Equinix Metal provider configuration|Requires the Equinix Metal CCM| +## Kube-Vip flag reference + +| Category | Flag | Usage | Notes | +| ------------------ | ---------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------- | +| **Mode** | | | | +| | `--controlPlane` | Enables `kube-vip` control-plane functionality | | +| | `--services` | Enables `kube-vip` to watch services of type:LoadBalancer | | +| **Vip Config** | | | | +| | `--arp` | Enables ARP broadcasts from Leader | | +| | `--bgp` | Enables BGP peering from `kube-vip` | | +| | `--vip` | `` | (deprecated) | +| | `--address` | `` or `` | | +| | `--interface` | `` | | +| | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | +| **Services** | | | | +| | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | +| **Kubernetes** | | | | +| | `--inCluster` | Defaults to looking inside the Pod for the token | | +| | `--taint` | Enables a taint, stopping control plane daemonset being on workers | | +| **LeaderElection** | | | | +| | `--leaseDuration` | default 5 | Seconds a lease is held for | +| | `--leaseRenewDuration` | default 3 | Seconds a leader can attempt to renew the lease | +| | `--leaseRetry` | default 1 | Number of times the leader will hold the lease for | +| | `--namespace` | "kube-vip" | The namespace where the lease will reside | +| **BGP** | | | | +| | `--bgpRouterID` | `` | Typically the address of the local node | +| | `--localAS` | default 65000 | The AS we peer from | +| | `--bgppeers` | `` | Comma separated list of BGP peers | +| | `--peerAddress` | `` | Address of a single BGP Peer | +| | `--peerAS` | default 65000 | AS of a single BGP Peer | +| | `--peerPass` | "" | Password to work with a single BGP Peer | +| | `--multiHop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | +| | `--annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | +| **Equinix Metal** | | | (May be deprecated) | +| | `--metal` | Enables Equinix Metal API calls | | +| | `--metalKey` | Equinix Metal API token | | +| | `--metalProject` | Equinix Metal Project (Name) | | +| | `--metalProjectID` | Equinix Metal Project (UUID) | | +| | `--provider-config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | ## Changelog @@ -112,7 +113,7 @@ Once DHCP returns an IP for the FQDN, the same `dnsUpdater` runs to periodically ## BGP Support (added in 0.1.8) -In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. +In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. The following new flags are used: @@ -128,7 +129,7 @@ If the `--bgp` flag is passed along with the Equinix Metal flags `metal, metalKe ## Equinix Metal Control Plane Support (added in 0.1.8) -Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Equinix Metal Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Equinix Metal account and create a EIP (either public or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Equinix Metal project we can now apply this address to the servers that live in the same project. +Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Equinix Metal Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Equinix Metal account and create a EIP (either public or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Equinix Metal project we can now apply this address to the servers that live in the same project. In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. diff --git a/docs/index.md b/docs/index.md index afc5c016..20ffcf7d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,45 +1,45 @@ ![kube-vip.png](kube-vip.png) ## Overview -Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services -The idea behind `kube-vip` is a small self-contained Highly-Available option for all environments, especially: +Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services. + +The idea behind `kube-vip` is a small, self-contained, highly-available option for all environments, especially: - Bare-Metal - On-Prem -- Edge (ARM / Raspberry PI) +- Edge (ARM / Raspberry Pi) - Virtualisation - Pretty much anywhere else :) ## Features -Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, over time it has evolved to incorporate that same functionality into Kubernetes service type [load-balancers](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). +Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, but over time it has evolved to incorporate that same functionality for Kubernetes Services of type [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). - VIP addresses can be both IPv4 or IPv6 - Control Plane with ARP (Layer 2) or BGP (Layer 3) - Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) - Control Plane HA with kubeadm (static Pods) -- Control Plane HA with K3s/and others (daemonsets) -- Control Plane LoadBalancing with IPVS (kube-vip > 0.4) +- Control Plane HA with K3s/and others (DaemonSets) +- Control Plane LoadBalancing with IPVS (kube-vip ≥ 0.4) - Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2) - Service LoadBalancer using multiple nodes with BGP - Service LoadBalancer address pools per namespace or global - Service LoadBalancer address via (existing network DHCP) -- Service LoadBalancer address exposure to gateway via UPNP -- ... manifest generation, vendor API integrations and many nore... +- Service LoadBalancer address exposure to gateway via UPnP +- ... manifest generation, vendor API integrations and many more... ## Why? -The "original" purpose of `kube-vip` was to simplify the building of HA Kubernetes clusters, which at this time can involve a few components and configurations that all need to be managed. This was blogged about in detail by [thebsdbox](https://twitter.com/thebsdbox/) here -> [https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing](https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing). As the project evolved it now can use those same technologies to provide load-balancing capabilities within a Kubernetes Cluster. - +The "original" purpose of `kube-vip` was to simplify the building of HA Kubernetes clusters, which at the time involved a few components and configurations that all needed to be managed. This was blogged about in detail by [thebsdbox](https://twitter.com/thebsdbox/) [here](https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing). Since the project has evolved, it can now use those same technologies to provide load balancing capabilities within a Kubernetes Cluster. ## Architecture -The architecture for `kube-vip` (and associated kubernetes components) is covered in detail [here](/architecture/) +The architecture for `kube-vip` (and associated Kubernetes components) is covered in detail [here](/architecture/). ## Installation -There are two main routes for deploying `kube-vip`, either through a [static pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [daemon set](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [k3s](https://k3s.io)). +There are two main routes for deploying `kube-vip`: either through a [static pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [K3s](https://k3s.io)). The infrastructure for our example HA Kubernetes cluster is as follows: @@ -51,10 +51,10 @@ The infrastructure for our example HA Kubernetes cluster is as follows: | controlPlane03 | 10.0.0.43 | | worker01 | 10.0.0.44 | -All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we only have one worker as we're going to use our controlPlanes in "hybrid" mode. +All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0. We only have one worker as we're going to use our control plane in "hybrid" mode. - [Static Pod](/install_static) -- [Daemon Set](/install_daemonset) +- [DaemonSet](/install_daemonset) ## Usage @@ -69,12 +69,13 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0, we ## Links -- The Kube-Vip Cloud Provider Repository -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) -- The Kube-Vip Repository -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) -- The Kube-Vip RBAC (required for the daemonset) -> [https://kube-vip.io/manifests/rbac.yaml](https://kube-vip.io/manifests/rbac.yaml) +- [Kube-Vip Cloud Provider Repository](https://github.com/kube-vip/kube-vip-cloud-provider) +- [Kube-Vip Repository](https://github.com/kube-vip/kube-vip) +- [Kube-Vip RBAC manifest (required for the DaemonSet)](https://kube-vip.io/manifests/rbac.yaml) + ## Copyright -© 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All right reserved +© 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index cb83ae07..a3bd5276 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -1,18 +1,18 @@ -# Kube-Vip as a daemonset +# Kube-Vip as a DaemonSet ## Daemonset -Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a daemonset for all control plane nodes. +Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a DaemonSet for all control plane nodes. -If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. +If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. -## Kube-Vip as **HA**, **Load-Balancer** or both ` ¯\_(ツ)_/¯` +## Kube-Vip as HA, Load Balancer, or both -When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. +When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. With both enabled `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. -**Note about Daemonsets** +**Note about DaemonSets** Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. @@ -28,7 +28,7 @@ kubectl apply -f https://kube-vip.io/manifests/rbac.yaml This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). -**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `daemonset` and NOT `pod`. +**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `DaemonSet` and NOT `pod`. ### Set configuration details @@ -38,7 +38,7 @@ This section only covers generating a simple *BGP* configuration, as the main fo ### Configure to use a container runtime -#### Get latest version +#### Get latest version We can parse the GitHub API to find the latest version (or we can set this manually) @@ -58,9 +58,9 @@ The easiest method to generate a manifest is using the container itself, below w ### BGP Example -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma separate list in the format of `address:AS:password:multihop`. **Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. diff --git a/docs/install_static/index.md b/docs/install_static/index.md index 0670fd17..89c29967 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -1,57 +1,67 @@ -# Kube-vip as a Static Pod +# Kube-Vip as a Static Pod ## Static Pods -Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. +[Static Pods](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) are Kubernetes Pods that are run by the `kubelet` on a single node and are not managed by the Kubernetes cluster itself. This means that whilst the Pod can appear within Kubernetes, it can't make use of a variety of Kubernetes functionality (such as the Kubernetes token or ConfigMap resources). The static Pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) as this is due to the sequence of actions performed by `kubeadm`. Ideally, we want `kube-vip` to be part of the Kubernetes cluster, but for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. -The sequence of events for this to work follows: -1. Generate a `kube-vip` manifest in the static pods manifest folder -2. Run `kubeadm init`, this generates the manifests for the control plane and wait to connect to the VIP -3. The `kubelet` will parse and execute all manifest, including the `kube-vip` manifest -4. `kube-vip` starts and advertises our VIP -5. The `kubeadm init` finishes succesfully. +The sequence of events for building a highly available Kubernetes cluster with `kubeadm` and `kube-vip` are as follows: -## Kube-Vip as **HA**, **Load-Balancer** or both ` ¯\_(ツ)_/¯` +1. Generate a `kube-vip` manifest in the static Pods manifest directory (see the [generating a manifest](#generating-a-manifest) section below). +2. Run `kubeadm init` with the `--control-plane-endpoint` flag using the VIP address provided when generating the static Pod manifest. +3. The `kubelet` will parse and execute all manifests, including the `kube-vip` manifest generated in step one and the other control plane components including `kube-apiserver`. +4. `kube-vip` starts and advertises the VIP address. +5. The `kubelet` on this first control plane will connect to the VIP advertised in the previous step. +6. `kubeadm init` finishes successfully on the first control plane. +7. Using the output from the `kubeadm init` command on the first control plane, run the `kubeadm join` command on the remainder of the control planes. +8. Copy the generated `kube-vip` manifest to the remainder of the control planes and place in their static Pods manifest directory (default of `/etc/kubernetes/manifests/`). -When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. +## Kube-Vip as HA, Load Balancer, or both -With both enabled `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Generating a Manifest -This section details creating a number of manifests for various use cases +In order to create an easier experience of consuming the various functionality within `kube-vip`, we can use the `kube-vip` container itself to generate our static Pod manifest. We do this by running the `kube-vip` image as a container and passing in the various [flags](/flags/) for the capabilities we want to enable. ### Set configuration details -`export VIP=192.168.0.40` +We use environment variables to predefine the values of the inputs to supply to `kube-vip`. + +Set the `VIP` address to be used for the control plane: -`export INTERFACE=` +`export VIP=192.168.0.40` -## Configure to use a container runtime +Set the `INTERFACE` name to the name of the interface on the control plane(s) which will announce the VIP. In many Linux distributions this can be found with the `ip a` command. -### Get latest version +`export INTERFACE=ens160` - We can parse the GitHub API to find the latest version (or we can set this manually) +Get the latest version of the `kube-vip` release by parsing the GitHub API. This step requires that `jq` and `curl` are installed. `KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` -or manually: +To set manually instead, find the desired [release tag](https://github.com/kube-vip/kube-vip/releases): + +`export KVVERSION=v0.4.0` -`export KVVERSION=vx.x.x` +### Creating the manifest -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. +With the input values now set, we can pull and run the `kube-vip` image supplying it the desired flags and values. Once the static Pod manifest is generated for your desired method (ARP or BGP), if running multiple control plane nodes, ensure it is placed in each control plane's static manifest directory (by default, `/etc/kubernetes/manifests`). + +Depending on the container runtime, use one of the two aliased commands to create a `kube-vip` command which runs the `kube-vip` image as a container. + +For containerd, run the below command: -### containerd `alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` -### Docker +For Docker, run the below command: + `alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` -## ARP +### ARP -This configuration will create a manifest that starts `kube-vip` providing **controlplane** and **services** management, using **leaderElection**. When this instance is elected as the leader it will bind the `vip` to the specified `interface`, this is also the same for services of `type:LoadBalancer`. +With the inputs and alias command set, we can run the `kube-vip` container to generate a static Pod manifest which will be directed to a file at `/etc/kubernetes/manifests/kube-vip.yaml`. As such, this is assumed to run on the first control plane node. -`export INTERFACE=eth0` +This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management using the `leaderElection` method and ARP. When this instance is elected as the leader, it will bind the `vip` to the specified `interface`. This is the same behavior for Services of type `LoadBalancer`. ``` kube-vip manifest pod \ @@ -60,10 +70,10 @@ kube-vip manifest pod \ --controlplane \ --services \ --arp \ - --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml + --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml ``` -### Example manifest +#### Example ARP Manifest ``` apiVersion: v1 @@ -128,11 +138,11 @@ spec: status: {} ``` -## BGP +### BGP -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. +This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management. Unlike ARP, all nodes in the BGP configuration will advertise virtual IP addresses. -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma-separated list in the format of `address:AS:password:multihop`. `export INTERFACE=lo` @@ -145,10 +155,10 @@ kube-vip manifest pod \ --bgp \ --localAS 65000 \ --bgpRouterID 192.168.0.2 \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml + --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml ``` -### Example Manifest +#### Example BGP Manifest ``` apiVersion: v1 @@ -213,4 +223,4 @@ spec: path: /etc/kubernetes/admin.conf name: kubeconfig status: {} -``` \ No newline at end of file +``` diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index a5aebb61..afafe84c 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -1,123 +1,81 @@ -# Kube-vip on-prem +# Kube-Vip On-Prem -We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. +We've designed `kube-vip` to be as decoupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes Services to the outside world and marking these Services as ready to use. -## CCM +## Cloud Controller Manager -We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. +`kube-vip` isn't coupled to anything other than the Kubernetes API and will only act upon an existing Kubernetes primitive (in this case the object of type `Service`). This makes it easy for existing [cloud controller managers (CCMs)](https://kubernetes.io/docs/concepts/architecture/cloud-controller/) to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load balancers to the outside world. +## Using the Kube-Vip Cloud Provider -## Using the Kube-vip Cloud Provider +The `kube-vip` cloud provider can be used to populate an IP address for Services of type `LoadBalancer` similar to what public cloud providers allow through a Kubernetes CCM. The below instructions *should just work* on Kubernetes regardless of the architecture (a Linux OS being the only requirement) and will install the latest components. -The below instructions *should just work* on Kubernetes regardless of architecture (Linux Operating System is the only requirement) - you can quickly install the "latest" components: +## Install the Kube-Vip Cloud Provider -### Create the RBAC settings - -As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` - -### Install the `kube-vip-cloud-provider` - -``` -$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml -``` - -It uses a `statefulSet` and can always be viewed with the following command: - -``` -kubectl describe pods -n kube-system kube-vip-cloud-provider-0 -``` - -**Create a global CIDR or IP Range** - -Any `service` in any `namespace` can use an address from the global CIDR `cidr-global` or range `range-global` +The `kube-vip` cloud provider can be installed from the latest release in the `main` branch by using the following command: ``` -kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29 +kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml ``` -or -``` -kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 -``` - -Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific - -## The Detailed guide +## Create a global CIDR or IP Range -### Create the RBAC settings - -As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` +In order for `kube-vip` to set an IP address for a Service of type `LoadBalancer`, it needs to have an availability of IP address to assign. This information is stored in a Kubernetes ConfigMap to which `kube-vip` has access. You control the scope of the IP allocations with the `key` within the ConfigMap. Either CIDR blocks or IP ranges may be specified and scoped either globally (cluster-side) or per-Namespace. -### Install the `kube-vip-cloud-provider` +To allow a global (cluster-wide) CIDR block which `kube-vip` can use to allocate an IP to Services of type `LoadBalancer` in any Namespace, create a ConfigMap named `kubevip` with the key `cidr-global` and value equal to a CIDR block available in your environment. For example, the below command creates a global CIDR with value `192.168.0.220/29` from which `kube-vip` will allocate IP addresses. ``` -$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +kubectl create configmap -n kube-system kubevip --from-literal cidr-global=192.168.0.220/29 ``` -The following output should appear when the manifest is applied: +To use a global range instead, create the key `range-global` with the value set to a valid range of IP addresses. For example, the below command creates a global range using the pool `192.168.1.220-192.168.1.230`. ``` -serviceaccount/kube-vip-cloud-controller created -clusterrole.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-role created -clusterrolebinding.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-binding created -statefulset.apps/kube-vip-cloud-provider created +kubectl create configmap -n kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 ``` -We can validate the cloud provider by examining the pods and following the logs: +Creating services of type `LoadBalancer` in any Namespace will now take addresses from one of the global pools defined in the ConfigMap unless a Namespace-specific pool is created. -``` -kubectl describe pods -n kube-system kube-vip-cloud-provider-0 -kubectl logs -n kube-system kube-vip-cloud-provider-0 -f -``` +### The Kube-Vip Cloud Provider ConfigMap -### The Kube-vip Cloud Provider `configmap` +To manage the IP address ranges for Services of type `LoadBalancer`, the `kube-vip-cloud-provider` uses a ConfigMap held in the `kube-system` Namespace. IP addresses can be configured using one or multiple formats: -To manage the IP address ranges for the load balancer instances the `kube-vip-cloud-provider` uses a `configmap` held in the `kube-system` namespace. IP address ranges can be configured using: -- IP address pools by CIDR +- CIDR blocks - IP ranges [start address - end address] -- Multiple pools by CIDR per namespace -- Multiple IP ranges per namespace (handles overlapping ranges) -- Setting of static addresses through --load-balancer-ip=x.x.x.x +- Multiple pools by CIDR per Namespace +- Multiple IP ranges per Namespace (handles overlapping ranges) +- Setting of static addresses through --load-balancer-ip=x.x.x.x (`kubectl expose` command) -To control which IP address range is used for which service the following rules are applied: -- Global address pools (`cidr-global` or `range-global`) are available for use by *any* `service` in *any* `namespace` -- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by `service` in the *specific* `namespace` -- Static IP addresses can be applied to a load balancer `service` using the `loadbalancerIP` setting, even outside of the assigned ranges +To control which IP address range is used for which Service, the following rules are applied: -Example Configmap: +- Global address pools (`cidr-global` or `range-global`) are available for use by *any* Service in *any* Namespace +- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by a Service in the *specific* Namespace +- Static IP addresses can be applied to a Service of type `LoadBalancer` using the `spec.loadBalancerIP` field, even outside of the assigned ranges -``` -$ kubectl get configmap -n kube-system kubevip -o yaml +Example Configmap: +```yaml apiVersion: v1 kind: ConfigMap metadata: name: kubevip namespace: kube-system data: - cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default namespace - range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development namespace - cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance namespace - cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any namespace + cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default Namespace + range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development Namespace + cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance Namespace + cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any Namespace ``` -### Expose a service +### Expose a Service -We can now expose a service and once the cloud provider has provided an address `kube-vip` will start to advertise that address to the outside world as shown below! +We can now expose a Service and once the cloud provider has provided an address, `kube-vip` will start to advertise that address to the outside world as shown below: ``` kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx ``` -or via a `service` YAML definition +or via a Service YAML definition: ``` apiVersion: v1 @@ -134,14 +92,13 @@ spec: type: LoadBalancer ``` - -We can also expose a specific address by specifying it on the command line: +We can also expose a specific address by specifying it imperatively on the command line: ``` kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 ``` -or including it in the `service` definition: +or including it in the Service definition: ``` apiVersion: v1 @@ -161,14 +118,12 @@ spec: ### Using DHCP for Load Balancers (experimental) -With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a - Kubernetes service on the network. +With `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load balancer address that can be used to access a Kubernetes service on the network. -In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the -address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! +In order to do this, we need to signify to `kube-vip` and the cloud provider that we don't need one of their managed addresses. We do this by explicitly exposing a Service on the address `0.0.0.0`. When `kube-vip` sees a Service on this address, it will create a `macvlan` interface on the host and request a DHCP address. Once this address is provided, it will assign it as the `LoadBalancer` IP and update the Kubernetes Service. ``` -$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc +$ kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; kubectl get svc service/nginx-dhcp exposed NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 17m @@ -176,44 +131,43 @@ nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s { ... a second or so later ... } -$ k get svc +$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 17m nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s ``` -### Using UPNP to expose a service to the outside world +### Using UPnP to expose a Service to the outside world -With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the inte -rnet. +With `kube-vip` > 0.2.1, it is possible to expose a Service of type `LoadBalancer` on a specific port to the Internet by using UPnP (on a supported gateway). Most simple networks look something like the following: `<----- ----> Internet` -Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. +Using UPnP we can create a matching port on the `` allowing your Service to be exposed to the Internet. -#### Enable UPNP +#### Enable UPnP -Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. +Add the following to the `kube-vip` `env:` section of either the static Pod or DaemonSet for `kube-vip`, and the rest should be completely automated. -**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) +**Note** some environments may require (Unifi) `Secure mode` being `disabled` (this allows a host with a different address to register a port). ``` - name: enableUPNP value: "true" ``` -#### Exposing a service +#### Exposing a Service -To expose a port successfully we'll need to change the command slightly: +To expose a port successfully, we'll need to change the command slightly: `--target-port=80` the port of the application in the pods (HTT/NGINX) -`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) +`--port=32380` the port the Service will be exposed on (and what you should connect to in order to receive traffic from the Service) `kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` -The above example should expose a port on your external (internet facing address), that can be tested externally with: +The above example should expose a port on your external (Internet facing) address that can be tested externally with: ``` $ curl externalIP:32380 From a377b6e2a8fa586dfde12f34c8099f8671b121f3 Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Sun, 21 Nov 2021 19:32:04 -0500 Subject: [PATCH 177/542] linting, typos Signed-off-by: Chip Zoller --- ROADMAP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index d83a539e..7f934019 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,10 +1,10 @@ # Kube-Vip Roadmap -This document outlines the roadmap for the **kube-vip** project and only covers the technologies within this particular project, other projects that augment or provide additional functionality (such as cloud-providers) may have their own roadmaps in future. The functionality for **kube-vip** has grown either been developed organically or through real-world needs, and this is the first attempt to put into words a plan for the future of **kube-vip** and will additional evolve over time. This means that items listed or detailed here are not neccessarily set in stone and the roadmap can grow/shrink as the project matures. We definitely welcome suggestions and ideas from everyone about the roadmap and **kube-vip** features. Reach us through Issues, Slack or email @kube-vip.io. - +This document outlines the roadmap for the **kube-vip** project and only covers the technologies within this particular project, other projects that augment or provide additional functionality (such as cloud-providers) may have their own roadmaps in future. The functionality for **kube-vip** has grown either been developed organically or through real-world needs, and this is the first attempt to put into words a plan for the future of **kube-vip** and will additional evolve over time. This means that items listed or detailed here are not necessarily set in stone and the roadmap can grow/shrink as the project matures. We definitely welcome suggestions and ideas from everyone about the roadmap and **kube-vip** features. Reach us through Issues, Slack or email @kube-vip.io. + ## Release methodology -The **kube-vip** project attempts to follow a tick-tock release cycle, this typically means that one release will come **packed** with new features where the following release will come with fixes, code sanitation and performane enhancements. +The **kube-vip** project attempts to follow a tick-tock release cycle, this typically means that one release will come **packed** with new features where the following release will come with fixes, code sanitation and performance enhancements. ## Roadmap @@ -13,12 +13,12 @@ The **kube-vip** project offers two main areas of functionality: - HA Kubernetes clusters through a control-plane VIP - Kubernetes `service type:LoadBalancer` -Whilst both of these functions share underlying technologies and code they will have slightly differening roadmaps. +Whilst both of these functions share underlying technologies and code they will have slightly differing roadmaps. ### HA Kubernetes Control Plane -- **Re-implememt LoadBalancing** - due to a previous request the HTTP loadbalancing was removed leaving just HA for the control plane. This functionality will be re-implemented either through the original round-robin HTTP requests or utilising IPVS. -- **Utilise the Kubernetes API to determine additional Control Plane members** - Once a single node cluster is running **kube-vip** could use the API to determine the additional members, at this time a Cluster-API provider needs to drop a static manifest per CP node. +- **Re-implement LoadBalancing** - due to a previous request the HTTP loadbalancing was removed leaving just HA for the control plane. This functionality will be re-implemented either through the original round-robin HTTP requests or utilising IPVS. +- **Utilise the Kubernetes API to determine additional Control Plane members** - Once a single node cluster is running **kube-vip** could use the API to determine the additional members, at this time a Cluster-API provider needs to drop a static manifest per CP node. - **Re-evaluate raft** - **kube-vip** is mainly designed to run within a Kubernetes cluster, however it's original design was a raft cluster external to Kubernetes. Unfortunately given some of the upgrade paths identified in things like CAPV moving to leaderElection within Kubernetes became a better idea. ## Kubernetes `service type:LoadBalancer` @@ -29,7 +29,7 @@ Whilst both of these functions share underlying technologies and code they will ## Global **Kube-Vip** items - **Improved metrics** - At this time the scaffolding for monitoring exists, however this needs drastically extending to provide greater observability to what is happening within **kube-vip** -- **Windows support** - The Go SDK didn't support the capability for low-levels sockets for ARP originally, this should be revisted. +- **Windows support** - The Go SDK didn't support the capability for low-levels sockets for ARP originally, this should be revisited. - **Additional BGP features** : - Communities - BFD From 31e4958c99b8ab5bdff16626e7fab241691ac8fc Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Sun, 21 Nov 2021 19:39:17 -0500 Subject: [PATCH 178/542] linting Signed-off-by: Chip Zoller --- docs/usage/kind/index.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index f3915dd6..5321c830 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -2,7 +2,7 @@ ## Deploying KIND -The documentation for KIND is fantastic and it's quickstart guide will have you up and running in no time -> [https://kind.sigs.k8s.io/docs/user/quick-start/](https://kind.sigs.k8s.io/docs/user/quick-start/) +The documentation for KIND is fantastic and its [quick start](https://kind.sigs.k8s.io/docs/user/quick-start/) guide will have you up and running in no time. ## Find Address Pool for Kube-Vip @@ -12,12 +12,12 @@ We will need to find addresses that can be used by Kube-Vip: docker network inspect kind -f '{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}' ``` -This will return a cidr range such as `172.18.0.0/16` and from here we can select a range. +This will return a CIDR range such as `172.18.0.0/16` and from here we can select a range. ## Deploy the Kube-Vip Cloud Controller ``` -$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml +kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml ``` ## Add our Address range @@ -28,9 +28,9 @@ kubectl create configmap --namespace kube-system kubevip --from-literal range-gl ## Install kube-vip -### Get latest version +### Get latest version - We can parse the GitHub API to find the latest version (or we can set this manually) +We can parse the GitHub API to find the latest version (or we can set this manually) `KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` @@ -41,12 +41,14 @@ or manually: The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. ### containerd + `alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` ### Docker + `alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` -## Deploy Kube-vip as a deamonset +## Deploy Kube-vip as a DaemonSet ``` kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - @@ -67,4 +69,4 @@ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 74m nginx LoadBalancer 10.96.196.235 172.18.100.11 80:31236/TCP 6s -``` \ No newline at end of file +``` From 2ec0510a371fffc119df6cd24671d088faa49e5a Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Sun, 21 Nov 2021 20:01:31 -0500 Subject: [PATCH 179/542] more linting Signed-off-by: Chip Zoller --- docs/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index 20ffcf7d..c6805114 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,19 +2,19 @@ ## Overview -Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services. +Kube-Vip provides Kubernetes clusters a virtual IP and load balancer for both control plane and Kubernetes Services. The idea behind `kube-vip` is a small, self-contained, highly-available option for all environments, especially: -- Bare-Metal -- On-Prem +- Bare metal +- On-Premises - Edge (ARM / Raspberry Pi) - Virtualisation - Pretty much anywhere else :) ## Features -Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, but over time it has evolved to incorporate that same functionality for Kubernetes Services of type [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). +Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, but over time it has evolved to incorporate that same functionality for Kubernetes Services of type [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). Some of the features include: - VIP addresses can be both IPv4 or IPv6 - Control Plane with ARP (Layer 2) or BGP (Layer 3) From f5e8e052718be3096542a11fe1e86d821db0097c Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Mon, 22 Nov 2021 09:17:17 -0500 Subject: [PATCH 180/542] more work Signed-off-by: Chip Zoller --- docs/flags/index.md | 11 +- docs/install_daemonset/index.md | 185 ++++++++++++++++++++++---------- docs/install_static/index.md | 2 + 3 files changed, 134 insertions(+), 64 deletions(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 3766e7f2..4c086bde 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -16,15 +16,15 @@ These flags are typically used in the `kube-vip` manifest generation process. | | `--bgp` | Enables BGP peering from `kube-vip` | | | | `--vip` | `` | (deprecated) | | | `--address` | `` or `` | | -| | `--interface` | `` | | +| | `--interface` | Linux interface on the node | | | | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| | `--enableLoadBalancer` | Enables IPVS load balancer | | +| | `--enableLoadBalancer` | Enables IPVS load balancer | `kube-vip` ≥ 0.4.0 | | | `--lbPort` | 6443 | The port that the api server will load-balanced on | | **Services** | | | | | | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | | **Kubernetes** | | | | -| | `--inCluster` | Defaults to looking inside the Pod for the token | | -| | `--taint` | Enables a taint, stopping control plane DaemonSet being on workers | | +| | `--inCluster` | Required for `kube-vip` as DaemonSet. | Runs `kube-vip` with a ServiceAccount called `kube-vip`. | +| | `--taint` | Required for `kube-vip` as DaemonSet. | Adds node affinity rules forcing `kube-vip` Pods to run on control plane. | | **LeaderElection** | | | | | | `--leaseDuration` | default 5 | Seconds a lease is held for | | | `--leaseRenewDuration` | default 3 | Seconds a leader can attempt to renew the lease | @@ -79,6 +79,7 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `cp_namespace` | "kube-vip" | The namespace where the lease will reside | | **BGP** | | | | | | `bgp_routerid` | `` | Typically the address of the local node | +| | `bgp_routerinterface` | Interface name | Used to associate the `routerID` with the control plane's interface. | | | `bgp_as` | default 65000 | The AS we peer from | | | `bgp_peers` | `` | Comma separated list of BGP peers | | | `bgp_peeraddress` | `` | Address of a single BGP Peer | @@ -93,4 +94,4 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `PACKET_AUTH_TOKEN` | Equinix Metal API token | | | | `vip_packetproject` | Equinix Metal Project (Name) | | | | `vip_packetprojectid` | Equinix Metal Project (UUID) | | -| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | \ No newline at end of file +| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index a3bd5276..37edf483 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -1,24 +1,20 @@ # Kube-Vip as a DaemonSet -## Daemonset +## DaemonSet -Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a DaemonSet for all control plane nodes. +Some Kubernetes distributions can bring up a Kubernetes cluster without depending on a pre-existing VIP (but they may be configured to support one). A prime example of this would be K3s which can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist before the cluster, we can bring up the K3s node(s) and then add `kube-vip` as a DaemonSet for all control plane nodes. -If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. +If the Kubernetes installer allows for adding a virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate, we can apply `kube-vip` to the cluster once the first node has been brought up. -## Kube-Vip as HA, Load Balancer, or both - -When generating a manifest for `kube-vip` we will pass in the flags `--controlplane` / `--services` these will enable the various types of functionality within `kube-vip`. +Unlike running `kube-vip` as a [static Pod](/install_static) there are a few more things that may need configuring when running `kube-vip` as a DaemonSet. This page will cover primarily the differences. -With both enabled `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. - -**Note about DaemonSets** +## Kube-Vip as HA, Load Balancer, or both -Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Create the RBAC settings -As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: +Since `kube-vip` as a DaemonSet runs as a regular resource instead of a static Pod, it still needs the correct access to be able to watch Kubernetes Services and other objects. In order to do this, RBAC resources must be created which include a ServiceAccount, ClusterRole, and ClusterRoleBinding and can be applied this with the command: ``` kubectl apply -f https://kube-vip.io/manifests/rbac.yaml @@ -26,45 +22,113 @@ kubectl apply -f https://kube-vip.io/manifests/rbac.yaml ## Generating a Manifest -This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). - -**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `DaemonSet` and NOT `pod`. - -### Set configuration details - -`export VIP=192.168.0.40` - -`export INTERFACE=` - -### Configure to use a container runtime - -#### Get latest version - - We can parse the GitHub API to find the latest version (or we can set this manually) - -`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` - -or manually: +In order to create an easier experience of consuming the various functionality within `kube-vip`, we can use the `kube-vip` container itself to generate our DaemonSet manifest. We do this by running the `kube-vip` image as a container and passing in the various [flags](/flags/) for the capabilities we want to enable. Generating a `kube-vip` manifest for running as a DaemonSet is almost identical to the process when running `kube-vip` as a [static Pod](/install_static). Only a few flags are different between the two processes. Therefore, refer back to the [Generating a Manifest](/install_static/#generating-a-manifest) section on the [static Pod installation page](/install_static) for the main process steps. -`export KVVERSION=vx.x.x` +### ARP Example for DaemonSet -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. +When creating the `kube-vip` installation manifest as a DaemonSet, the `manifest` subcommand takes the value `daemonset` as opposed to the `pod` value. The flags `--inCluster` and `--taint` are also needed to configure the DaemonSet to use a ServiceAccount and affine the `kube-vip` Pods to control plane nodes thereby preventing them from running on worker instances. -### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` - -### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` +``` +kube-vip manifest daemonset \ + --interface $INTERFACE \ + --vip $VIP \ + --inCluster \ + --taint \ + --controlplane \ + --services \ + --arp \ + --leaderElection +``` -### BGP Example +#### Example ARP Manifest -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. +```yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/master + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: ens160 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.40 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_TIME + hostNetwork: true + serviceAccountName: kube-vip + tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 +``` -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma separate list in the format of `address:AS:password:multihop`. +### BGP Example for DaemonSet -**Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. +This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management. Unlike ARP, all nodes in the BGP configuration will advertise virtual IP addresses. -**Note 3** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. +**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma-separated list in the format of `address:AS:password:multihop`. `export INTERFACE=lo` @@ -72,17 +136,20 @@ This configuration will create a manifest that will start `kube-vip` providing * kube-vip manifest daemonset \ --interface $INTERFACE \ --vip $VIP \ - --controlplane \ - --services \ --inCluster \ --taint \ + --controlplane \ + --services \ --bgp \ + --localAS 65000 \ + --bgpRouterID 192.168.0.2 \ --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false + ``` -### Generated Manifest +#### Example BGP Manifest -``` +```yaml apiVersion: apps/v1 kind: DaemonSet metadata: @@ -118,7 +185,7 @@ spec: - name: port value: "6443" - name: vip_interface - value: ens192 + value: ens160 - name: vip_cidr value: "32" - name: cp_enable @@ -132,6 +199,7 @@ spec: - name: bgp_enable value: "true" - name: bgp_routerid + value: 192.168.0.2 - name: bgp_as value: "65000" - name: bgp_peeraddress @@ -142,7 +210,7 @@ spec: value: 192.168.0.10:65000::false,192.168.0.11:65000::false - name: vip_address value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 imagePullPolicy: Always name: kube-vip resources: {} @@ -167,20 +235,19 @@ status: numberReady: 0 ``` -### Managing a `routerID` as a daemonset +#### Managing a `routerID` as a DaemonSet -The routerID needs to be unique on each node that participates in BGP advertisements. In order to do this we can modify the manifest so that when `kube-vip` starts it will look up its local address and use that as the routerID. +The `routerID` needs to be unique on each node that participates in BGP advertisements. In order to do this, we can modify the manifest so that when `kube-vip` starts it will look up its local address and use that as the `routerID`. Add the following to the `env[]` array of the container: -``` - - name: bgp_routerinterface - value: "ens160" +```yaml +- name: bgp_routerinterface + value: "ens160" ``` -This will instruct each instance of `kube-vip` as part of the daemonset to look up the IP address on that interface and use it as the routerID. +### DaemonSet Manifest Overview -### Manifest Overview +Once the manifest for `kube-vip` as a DaemonSet is generated, these are some of the notable differences over the [static Pod](/install_static) manifest and their significance. -- `nodeSelector` - Ensures that this particular daemonset only runs on control plane nodes -- `serviceAccountName: kube-vip` - this specifies the user in the `rbac` that will give us the permissions to get/update services. -- `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) -- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. +- `nodeSelector`: Ensures that DaemonSet Pods only run on control plane nodes. +- `serviceAccountName: kube-vip`: Specifies the ServiceAccount name that will be used to get/update Kubernetes Service resources. +- `tolerations`: Allows scheduling to control plane nodes that normally specify `NoSchedule` or `NoExecute` taints. diff --git a/docs/install_static/index.md b/docs/install_static/index.md index 89c29967..bdf0a283 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -63,6 +63,8 @@ With the inputs and alias command set, we can run the `kube-vip` container to ge This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management using the `leaderElection` method and ARP. When this instance is elected as the leader, it will bind the `vip` to the specified `interface`. This is the same behavior for Services of type `LoadBalancer`. +> Note: When running these commands on a to-be control plane node, `sudo` access may be required along with pre-creation of the `/etc/kubernetes/manifests/` directory. + ``` kube-vip manifest pod \ --interface $INTERFACE \ From c1c9635bf4bd1567e40694bfd91a99c8ba51a1b2 Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Mon, 22 Nov 2021 10:06:25 -0500 Subject: [PATCH 181/542] updates Signed-off-by: Chip Zoller --- docs/architecture/index.md | 123 ++++++++++++++++++------------------- docs/flags/index.md | 2 +- docs/index.md | 16 +---- 3 files changed, 64 insertions(+), 77 deletions(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 65c0b641..f8030074 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -1,52 +1,52 @@ -# **kube-vip** architecture +# Kube-Vip Architecture This section covers two parts of the architecture: -1. The technical capabilities of `kube-vip` -2. The components to build a load-balancing service within [Kubernetes](https://kubernetes.io) +1. The technical capabilities of `kube-vip`. +2. The components to build a load balancing service within Kubernetes. -The `kube-vip` project is designed to provide both a highly available networking endpoint and load-balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control-plane for Kubernetes, it has since expanded to provide the same functionality for applications within a Kubernetes cluster. +The `kube-vip` project is designed to provide both a highly available networking endpoint and load balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control plane for Kubernetes but has since expanded to provide the same functionality for Service resources within a Kubernetes cluster. -Additionally `kube-vip` is designed to be lightweight and **multi-architecture**, all of the components are built for Linux but are also built for both `x86` and `armv7`,`armhvf`,`ppc64le`. This means that `kube-vip` will run fine in **bare-metal**, **virtual** and **edge** (raspberry pi or small arm SoC devices). +Additionally, `kube-vip` is designed to be lightweight and multi-architecture. All of the components are built for Linux on `x86`, `armv7`, `armhvf`, and `ppc64le` architectures. This means that `kube-vip` will run fine in bare metal, virtual, and edge (Raspberry Pi or small ARM SoC) use cases. ## Technologies -There are a number of technologies or functional design choices that provide high-availability or networking functions as part of a VIP/Load-balancing solution. +There are a number of technologies or functional design choices that provide high availability and networking functions as part of a VIP/load balancing solution. ### Cluster -The `kube-vip` service builds a multi-node or multi-pod cluster to provide High-Availability. In ARP mode a leader is elected, this node will inherit the Virtual IP and become the leader of the load-balancing within the cluster, whereas with BGP all nodes will advertise the VIP address. +The `kube-vip` service builds a multi-node or multi-pod cluster to provide high availability. In ARP mode, a leader is elected which will inherit the virtual IP and become the leader of the load balancing within the cluster whereas with BGP all nodes will advertise the VIP address. -When using ARP or layer2 it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) +When using ARP or [Layer 2](https://osi-model.com/data-link-layer/) it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection). ### Virtual IP -The leader within the cluster will assume the **vip** and will have it bound to the selected interface that is declared within the configuration. When the leader changes it will evacuate the **vip** first or in failure scenarios the **vip** will be directly assumed by the next elected leader. +The leader within the cluster will assume the VIP and will have it bound to the selected interface that is declared within the configuration. When the leader changes, it will evacuate the VIP first or in failure scenarios the VIP will be directly assumed by the next elected leader. -When the **vip** moves from one host to another any host that has been using the **vip** will retain the previous `vip <-> MAC address` mapping until the ARP (Address resolution protocol) expires the old entry (typically 30 seconds) and retrieves a new `vip <-> MAC` mapping. This can be improved using Gratuitous ARP broadcasts (when enabled), this is detailed below. +When the VIP moves from one host to another, any host that has been using the VIP will retain the previous VIP-to-MAC address mapping until the old ARP entry expires (typically within 30 seconds) and retrieves a new mapping. This can be improved by using [Gratuitous ARP](https://wiki.wireshark.org/Gratuitous_ARP) broadcasts when enabled (detailed below). ### ARP -(Optional) The `kube-vip` can be configured to broadcast a [gratuitous arp](https://wiki.wireshark.org/Gratuitous_ARP) that will typically immediately notify all local hosts that the `vip <-> MAC` has changed. +`kube-vip` can optionally be configured to broadcast a Gratuitous ARP that will typically immediately notify all local hosts that the VIP-to-MAC address mapping has changed. -**Below** we can see that the failover is typically done within a few seconds as the ARP broadcast is received. +Below we can see that the failover is typically done within a few seconds as the ARP broadcast is received. ``` 64 bytes from 192.168.0.75: icmp_seq=146 ttl=64 time=0.258 ms 64 bytes from 192.168.0.75: icmp_seq=147 ttl=64 time=0.240 ms 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst - 4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 +4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 148 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst - 4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 +4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 149 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst - 4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 +4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 150 64 bytes from 192.168.0.75: icmp_seq=151 ttl=64 time=0.245 ms @@ -54,85 +54,84 @@ Request timeout for icmp_seq 150 ### Load Balancing -Kube-Vip has the capability to provide a HA address for both the Kubernetes control plane and for a Kubernetes service, it recently implemented support for "actual" load-balancing for the control plane to distribute API requests across control-plane nodes. +`kube-vip` has the capability to provide a high availability address for both the Kubernetes control plane and for a Kubernetes Service. As of v0.4.0, `kube-vip` implements support for true load balancing for the control plane to distribute API requests across control plane nodes. -#### Kubernetes Service Load-Balancing +#### Kubernetes Service Load Balancing -The following is required in the kube-vip yaml to enable services: +The following is required in the `kube-vip` manifest to enable Service of type `LoadBalancer`: -``` - - name: svc_enable - value: "true" +```yaml +- name: svc_enable + value: "true" ``` -This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: +This section details the flow of events in order for `kube-vip` to advertise a Kubernetes Service: -1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` -3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. -4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. -6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. -7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. -8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. +1. An end user exposes an application through Kubernetes as a Service type `LoadBalancer`. For example, imperatively using `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` +2. Within the Kubernetes cluster, a Service object is created with the `spec.type` set to `LoadBalancer`. +3. A controller (typically a [Cloud Controller](/usage/on-prem)) has a loop that "watches" for Services of the type `LoadBalancer`. +4. The controller now has the responsibility of providing an IP address for this Service along with doing anything that is network specific for the environment where the cluster is running. +5. Once the controller has an IP address, it will update the Service field `spec.loadBalancerIP` with the IP address. +6. `kube-vip` Pods implement a "watcher" for Services that have a `svc.Spec.loadBalancerIP` address attached. +7. When a new Service appears, `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the Service network. +8. Finally, `kube-vip` will update the Service status so that the API reflects the object is ready. This is done by updating the `status.loadBalancer.ingress` with the VIP address. -#### Control Plane Load-Balancing (> 0.4) +#### Control Plane Load-Balancing -**NOTE** in it's initial release IPVS load-balancing is configured for having the VIP in the same subnet as the control-plane nodes, NAT based load-balancing will appear soon. +As of `kube-vip` v0.4.0, IPVS load balancing is configured for having the VIP in the same subnet as the control plane nodes. NAT-based load balancing will follow later. -To enable control-plane load balancing, the following is required in the kube-vip yaml to enable control plane load-balancing. +To enable control plane load balancing using IPVS, the environment variable `lb_enable` is required in the `kube-vip` manifest: -``` - - name : lb_enable - value: "true" +```yaml +- name : lb_enable + value: "true" ``` -The load balancing is provided through IPVS (IP Virtual Server) and provides a layer-4 (TCP Port) based round-robin across all of the control plane nodes. By default the load balancer will listen on the default 6443 port as the Kubernetes API server. -**Note:** The IPVS virtual server lives in kernel space and doesn't create an "actual" service that listens on port 6443, this allows the kernel to parse packets before they're sent to an actual TCP port. This is important to know because it means we don't have any port conflicts having the IPVS load-balancer listening on the same port as the API server on the same host. +The load balancing is provided through IPVS (IP Virtual Server) and provides a Layer 4 (TCP-based) round-robin across all of the control plane nodes. By default, the load balancer will listen on the default port of 6443 as the Kubernetes API server. The IPVS virtual server lives in kernel space and doesn't create an "actual" service that listens on port 6443. This allows the kernel to parse packets before they're sent to an actual TCP port. This is important to know because it means we don't have any port conflicts having the IPVS load balancer listening on the same port as the API server on the same host. -The load balancer port can be customised with the following snippet in the yaml. +The load balancer port can be customised by changing the `lb_port` environment variable in the `kube-vip` manifest: -``` - - name: lb_port - value: "6443" +```yaml +- name: lb_port + value: "6443" ``` -**How it works!** +##### How it works -Once the `lb_enable` is set to true kube-vip will do the following: +Once the `lb_enable` variable is set to `true`, `kube-vip` will do the following: -- In Layer 2 it will create an IPVS service on the leader -- In Layer 3 all nodes will create an IPVS service -- It will start a Kubernetes node watcher for nodes with the control plane label -- It will add/delete them as they're added and removed from the cluster +- In Layer 2 it will create an IPVS service on the leader. +- In Layer 3 all nodes will create an IPVS service. +- It will start a Kubernetes node watcher for nodes with the control plane label. +- It will add/delete them as they're added and removed from the cluster. -#### Debugging control plane load-balancing +#### Debugging control plane load balancing - In order to inspect what is happening we will need to install the `ipvsadm` tool. +In order to inspect and debug traffic, install the `ipvsadm` tool. ##### View the configuration The command `sudo ipvsadm -ln` will display the load balancer configuration. -``` - $ sudo ipvsadm -ln +```sh +$ sudo ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags - -> RemoteAddress:Port Forward Weight ActiveConn InActConn +-> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.0.40:6443 rr - -> 192.168.0.41:6443 Local 1 4 0 - -> 192.168.0.42:6443 Local 1 3 0 - -> 192.168.0.43:6443 Local 1 3 0 +-> 192.168.0.41:6443 Local 1 4 0 +-> 192.168.0.42:6443 Local 1 3 0 +-> 192.168.0.43:6443 Local 1 3 0 ``` ##### Watch things interact with the API server -The command `watch sudo ipvsadm -lnc` will auto-refresh the connections to the load-balancer. +The command `watch sudo ipvsadm -lnc` will auto-refresh the connections to the load balancer. -``` +```sh $ watch sudo ipvsadm -lnc -... + sudo ipvsadm -lnc k8s01: Tue Nov 9 11:39:39 2021 @@ -152,7 +151,7 @@ TCP 14:49 ESTABLISHED 192.168.0.40:56040 192.168.0.40:6443 192.168.0.42:6443 ## Components within a Kubernetes Cluster -The `kube-vip` kubernetes load-balancer requires a number of components in order to function: +The `kube-vip` Kubernetes load balancer requires a number of components in order to function: -- The Kube-Vip Cloud Provider -> [https://github.com/kube-vip/kube-vip-cloud-provider](https://github.com/kube-vip/kube-vip-cloud-provider) -- The Kube-Vip Deployment -> [https://github.com/kube-vip/kube-vip](https://github.com/kube-vip/kube-vip) +- [Kube-Vip Cloud Provider](https://github.com/kube-vip/kube-vip-cloud-provider) +- [Kube-Vip Deployment](https://github.com/kube-vip/kube-vip) diff --git a/docs/flags/index.md b/docs/flags/index.md index 4c086bde..1eceebfb 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -68,7 +68,7 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `address` | `` or `` | | | | `vip_interface` | `` | | | | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| | `lb_enable` | Enables IPVS LoadBalancer | Will watch Kubernetes nodes and add them to the IPVS load-balancer | +| | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | | | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | | **Services** | | | | | | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | diff --git a/docs/index.md b/docs/index.md index c6805114..8fcbfa83 100644 --- a/docs/index.md +++ b/docs/index.md @@ -39,19 +39,7 @@ The architecture for `kube-vip` (and associated Kubernetes components) is covere ## Installation -There are two main routes for deploying `kube-vip`: either through a [static pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [K3s](https://k3s.io)). - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -|----------------|------------| -| VIP | 10.0.0.40 | -| controlPlane01 | 10.0.0.41 | -| controlPlane02 | 10.0.0.42 | -| controlPlane03 | 10.0.0.43 | -| worker01 | 10.0.0.44 | - -All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0. We only have one worker as we're going to use our control plane in "hybrid" mode. +There are two main routes for deploying `kube-vip`: either through a [static Pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [K3s](https://k3s.io)). - [Static Pod](/install_static) - [DaemonSet](/install_daemonset) @@ -59,7 +47,7 @@ All nodes are running Ubuntu 20.04, Docker CE and will use Kubernetes 1.21.0. We ## Usage - [On-Prem with the kube-vip cloud controller](/usage/on-prem) -- [KIND](/usage/kind) +- [KinD](/usage/kind) - [Equinix Metal](/usage/EquinixMetal) - [k3s](/usage/k3s) From 6f18708ec2eb5b76d44d4025cbe44a1ffd18eb92 Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Mon, 22 Nov 2021 12:25:27 -0500 Subject: [PATCH 182/542] address PR comments Signed-off-by: Chip Zoller --- docs/index.md | 2 +- kubernetes-control-plane.md | 147 ------------------------------------ 2 files changed, 1 insertion(+), 148 deletions(-) delete mode 100644 kubernetes-control-plane.md diff --git a/docs/index.md b/docs/index.md index 8fcbfa83..92674069 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ The idea behind `kube-vip` is a small, self-contained, highly-available option f Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, but over time it has evolved to incorporate that same functionality for Kubernetes Services of type [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). Some of the features include: -- VIP addresses can be both IPv4 or IPv6 +- VIP addresses can be either IPv4 or IPv6 - Control Plane with ARP (Layer 2) or BGP (Layer 3) - Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) - Control Plane HA with kubeadm (static Pods) diff --git a/kubernetes-control-plane.md b/kubernetes-control-plane.md deleted file mode 100644 index 835862a8..00000000 --- a/kubernetes-control-plane.md +++ /dev/null @@ -1,147 +0,0 @@ -# Load Balancing a Kubernetes Cluster (Control-Plane) - -This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster - -`tl;dr version` -- Generate/modify first node `kube-vip` config/manifest -- `init` first node -- `join` remaining nodes -- Add remaining config/manifests - -## Infrastructure architecture - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -|----------------|------------| -| VIP | 10.0.0.75 | -| controlPlane01 | 10.0.0.70 | -| controlPlane02 | 10.0.0.71 | -| controlPlane03 | 10.0.0.72 | - -All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. - -### Generate the `kube-vip` configuration - -Make sure that the config directory exists: `sudo mkdir -p /etc/kube-vip/`, this directory can be any directory however the `hostPath` in the manifest will need modifying to point to the correct path. - -``` -sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample config | sudo tee /etc/kube-vip/config.yaml -``` - -### Modify the configuration - -**Cluster Configuration** -Modify the `remotePeers` to point to the correct addresses of the other two nodes, ensure that their `id` is unique otherwise this will confuse the raft algorithm. The `localPeer` should be the configuration of the current node (`controlPlane01`), which is where this instance of the cluster will run. - -As this node will be the first node, it will need to elect itself leader as until this occurs the VIP won’t be activated! - -`startAsLeader: true` - -**VIP Config** -We will need to set our VIP address to `192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `gratuitousARP: true` - -**Load Balancer** -We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. - -We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. - -**config.yaml** - -`user@controlPlane01:/etc/kube-vip$ cat config.yaml` - -... - -``` -remotePeers: -- id: server2 - address: 192.168.0.71 - port: 10000 -- id: server3 - address: 192.168.0.72 - port: 10000 -localPeer: - id: server1 - address: 192.168.0.70 - port: 10000 -vip: 192.168.0.75 -gratuitousARP: true -singleNode: false -startAsLeader: true -interface: ens192 -loadBalancers: -- name: Kubernetes Control Plane - type: tcp - port: 6443 - bindToVip: true - backends: - - port: 6444 - address: 192.168.0.70 - - port: 6444 - address: 192.168.0.71 - - port: 6444 - address: 192.168.0.72 -``` - -### First Node - -To generate the basic Kubernetes static pod `yaml` configuration: - -Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` - -``` -sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -Ensure that `image: ghcr.io/kube-vip/kube-vip:` is modified to point to a specific version (`0.3.7` at the time of writing), refer to [GitHub](https://github.com/kube-vip/kube-vip/pkgs/container/kube-vip) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isn’t the above path. - -The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. - -`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` - -Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: - -``` -$ kubectl get pods -A -NAMESPACE NAME READY STATUS RESTARTS AGE -<...> -kube-system kube-vip-controlplane01 1/1 Running 0 10m -``` - -### Remaining Nodes - -We first will need to create the `kube-vip` configuration that resides in `/etc/kube-vip/config.yaml` or we can regenerate it from scratch using the above example. Ensure that the configuration is almost identical with the `localPeer` and `remotePeers` sections are updated for each node. Finally, ensure that the remaining nodes will behave as standard cluster nodes by setting `startAsLeader: false`. - -At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. - -``` - kubeadm join 192.168.0.75:6443 --token \ - --discovery-token-ca-cert-hash sha256: \ - --control-plane --certificate-key - -``` - -**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). - -``` -sudo docker run -it --rm ghcr.io/kube-vip/kube-vip:0.3.7 sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: - -``` -user@controlPlane01:~$ kubectl get pods -A | grep vip -kube-system kube-vip-controlplane01 1/1 Running 1 16m -kube-system kube-vip-controlplane02 1/1 Running 0 18m -kube-system kube-vip-controlplane03 1/1 Running 0 20m - -``` - -If we look at the logs, we can see that the VIP is running on the second node and we’re waiting for our third node to join the cluster: - -``` -$ kubectl logs kube-vip-controlplane02 -n kube-system -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” - -``` From 82db862a1a7e4693bd68dc01ca7015ad83b42dc9 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 22 Nov 2021 20:00:05 +0000 Subject: [PATCH 183/542] IPVS fixes --- pkg/loadbalancer/ipvs.go | 46 +++++++++++++++++++++++++-------------- testing/kubeadm/create.sh | 44 +++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index 58038567..d3cdb695 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -53,21 +53,6 @@ func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { Address: ipvs.NewIP(net.ParseIP(address)), Scheduler: ROUNDROBIN, } - err = c.CreateService(svc) - // 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") - err = c.RemoveService(svc) - if err != nil { - return nil, fmt.Errorf("error re-creating IPVS service: %v", err) - } - err = c.CreateService(svc) - if err != nil { - return nil, fmt.Errorf("error re-creating IPVS service: %v", err) - } - } else if err != nil { - return nil, fmt.Errorf("error creating IPVS service: %v", err) - } lb := &IPVSLoadBalancer{ Port: port, @@ -88,6 +73,32 @@ func (lb *IPVSLoadBalancer) RemoveIPVSLB() error { } func (lb *IPVSLoadBalancer) AddBackend(address string, port int) 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) + } + // 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") + err = lb.client.RemoveService(lb.loadBalancerService) + if err != nil { + return fmt.Errorf("error re-creating IPVS service: %v", err) + } + err = lb.client.CreateService(lb.loadBalancerService) + if err != nil { + return fmt.Errorf("error re-creating IPVS service: %v", err) + } + } else if err != nil { + return fmt.Errorf("error creating IPVS service: %v", err) + } + log.Infof("Created Load-Balancer services on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port) + } + dst := ipvs.Destination{ Address: ipvs.NewIP(net.ParseIP(address)), Port: uint16(port), @@ -96,12 +107,15 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { FwdMethod: ipvs.Local, } - err := lb.client.CreateDestination(lb.loadBalancerService, dst) + err = lb.client.CreateDestination(lb.loadBalancerService, dst) // Swallow error of existing back end, the node watcher may attempt to apply // the same back end multiple times if err != nil && !strings.Contains(err.Error(), "file exists") { return fmt.Errorf("error creating backend: %v", err) + } else { + log.Infof("Added backend for [%s:%d] on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port, address, port) } + return nil } diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 79ebc9ee..0d7ad0c0 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -7,19 +7,19 @@ if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then echo " Param 3: Kube-Vip mode [\"controlplane\"/\"services\"/\"hybrid\"]" echo " Param 4: Vip address" echo "" - echo "" ./create_k8s.sh 1.18.5 0.3.3 192.168.0.40 + echo "" ./create_k8s.sh 1.18.5 0.4.0 hybrid 192.168.0.40 exit 1 fi case "$3" in -"controlplane") echo "Sending SIGHUP signal" +"controlplane") echo "Creating in control plane only mode" mode="--controlplane" ;; -"services") echo "Sending SIGINT signal" +"services") echo "Creating in services-only mode" mode="--services" ;; -"hybrid") echo "Sending SIGQUIT signal" +"hybrid") echo "Creating in hybrid mode" mode="--controlplane --services" ;; *) echo "Unknown kube-vip mode [$3]" @@ -27,17 +27,25 @@ case "$3" in ;; esac -source ./testing/nodes +install_deps() { + echo "Installing Kubernetes dependencies for Kubernetes $! on all nodes" + ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" + ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" + ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" + ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" + ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +} -echo "Installing Kubernetes dependencies for Kubernetes $! on all nodes" -ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" -ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" -ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" -ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" -ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" +source ./testing/nodes +first_node() { echo "Creating First node!" -ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod $mode --interface ens160 --vip $4 --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml" +ssh $NODE01 "sudo modprobe ip_vs_rr" +ssh $NODE01 "sudo modprobe nf_conntrack" +ssh $NODE01 "docker rmi plndr/kube-vip:dev" + +# echo "echo "ip_vs | tee -a /etc/modules" +ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection --enableLoadBalancer $5 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $4 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") ssh $NODE01 "sudo rm -rf ~/.kube/" ssh $NODE01 "mkdir -p .kube" @@ -48,14 +56,22 @@ ssh $NODE01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \" ssh $NODE01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") +} + +additional_controlplane() { ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" sleep 3 -ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection $mode | sudo tee /etc/kubernetes/manifests/vip.yaml" +ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest pod --interface ens160 --vip $2 --arp --leaderElection --enableLoadBalancer $3 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" sleep 3 -ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection $mode | sudo tee /etc/kubernetes/manifests/vip.yaml" +ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest pod --interface ens160 --vip $2 --arp --leaderElection --enableLoadBalancer $3 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" +} + +first_node $1 $2 $3 $4 $mode +additional_controlplane $2 $4 $mode + ssh $NODE04 "sudo $JOIN_CMD" ssh $NODE05 "sudo $JOIN_CMD" echo From 0b6d0be44b3bc548141b24e68fd8c49f59abaa85 Mon Sep 17 00:00:00 2001 From: Lewis Diamond Date: Mon, 22 Nov 2021 16:55:09 -0500 Subject: [PATCH 184/542] Various KIND documentation fixes KVVERSION needs to be preceeded with `$` for shell expansion of the variable. `kubectl` is unlikely to be a binary in the current directory and is likely to be in `$PATH` --- docs/usage/kind/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index f3915dd6..9e3298e5 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -44,12 +44,12 @@ The easiest method to generate a manifest is using the container itself, below w `alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` ## Deploy Kube-vip as a deamonset ``` -kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - +kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | kubectl apply -f - ``` ## Test @@ -67,4 +67,4 @@ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 74m nginx LoadBalancer 10.96.196.235 172.18.100.11 80:31236/TCP 6s -``` \ No newline at end of file +``` From 135a6b55e2fa8deaede6393e389bacdd18ed8701 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 23 Nov 2021 15:17:24 +0000 Subject: [PATCH 185/542] Final fixes to IPVS --- pkg/loadbalancer/ipvs.go | 25 +++++++++++++++++++------ testing/kubeadm/create.sh | 4 ++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index d3cdb695..4be74155 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -42,8 +42,15 @@ func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { // Create IPVS client c, err := ipvs.New() if err != nil { - return nil, fmt.Errorf("error creating IPVS client: %v", err) + log.Errorf("ensure IPVS kernel modules are loaded") + log.Fatalf("Error starting IPVS [%v]", err) } + i, err := c.Info() + if err != nil { + log.Errorf("ensure IPVS kernel modules are loaded") + log.Fatalf("Error getting IPVS version [%v]", err) + } + log.Infof("IPVS Loadbalancer enabled for %d.%d.%d", i.Version[0], i.Version[1], i.Version[2]) // Generate out API Server LoadBalancer instance svc := ipvs.Service{ @@ -86,6 +93,7 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { if err != nil && strings.Contains(err.Error(), "file exists") { log.Warnf("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) } @@ -94,7 +102,9 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { return fmt.Errorf("error re-creating IPVS service: %v", err) } } else if err != nil { - return fmt.Errorf("error creating IPVS service: %v", err) + // 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.Infof("Created Load-Balancer services on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port) } @@ -110,11 +120,14 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { err = lb.client.CreateDestination(lb.loadBalancerService, dst) // Swallow error of existing back end, the node watcher may attempt to apply // the same back end multiple times - if err != nil && !strings.Contains(err.Error(), "file exists") { - return fmt.Errorf("error creating backend: %v", err) - } else { - log.Infof("Added backend for [%s:%d] on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port, address, port) + if err != nil { + if !strings.Contains(err.Error(), "file exists") { + return fmt.Errorf("error creating backend: %v", err) + } + // file exists is fine, we will just return at this point + return nil } + log.Infof("Added backend for [%s:%d] on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port, address, port) return nil } diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 0d7ad0c0..8c1f3bb1 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -40,8 +40,8 @@ source ./testing/nodes first_node() { echo "Creating First node!" -ssh $NODE01 "sudo modprobe ip_vs_rr" -ssh $NODE01 "sudo modprobe nf_conntrack" +#ssh $NODE01 "sudo modprobe ip_vs_rr" +#ssh $NODE01 "sudo modprobe nf_conntrack" ssh $NODE01 "docker rmi plndr/kube-vip:dev" # echo "echo "ip_vs | tee -a /etc/modules" From a36d33e4e526de9e44e4e0e0c3e14b35bd2858e4 Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Tue, 23 Nov 2021 10:17:26 -0500 Subject: [PATCH 186/542] further edits; revamp K3s docs Signed-off-by: Chip Zoller --- docs/install_daemonset/index.md | 8 +-- docs/install_static/index.md | 10 ++-- docs/usage/k3s/index.md | 94 +++++++++------------------------ 3 files changed, 33 insertions(+), 79 deletions(-) diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 37edf483..9777add8 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -31,7 +31,7 @@ When creating the `kube-vip` installation manifest as a DaemonSet, the `manifest ``` kube-vip manifest daemonset \ --interface $INTERFACE \ - --vip $VIP \ + --address $VIP \ --inCluster \ --taint \ --controlplane \ @@ -97,7 +97,7 @@ spec: value: "3" - name: vip_retryperiod value: "1" - - name: vip_address + - name: address value: 192.168.0.40 image: ghcr.io/kube-vip/kube-vip:v0.4.0 imagePullPolicy: Always @@ -135,7 +135,7 @@ This configuration will create a manifest that starts `kube-vip` providing contr ``` kube-vip manifest daemonset \ --interface $INTERFACE \ - --vip $VIP \ + --address $VIP \ --inCluster \ --taint \ --controlplane \ @@ -208,7 +208,7 @@ spec: value: "65000" - name: bgp_peers value: 192.168.0.10:65000::false,192.168.0.11:65000::false - - name: vip_address + - name: address value: 192.168.0.40 image: ghcr.io/kube-vip/kube-vip:v0.4.0 imagePullPolicy: Always diff --git a/docs/install_static/index.md b/docs/install_static/index.md index bdf0a283..f2e83b59 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -68,7 +68,7 @@ This configuration will create a manifest that starts `kube-vip` providing contr ``` kube-vip manifest pod \ --interface $INTERFACE \ - --vip $VIP \ + --address $VIP \ --controlplane \ --services \ --arp \ @@ -113,9 +113,9 @@ spec: value: "3" - name: vip_retryperiod value: "1" - - name: vip_address + - name: address value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 + image: ghcr.io/kube-vip/kube-vip:v0.4.0 imagePullPolicy: Always name: kube-vip resources: {} @@ -151,7 +151,7 @@ This configuration will create a manifest that starts `kube-vip` providing contr ``` kube-vip manifest pod \ --interface $INTERFACE \ - --vip $VIP \ + --address $VIP \ --controlplane \ --services \ --bgp \ @@ -200,7 +200,7 @@ spec: value: "65000" - name: bgp_peers value: 192.168.0.10:65000::false,192.168.0.11:65000::false - - name: vip_address + - name: address value: 192.168.0.40 image: ghcr.io/kube-vip/kube-vip:v0.3.9 imagePullPolicy: Always diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 78e57ade..60266208 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -1,99 +1,53 @@ -# K3s overview (on Equinix Metal) +# K3s Overview -## Prerequisites +`kube-vip` works on [K3s environments](https://k3s.io/) similar to most others with the exception of how it gets deployed. Because K3s is able to bootstrap a single server (control plane node) without the availability of the load balancer fronting it, `kube-vip` can be installed as a DaemonSet. -In order to make ARP work on Equinix Metal, you need to follow [metal-gateway](https://metal.equinix.com/developers/docs/networking/metal-gateway/) guide to have public VLAN subnet, which you can use as your loadbalancer IP. +## Prerequisites (on Equinix Metal) + +In order to make ARP work on Equinix Metal, follow the [metal-gateway](https://metal.equinix.com/developers/docs/networking/metal-gateway/) guide to have public VLAN subnet which can be used for the load balancer IP. + +## Clean Environment + +This step is optional but recommended if a K3s installation previously existed. -## Optional Tidy environment (best if something was running before) ``` rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ ip addr flush dev lo; \ ip addr add 127.0.0.1/8 dev lo; ``` -## Step 1: Create Manifests folder +## Step 1: Create Manifests Folder -This is required, this folder will contain all of the generated manifests that `k3s` will execute as it starts. We will create it before `k3s` and place our `kube-vip` manifests within it. +K3s has an optional manifests directory that will be searched to [auto-deploy](https://rancher.com/docs/k3s/latest/en/advanced/#auto-deploying-manifests) any manifests found within. Create this directory first in order to later place the `kube-vip` resources inside. ``` mkdir -p /var/lib/rancher/k3s/server/manifests/ ``` -## Step 2: Get rbac for `Kube-Vip` - -As `kube-vip` runs inside of the Kubernetes cluster, we will need to ensure that the required permissions exist. - -``` -curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/rbac.yaml -``` - -## Step 3: Generate kube-vip (A VIP address for the network will be required) - -Configure your virtual IP (for the control plane) and interface that will expose this VIP first. +## Step 2: Upload Kube-Vip RBAC Manifest -``` -export VIP=x.x.x.x -export INTERFACE=bind0 # or ethX depends on your networking setup -``` +As `kube-vip` runs as a DaemonSet under K3s and not a static Pod, we will need to ensure that the required permissions exist for it to communicate with the API server. RBAC resources are needed to ensure a ServiceAccount exists with those permissions and bound appropriately. -Modify the `VIP` and `INTERFACE` to match the floating IP address you'd like to use and the interface it should bind to. +Get the RBAC manifest and place in the auto-deploy directory: -To generate the manifest we have two options! We can generate the manifest from [kube-vip.io](kube-vip.io) or use a kube-vip image to generate the manifest! - -## Step 3.1: Generate from kube-vip.io - ``` -curl -sL kube-vip.io/k3s | vipAddress=$VIP vipInterface=$INTERFACE sh | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml +curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/kube-vip-rbac.yaml ``` -## Step 3.2 Generate from container image - - -### Get latest version +## Step 3: Generate a Kube-Vip DaemonSet Manifest - We can parse the GitHub API to find the latest version (or we can set this manually) +Refer to the [DaemonSet manifest generation documentation](/install_daemonset/#generating-a-manifest) for the process to complete this step. -`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` +Either store this generated manifest separately in the `/var/lib/rancher/k3s/server/manifests/` directory, or append to the existing RBAC manifest called `kube-vip-rbac.yaml`. As a general best practice, it is a cleaner approach to place all related resources into a single YAML file. -or manually: +> Note: Remember to include YAML document delimiters (`---`) when composing multiple documents. -`export KVVERSION=vx.x.x` +## Step 4: Install a HA K3s Cluster -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. +There are multiple ways to install K3s including `[k3sup](https://k3sup.dev/)` or [running the binary](https://rancher.com/docs/k3s/latest/en/quick-start/) locally. Whichever method you choose, the `--tls-san` flag must be passed with the same IP when generating the `kube-vip` DaemonSet manifest when installing the first server (control plane) instance. This is so that K3s generates an API server certificate with the `kube-vip` virtual IP address. -### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` - -### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` - - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --vip $VIP \ - --controlplane \ - --services \ - --inCluster \ - --taint \ - --arp -``` - -## Step 4: Up Cluster - -From online `-->` - -``` -curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ --t agent-secret --tls-san $VIP" sh - -``` - -From local `-->` - -``` -sudo ./k3s server --tls-san $VIP -``` +Once the cluster is installed, you should be able to edit the `kubeconfig` file generated from the process and use the `kube-vip` VIP address to access the control plane. -## Step 5: Service Load-Balancing +## Step 5: Service Load Balancing -For this refer to the [on-prem](../on-prem) documentation +If wanting to use the `kube-vip` [cloud controller](/usage/on-prem), pass the `--disable servicelb` flag so K3s will not attempt to render Kubernetes Service resources of type `LoadBalancer`. If building with `k3sup`, the flag should be given as an argument to the `--k3s-extra-args` flag itself: `--k3s-extra-args "--disable servicelb"`. To install the `kube-vip` cloud controller, follow the additional steps in the [cloud controller guide](/on-prem/#install-the-kube-vip-cloud-provider). From 8ad16208440ca9a077d69e5ff1ebcde457b41b5b Mon Sep 17 00:00:00 2001 From: Chip Zoller Date: Tue, 23 Nov 2021 10:20:29 -0500 Subject: [PATCH 187/542] fix conflicts Signed-off-by: Chip Zoller --- docs/usage/kind/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index 5321c830..e8526023 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -46,12 +46,12 @@ The easiest method to generate a manifest is using the container itself, below w ### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` +`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` ## Deploy Kube-vip as a DaemonSet ``` -kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | ./kubectl apply -f - +kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | kubectl apply -f - ``` ## Test From 0783c006b850c658bae800707129142f7005c021 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 25 Nov 2021 09:44:43 +0000 Subject: [PATCH 188/542] Update index.md Fixes header --- docs/usage/EquinixMetal/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index eab30549..90c02325 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -8,7 +8,7 @@ When deploying Kubernetes with Equinix Metal with the `--controlplane` functiona ## Configure to use a container runtime -### Get latest version +### Get latest version We can parse the GitHub API to find the latest version (or we can set this manually) From 2a2cb7b5facf2fa2a130cec78a6bc86f3a40ce3d Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 25 Nov 2021 09:45:27 +0000 Subject: [PATCH 189/542] Update index.md --- docs/usage/kind/index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index e8526023..f9f558fe 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -28,6 +28,14 @@ kubectl create configmap --namespace kube-system kubevip --from-literal range-gl ## Install kube-vip +### Create the RBAC settings + +Since `kube-vip` as a DaemonSet runs as a regular resource instead of a static Pod, it still needs the correct access to be able to watch Kubernetes Services and other objects. In order to do this, RBAC resources must be created which include a ServiceAccount, ClusterRole, and ClusterRoleBinding and can be applied this with the command: + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` + ### Get latest version We can parse the GitHub API to find the latest version (or we can set this manually) From 022b62caca697f813a53f17f2693e1b3436a6fc9 Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Sat, 27 Nov 2021 13:53:24 -0500 Subject: [PATCH 190/542] Update label selector for control-plane nodes The current node watcher uses a label selector of the form `node-role.kubernetes.io/control-plane=`; this does not work correctly. The label selector should be `node-role.kubernetes.io/control-plane" or `node-role.kubernetes.io/control-plane=true` to select the control-plane nodes. Without these changes, the IPVS tables are never updated with the control plane nodes and clients making requests to the VIP will fail with a "connection refused" error. ``` $ kubectl get nodes -l node-role.kubernetes.io/control-plane= No resources found $ kubectl get nodes -l node-role.kubernetes.io/control-plane=true NAME STATUS ROLES AGE VERSION pi4-00 Ready control-plane,etcd,master 21h v1.22.3+k3s1 pi4-01 Ready control-plane,etcd,master 20h v1.22.3+k3s1 pi4-02 Ready control-plane,etcd,master 20h v1.22.3+k3s1 $ kubectl get nodes -l node-role.kubernetes.io/control-plane NAME STATUS ROLES AGE VERSION pi4-00 Ready control-plane,etcd,master 21h v1.22.3+k3s1 pi4-01 Ready control-plane,etcd,master 20h v1.22.3+k3s1 pi4-02 Ready control-plane,etcd,master 20h v1.22.3+k3s1 ``` Signed-off-by: Matthew Sykes --- pkg/cluster/clusterLeaderElection.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 38249fa7..4b42c496 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -22,7 +22,6 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" @@ -235,9 +234,8 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro // 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") - labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"node-role.kubernetes.io/control-plane": ""}} listOptions := metav1.ListOptions{ - LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + LabelSelector: "node-role.kubernetes.io/control-plane", } rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ From 2d14d63ef204f507984cbc511808e0f3ca0bca99 Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Sat, 27 Nov 2021 20:52:55 -0500 Subject: [PATCH 191/542] Pass resolved VIP from Network.IP() to NewIPVSLB When the manager process is started without the `--vip` flag, it will panic during initialization. This is because the `nil` result from `net.ParseIP("")` is passed to `ipvs.NewIP()`. This change passes the resolved address from `cluster.Network.IP()` instead of the possibly-empty VIP from the configuration. Signed-off-by: Matthew Sykes --- pkg/cluster/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index a2ab70b9..df3cb510 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -78,7 +78,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co log.Infof("Starting IPVS LoadBalancer") - lb, err := loadbalancer.NewIPVSLB(c.VIP, c.LoadBalancerPort) + lb, err := loadbalancer.NewIPVSLB(cluster.Network.IP(), c.LoadBalancerPort) if err != nil { log.Errorf("Error creating IPVS LoadBalancer [%s]", err) } From 92f6ad4395168108c275d94ec2b229bcddb7cfd4 Mon Sep 17 00:00:00 2001 From: Lewis Diamond Date: Thu, 25 Nov 2021 17:24:28 -0500 Subject: [PATCH 192/542] Fix typo in log (s/addded/added/) Signed-off-by: Lewis Diamond --- pkg/manager/watcher.go | 4 ++-- pkg/service/watcher.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 665f979d..c6ff2878 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -64,9 +64,9 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { } if svc.Spec.LoadBalancerIP == "" { - log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) + log.Infof("Service [%s] has been added/modified, it has no assigned external addresses", svc.Name) } else { - log.Infof("Service [%s] has been addded/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Infof("Service [%s] has been added/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) wg.Add(1) err = sm.syncServices(svc, &wg) if err != nil { diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index bbea8af4..4944249b 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -48,9 +48,9 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } if svc.Spec.LoadBalancerIP == "" { - log.Infof("Service [%s] has been addded/modified, it has no assigned external addresses", svc.Name) + log.Infof("Service [%s] has been added/modified, it has no assigned external addresses", svc.Name) } else { - log.Infof("Service [%s] has been addded/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Infof("Service [%s] has been added/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) err = sm.syncServices(svc) if err != nil { log.Error(err) From 3855ed4553b4d509b7962b1b00622dd7cf4a1b61 Mon Sep 17 00:00:00 2001 From: Deepak Sharma Date: Fri, 10 Dec 2021 16:48:23 +0530 Subject: [PATCH 193/542] ddns fix gofmt file Signed-off-by: Deepak Sharma --- pkg/vip/ddns.go | 4 ++++ pkg/vip/dhcp.go | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 0604976f..0595a92b 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -46,6 +46,10 @@ func (ddns *ddnsManager) Start() (string, error) { ipCh <- lease.ACK.YourIPAddr.String() }) + client.WithHostName(ddns.network.DDNSHostName()) + + go client.Start() + log.Info("waiting for ip from dhcp") ip, timeout := "", time.After(1*time.Minute) diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index 41ce6e4d..dca2afe6 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -20,6 +20,7 @@ type Callback func(*nclient4.Lease) // DHCPClient is responsible for maintaining ipv4 lease for one specified interface type DHCPClient struct { iface *net.Interface + ddnsHostName string lease *nclient4.Lease initRebootFlag bool requestedIP net.IP @@ -38,6 +39,11 @@ func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string } } +func (c *DHCPClient) WithHostName(hostname string) *DHCPClient { + c.ddnsHostName = hostname + return c +} + // Stop state-transition process and close dhcp client func (c *DHCPClient) Stop() { close(c.stopChan) @@ -171,6 +177,10 @@ func (c *DHCPClient) request() (*nclient4.Lease, error) { defer broadcast.Close() + if c.ddnsHostName != "" { + return broadcast.Request(context.TODO(), dhcpv4.WithOption(dhcpv4.OptHostName(c.ddnsHostName))) + } + return broadcast.Request(context.TODO()) } From 0649fb01eb6c23635464d68b9afbeb680203fab7 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Guerraz <861556+jbguerraz@users.noreply.github.com> Date: Sat, 11 Dec 2021 23:21:13 +0000 Subject: [PATCH 194/542] allow to configure the ipvs forwarding method --- cmd/kube-vip-config.go | 1 + cmd/kube-vip-start.go | 1 + cmd/kube-vip.go | 1 + docs/flags/index.md | 2 ++ pkg/cluster/service.go | 2 +- pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 10 ++++++++++ pkg/kubevip/config_types.go | 6 ++++++ pkg/loadbalancer/ipvs.go | 23 +++++++++++++++++++++-- 9 files changed, 46 insertions(+), 3 deletions(-) diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go index d3f4ab8d..2bb271f5 100644 --- a/cmd/kube-vip-config.go +++ b/cmd/kube-vip-config.go @@ -31,6 +31,7 @@ func init() { kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance") kubeVipSampleConfig.Flags().IntVar(&cliConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") kubeVipSampleConfig.Flags().StringSliceVar(&cliBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") + kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.ForwardingMethod, "lbForwardingMethod", "local", "The forwarding method of a load balancer instance") } var kubeVipSampleConfig = &cobra.Command{ diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 1a17ce2d..762587b1 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -38,6 +38,7 @@ func init() { kubeVipStart.Flags().IntVar(&startConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") kubeVipStart.Flags().IntVar(&startConfigLB.BackendPort, "lbBackEndPort", 6443, "A port that all backends may be using (optional)") kubeVipStart.Flags().StringSliceVar(&startBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") + kubeVipStart.Flags().StringVar(&startConfigLB.ForwardingMethod, "lbForwardingMethod", "local", "The forwarding method of a load balancer instance") // Cluster configuration kubeVipStart.Flags().StringVar(&startKubeConfigPath, "kubeConfig", "/etc/kubernetes/admin.conf", "The path of a kubernetes configuration file") diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 0013344a..23ab4cb1 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -72,6 +72,7 @@ func init() { // LoadBalancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS") kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6443, "loadbalancer port for the VIP") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerForwardingMethod, "lbForwardingMethod", "local", "loadbalancer forwarding method") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") diff --git a/docs/flags/index.md b/docs/flags/index.md index 1eceebfb..2e81e11c 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -20,6 +20,7 @@ These flags are typically used in the `kube-vip` manifest generation process. | | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | | | `--enableLoadBalancer` | Enables IPVS load balancer | `kube-vip` ≥ 0.4.0 | | | `--lbPort` | 6443 | The port that the api server will load-balanced on | +| | `--lbForwardingMethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | | **Services** | | | | | | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | | **Kubernetes** | | | | @@ -70,6 +71,7 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | | | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | | | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | +| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | | **Services** | | | | | | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | | **LeaderElection** | | | | diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index df3cb510..1ba458cd 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -78,7 +78,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co log.Infof("Starting IPVS LoadBalancer") - lb, err := loadbalancer.NewIPVSLB(cluster.Network.IP(), c.LoadBalancerPort) + lb, err := loadbalancer.NewIPVSLB(cluster.Network.IP(), c.LoadBalancerPort, c.LoadBalancerForwardingMethod) if err != nil { log.Errorf("Error creating IPVS LoadBalancer [%s]", err) } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d8481496..76cd3248 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -109,6 +109,9 @@ const ( //lbPort defines the port of load-balancer lbPort = "lb_port" + //lbForwardingMethod defines the forwarding method of load-balancer + lbForwardingMethod = "lb_fwdmethod" + //vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index c3ef4e51..ebc0849c 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -330,6 +330,12 @@ func ParseEnvironment(c *Config) error { } c.LoadBalancerPort = int(i) } + + // Find loadbalancer forwarding method + env = os.Getenv(lbForwardingMethod) + if env != "" { + c.LoadBalancerForwardingMethod = env + } return nil } @@ -584,6 +590,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: lbPort, Value: fmt.Sprintf("%d", c.LoadBalancerPort), }, + { + Name: lbForwardingMethod, + Value: c.LoadBalancerForwardingMethod, + }, } newEnvironment = append(newEnvironment, lb...) diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 0cc63b0a..8fba0f01 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -72,6 +72,9 @@ type Config struct { // Listen port for the IPVS Service LoadBalancerPort int `yaml:"lbPort"` + // Forwarding method for the IPVS Service + LoadBalancerForwardingMethod string `yaml:"lbForwardingMethod"` + // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer @@ -146,6 +149,9 @@ type LoadBalancer struct { //Backends, is an array of backend servers Backends []BackEnd `yaml:"backends"` + + // Forwarding method of LoadBalancer, either Local, Tunnel, DirectRoute or Bypass + ForwardingMethod string `yaml:"forwardingMethod"` } // BackEnd is a server we will load balance over diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index 4be74155..a9640185 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -35,9 +35,10 @@ type IPVSLoadBalancer struct { client ipvs.Client loadBalancerService ipvs.Service Port int + forwardingMethod ipvs.ForwardType } -func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { +func NewIPVSLB(address string, port int, forwardingMethod string) (*IPVSLoadBalancer, error) { // Create IPVS client c, err := ipvs.New() @@ -61,10 +62,28 @@ func NewIPVSLB(address string, port int) (*IPVSLoadBalancer, error) { Scheduler: ROUNDROBIN, } + var m ipvs.ForwardType + switch strings.ToLower(forwardingMethod) { + case "masquerade": + m = ipvs.Masquarade + case "local": + m = ipvs.Local + case "tunnel": + m = ipvs.Tunnel + case "directroute": + m = ipvs.DirectRoute + case "bypass": + m = ipvs.Bypass + default: + m = ipvs.Local + log.Warnf("unknown forwarding method. Defaulting to Local") + } + lb := &IPVSLoadBalancer{ Port: port, client: c, loadBalancerService: svc, + forwardingMethod: m, } // Return our created load-balancer return lb, nil @@ -114,7 +133,7 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { Port: uint16(port), Family: ipvs.INET, Weight: 1, - FwdMethod: ipvs.Local, + FwdMethod: lb.forwardingMethod, } err = lb.client.CreateDestination(lb.loadBalancerService, dst) From a642f32414f56906cb5af2145299517df3900de4 Mon Sep 17 00:00:00 2001 From: Deepak Sharma Date: Mon, 13 Dec 2021 16:17:28 +0530 Subject: [PATCH 195/542] add client id to request Signed-off-by: Deepak Sharma --- pkg/vip/dhcp.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index dca2afe6..4c8be0b2 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -178,7 +178,9 @@ func (c *DHCPClient) request() (*nclient4.Lease, error) { defer broadcast.Close() if c.ddnsHostName != "" { - return broadcast.Request(context.TODO(), dhcpv4.WithOption(dhcpv4.OptHostName(c.ddnsHostName))) + return broadcast.Request(context.TODO(), + dhcpv4.WithOption(dhcpv4.OptHostName(c.ddnsHostName)), + dhcpv4.WithOption(dhcpv4.OptClientIdentifier([]byte(c.ddnsHostName)))) } return broadcast.Request(context.TODO()) From df539cbc6e88cb83b18ae8920b8145d403d0e6b1 Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Thu, 16 Dec 2021 23:54:15 +0800 Subject: [PATCH 196/542] Check interface In some cases, kube-vip will start to serve before the interface is not existed or not up. We should make sure the interface is valid. Signed-off-by: yaocw2020 --- cmd/kube-vip.go | 17 +++++++++++++---- pkg/kubevip/config_manager.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 23ab4cb1..b441e9c1 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -7,14 +7,15 @@ import ( "os" "time" - "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/manager" - "github.com/kube-vip/kube-vip/pkg/packet" - "github.com/kube-vip/kube-vip/pkg/vip" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/manager" + "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/vip" ) // Path to the configuration file @@ -172,6 +173,10 @@ var kubeVipService = &cobra.Command{ log.Fatalln(err) } + if err := initConfig.CheckInterface(); err != nil { + log.Fatalln(err) + } + // User Environment variables as an option to make manifest clearer envConfigMap := os.Getenv("vip_configmap") if envConfigMap != "" { @@ -203,6 +208,10 @@ var kubeVipManager = &cobra.Command{ log.Fatalln(err) } + if err := initConfig.CheckInterface(); err != nil { + log.Fatalln(err) + } + // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index a9e588c0..8a0fca8a 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -9,6 +9,7 @@ import ( "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" ) var endPointIndex int // Holds the previous endpoint (for determining decisions on next endpoint) @@ -181,3 +182,32 @@ func (c *Config) WriteConfig(path string) error { log.Debugf("wrote %d bytes\n", bytesWritten) return nil } + +func (c *Config) CheckInterface() error { + if c.Interface != "" { + if err := isValidInterface(c.Interface); err != nil { + return fmt.Errorf("%s is not valid interface, reason: %w", c.Interface, err) + } + } + + if c.ServicesInterface != "" { + if err := isValidInterface(c.ServicesInterface); err != nil { + return fmt.Errorf("%s is not valid interface, reason: %w", c.ServicesInterface, err) + } + } + + return nil +} + +func isValidInterface(iface string) error { + l, err := netlink.LinkByName(iface) + if err != nil { + return fmt.Errorf("get %s failed, error: %w", iface, err) + } + + if l.Attrs().OperState != netlink.OperUp { + return fmt.Errorf("%s is not up", iface) + } + + return nil +} From dd621131c6151c776547a0ffd81da8185c8fd674 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 20 Dec 2021 13:11:35 +0000 Subject: [PATCH 197/542] Adds missing flag/env for services interface --- docs/flags/index.md | 86 +++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 2e81e11c..5a99a677 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -22,6 +22,7 @@ These flags are typically used in the `kube-vip` manifest generation process. | | `--lbPort` | 6443 | The port that the api server will load-balanced on | | | `--lbForwardingMethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | | **Services** | | | | +| | `--serviceInterface` | "" | Defines an optional different interface to bind services too | | | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | | **Kubernetes** | | | | | | `--inCluster` | Required for `kube-vip` as DaemonSet. | Runs `kube-vip` with a ServiceAccount called `kube-vip`. | @@ -55,45 +56,46 @@ These environment variables are usually part of a `kube-vip` manifest and used w More environment variables can be read through the `pkg/kubevip/config_envvar.go` file. -| Category | Environment Variable | Usage | Notes | -| ------------------- | --------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------- | -| **Troubleshooting** | | | | -| | `vip_loglevel` | default 4 | Set to `5` for debugging logs | -| **Mode** | | | | -| | `cp_enable` | Enables `kube-vip` control plane functionality | | -| | `svc_enable` | Enables `kube-vip` to watch Services of type `LoadBalancer` | | -| **VIP Config** | | | | -| | `vip_arp` | Enables ARP broadcasts from Leader | | -| | `bgp_enable` | Enables BGP peering from `kube-vip` | | -| | `vip_address` | `` | (deprecated) | -| | `address` | `` or `` | | -| | `vip_interface` | `` | | -| | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | -| | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | -| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | -| **Services** | | | | -| | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | -| **LeaderElection** | | | | -| | `vip_leaseduration` | default 5 | Seconds a lease is held for | -| | `vip_renewdeadline` | default 3 | Seconds a leader can attempt to renew the lease | -| | `vip_retryperiod` | default 1 | Number of times the leader will hold the lease for | -| | `cp_namespace` | "kube-vip" | The namespace where the lease will reside | -| **BGP** | | | | -| | `bgp_routerid` | `` | Typically the address of the local node | -| | `bgp_routerinterface` | Interface name | Used to associate the `routerID` with the control plane's interface. | -| | `bgp_as` | default 65000 | The AS we peer from | -| | `bgp_peers` | `` | Comma separated list of BGP peers | -| | `bgp_peeraddress` | `` | Address of a single BGP Peer | -| | `bgp_peeras` | default 65000 | AS of a single BGP Peer | -| | `bgp_peerpass` | "" | Password to work with a single BGP Peer | -| | `bgp_multihop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | -| | `bgp_sourceif` | Source Interface | Determines which interface BGP should peer _from_ | -| | `bgp_sourceip` | Source Address | Determines which IP address BGP should peer _from_ | -| | `annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | -| **Equinix Metal** | | | (May be deprecated) | -| | `vip_packet` | Enables Equinix Metal API calls | | -| | `PACKET_AUTH_TOKEN` | Equinix Metal API token | | -| | `vip_packetproject` | Equinix Metal Project (Name) | | -| | `vip_packetprojectid` | Equinix Metal Project (UUID) | | -| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | +| Category | Environment Variable | Usage | Notes | +| ------------------- | ---------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------- | +| **Troubleshooting** | | | | +| | `vip_loglevel` | default 4 | Set to `5` for debugging logs | +| **Mode** | | | | +| | `cp_enable` | Enables `kube-vip` control plane functionality | | +| | `svc_enable` | Enables `kube-vip` to watch Services of type `LoadBalancer` | | +| **VIP Config** | | | | +| | `vip_arp` | Enables ARP broadcasts from Leader | | +| | `bgp_enable` | Enables BGP peering from `kube-vip` | | +| | `vip_address` | `` | (deprecated) | +| | `address` | `` or `` | | +| | `vip_interface` | `` | | +| | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | +| | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | +| | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | +| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | +| **Services** | | | | +| | `vip_servicesinterface`| "" | Defines an optional different interface to bind services too | +| | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | +| **LeaderElection** | | | | +| | `vip_leaseduration` | default 5 | Seconds a lease is held for | +| | `vip_renewdeadline` | default 3 | Seconds a leader can attempt to renew the lease | +| | `vip_retryperiod` | default 1 | Number of times the leader will hold the lease for | +| | `cp_namespace` | "kube-vip" | The namespace where the lease will reside | +| **BGP** | | | | +| | `bgp_routerid` | `` | Typically the address of the local node | +| | `bgp_routerinterface` | Interface name | Used to associate the `routerID` with the control plane's interface. | +| | `bgp_as` | default 65000 | The AS we peer from | +| | `bgp_peers` | `` | Comma separated list of BGP peers | +| | `bgp_peeraddress` | `` | Address of a single BGP Peer | +| | `bgp_peeras` | default 65000 | AS of a single BGP Peer | +| | `bgp_peerpass` | "" | Password to work with a single BGP Peer | +| | `bgp_multihop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | +| | `bgp_sourceif` | Source Interface | Determines which interface BGP should peer _from_ | +| | `bgp_sourceip` | Source Address | Determines which IP address BGP should peer _from_ | +| | `annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | +| **Equinix Metal** | | | (May be deprecated) | +| | `vip_packet` | Enables Equinix Metal API calls | | +| | `PACKET_AUTH_TOKEN` | Equinix Metal API token | | +| | `vip_packetproject` | Equinix Metal Project (Name) | | +| | `vip_packetprojectid` | Equinix Metal Project (UUID) | | +| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | From a5b0eab318d22c25ceebf0a6d4240a36b7c2d5c8 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 21 Dec 2021 09:33:52 +0000 Subject: [PATCH 198/542] Adding static analysis as part of CNCF onboarding --- .github/workflows/codeql-analysis.yml | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..75d55714 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '17 10 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 09088a9c17c4bb726a09b148bf2ebdf5d6209bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Tue, 21 Dec 2021 22:58:58 +0100 Subject: [PATCH 199/542] Dockerfile: Update to go 1.16.12 and alpine 3.15 base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e0bd4137..e09b6cf0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.16.5-alpine3.13 as dev +FROM golang:1.16.12-alpine3.15 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ @@ -16,4 +16,4 @@ FROM scratch COPY --from=dev /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt # Add kube-vip binary COPY --from=dev /src/kube-vip / -ENTRYPOINT ["/kube-vip"] \ No newline at end of file +ENTRYPOINT ["/kube-vip"] From 19d84bb50b951d3cead2ced968291f52a2301cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Tue, 21 Dec 2021 23:14:11 +0100 Subject: [PATCH 200/542] go.mod: Update dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 -> v0.8.0 github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e -> v0.0.0-20211214070828-5297eed8f489 github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 -> v0.0.0-20210831201139-f982b8766fb5 github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf -> v0.0.0-20211126142749-4eae47f3d54b github.com/onsi/ginkgo v1.14.0 -> v1.14.2 github.com/packethost/packngo v0.13.0 -> v0.20.0 github.com/prometheus/client_golang v0.10.0 -> v0.11.0 github.com/spf13/cobra v1.1.3 -> v1.3.0 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f -> v0.0.0-20211101163701-50045581ed74 golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d -> v0.0.0-20211216030914-fe4d6282115f golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 -> v0.0.0-20211216021012-1d35b9e2eb4e golang.org/x/term v0.0.0-20210503060354-a79de5458b56 -> v0.0.0-20210927222741-03fcf44c2211 k8s.io/api v0.22.2 -> v0.22.5 k8s.io/apimachinery v0.22.2 -> v0.22.5 k8s.io/client-go v0.22.2 -> v0.22.5 k8s.io/klog/v2 v2.9.0 -> v2.40.1 sigs.k8s.io/kind v0.10.0 -> v0.11.1 Signed-off-by: Manuel Rüger --- go.mod | 47 ++--- go.sum | 575 +++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 367 insertions(+), 255 deletions(-) diff --git a/go.mod b/go.mod index 96ac1884..063599c7 100644 --- a/go.mod +++ b/go.mod @@ -3,47 +3,34 @@ module github.com/kube-vip/kube-vip go 1.14 require ( - github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 + github.com/cloudflare/ipvs v0.8.0 github.com/davecgh/go-spew v1.1.1 github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/google/gofuzz v1.2.0 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e + github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 - github.com/magiconair/properties v1.8.5 // indirect - github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 - github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect - github.com/onsi/ginkgo v1.14.0 + github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5 + github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect + github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.1 github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee - github.com/packethost/packngo v0.13.0 - github.com/pelletier/go-toml v1.9.0 // indirect + github.com/packethost/packngo v0.20.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.10.0 - github.com/prometheus/common v0.23.0 // indirect + github.com/prometheus/client_golang v1.11.0 github.com/sirupsen/logrus v1.8.1 - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.1.3 - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect - golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d - golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c // indirect - golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 - golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 // indirect - google.golang.org/grpc v1.37.0 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect - k8s.io/api v0.22.2 - k8s.io/apimachinery v0.22.2 - k8s.io/client-go v0.22.2 - k8s.io/klog/v2 v2.9.0 - sigs.k8s.io/kind v0.10.0 + github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + golang.org/x/net v0.0.0-20211216030914-fe4d6282115f + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + k8s.io/api v0.22.5 + k8s.io/apimachinery v0.22.5 + k8s.io/client-go v0.22.5 + k8s.io/klog/v2 v2.40.1 + sigs.k8s.io/kind v0.11.1 ) diff --git a/go.sum b/go.sum index 28d0c264..befc6b0c 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,20 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -22,6 +36,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -43,72 +58,67 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alessio/shellescape v1.2.2 h1:8LnL+ncxhWT2TR00dfJRT25JWWrhkMZXneHVWnetDZg= -github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU= +github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3 h1:uI/fFG5+s/On/vH4eAaeYTKSliqmlnzzWL85zeI4zOM= -github.com/cloudflare/ipvs v0.0.0-20210114211356-96b2597859b3/go.mod h1:4zyIiC//fAlPlMC9LYUmHPn8Ak/aj41FKFXuWoK8CvU= +github.com/cloudflare/ipvs v0.8.0 h1:2cl7WMwQI6pklBcwrzdusAqHuPThu/VBdAFNl5r/D5w= +github.com/cloudflare/ipvs v0.8.0/go.mod h1:rL2uv7wRPwNsyRig+6EJybJVLVIuw7+L6dc8DPyn+84= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -121,37 +131,40 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= -github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.2.0 h1:8ozOH5xxoMYDt5/u+yMTsVXydVCbTORFnOOoq2lumco= +github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -160,34 +173,32 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -201,6 +212,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -216,9 +229,10 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= @@ -230,15 +244,19 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -246,72 +264,86 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e h1:sgh63o+pm5kcdrgyYaCIoeD7mccyL6MscVmy+DvY6C4= -github.com/insomniacslk/dhcp v0.0.0-20210621130208-1cac67f12b1e/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= +github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as= +github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -322,17 +354,19 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= -github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943 h1:REP5ibuxEIcBcG837UAei093pVqmOPm/tw0TbUd18YI= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= +github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= +github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= +github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190 h1:iycCSDo8EKVueI9sfVBBJmtNn9DnXV/K1YWwEJO+uOs= +github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -350,48 +384,64 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= +github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI= -github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= +github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5 h1:w1Lne6x7QKrrkAviNvSd0M3NYblM1n76Pv2FsGkNzzI= +github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= -github.com/mdlayher/netlink v1.2.1 h1:Q5xDCtos3xv72vqzjuAh5Ns/IUlFfoy+948yBNSktTc= github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= +github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= +github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= +github.com/mdlayher/netlink v1.4.1 h1:I154BCU+mKlIf7BgcAJB2r7QjveNPty6uNY1g9ChVfI= +github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= -github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= +github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 h1:qEtkL8n1DAHpi5/AOgAckwGQUlMe4+jhL/GMt+GKIks= +github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -399,106 +449,77 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee h1:p9cPdDaBWf5r9+arw2pUuc0aDT/tkfCEBVqfx/UBb2o= github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee/go.mod h1:QvEj9qq9o66TvTyFC0Yyn1zgSSFrno8MsptfrjyMR7A= -github.com/packethost/packngo v0.13.0 h1:VIeDY/Uju53v8LAKxiqTrfR9jkpX5PhWdnQC0h3aUU8= -github.com/packethost/packngo v0.13.0/go.mod h1:YrtUNN9IRjjqN6zK+cy2IYoi3EjHfoWTWxJkI1I1Vk0= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/packethost/packngo v0.20.0 h1:vUU1z2q+x6/pfNCwHbmdoMrXl/lin8LBk24yqtp4ZjQ= +github.com/packethost/packngo v0.20.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= -github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.23.0 h1:GXWvPYuTUenIa+BhOq/x+L/QZzCqASkVRny5KTlPDGM= -github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -506,13 +527,15 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -520,42 +543,37 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= +github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -565,58 +583,56 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= -github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -640,6 +656,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -648,6 +665,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -656,21 +677,19 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -690,21 +709,40 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c h1:SgVl/sCtkicsS7psKkje4H9YtjdEl3xsYh7N+5TDHqY= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -715,6 +753,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -722,8 +761,8 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -733,22 +772,25 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -763,50 +805,72 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200928205150-006507a75852/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -818,13 +882,13 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -833,7 +897,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -853,14 +916,23 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -877,8 +949,23 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -891,7 +978,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -910,24 +996,52 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76 h1:0pBp6vCQyvmttnWa4c74n/y2U7bAQeIUVyVvZpb7Fyo= -google.golang.org/genproto v0.0.0-20210505142820-a42aa055cf76/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -936,9 +1050,23 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -950,30 +1078,29 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -984,7 +1111,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -992,33 +1118,32 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= -k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= +k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.22.5 h1:cIPwldOYm1Slq9VLBRPtEYpyhjIm1C6aAMAoENuvN9s= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= +k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c h1:jvamsI1tn9V0S8jicyX82qaFC0H/NKxv2e5mbqsgR80= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/kind v0.10.0 h1:Tm+QITIqdRd+efLOsxZHMAfLnr5K4e3/RH8MePspEXs= -sigs.k8s.io/kind v0.10.0/go.mod h1:fb32zUw7ewC47bPwLnwhf47wd/vADtv3c38KP7sjIlo= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA= +sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= From cd5fa620d5bd30c7934451f187ecb10fe98fc27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Wed, 22 Dec 2021 00:04:41 +0100 Subject: [PATCH 201/542] pkg/vip/ndp.go: Rename Dial to Listen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function was renamed. See: https://github.com/mdlayher/ndp/commit/9dc889e4351e091936eb919a72b6dc7b8b904589 Signed-off-by: Manuel Rüger --- pkg/vip/ndp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vip/ndp.go b/pkg/vip/ndp.go index 73fec41e..75235971 100644 --- a/pkg/vip/ndp.go +++ b/pkg/vip/ndp.go @@ -24,7 +24,7 @@ func NewNDPResponder(ifaceName string) (*NdpResponder, error) { } // Use link-local address as the source IPv6 address for NDP communications. - conn, _, err := ndp.Dial(iface, ndp.LinkLocal) + conn, _, err := ndp.Listen(iface, ndp.LinkLocal) if err != nil { return nil, fmt.Errorf("creating NDP responder for %q: %s", iface.Name, err) } From 7f58bf4012c8c3c8180a030a0488470632e9d4ac Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 22 Dec 2021 10:14:20 +0000 Subject: [PATCH 202/542] removes an incorrect CAP --- pkg/kubevip/config_generator.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index ebc0849c..636203d7 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -631,7 +631,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Add: []corev1.Capability{ "NET_ADMIN", "NET_RAW", - "SYS_TIME", }, }, }, From 3507c46a51a34f6dfa339f3b41084d4282ee7cb3 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 22 Dec 2021 10:25:19 +0000 Subject: [PATCH 203/542] Removes redundant config generation and e2e fix --- cmd/kube-vip-config.go | 147 --------------------------------- cmd/kube-vip.go | 5 -- testing/e2e/kube-vip.yaml.tmpl | 2 +- 3 files changed, 1 insertion(+), 153 deletions(-) delete mode 100644 cmd/kube-vip-config.go diff --git a/cmd/kube-vip-config.go b/cmd/kube-vip-config.go deleted file mode 100644 index 2bb271f5..00000000 --- a/cmd/kube-vip-config.go +++ /dev/null @@ -1,147 +0,0 @@ -package cmd - -import ( - "fmt" - - "github.com/ghodss/yaml" - "github.com/kube-vip/kube-vip/pkg/kubevip" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - appv1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// [sample configuration] - flags -var cliConfig kubevip.Config -var cliConfigLB kubevip.LoadBalancer -var cliLocalPeer string -var cliRemotePeers, cliBackends []string - -func init() { - kubeVipSampleConfig.Flags().StringVar(&cliConfig.Interface, "interface", "eth0", "Name of the interface to bind to") - kubeVipSampleConfig.Flags().StringVar(&cliConfig.VIP, "vip", "192.168.0.1", "The Virtual IP address") - kubeVipSampleConfig.Flags().BoolVar(&cliConfig.SingleNode, "singleNode", false, "Start this instance as a single node") - kubeVipSampleConfig.Flags().BoolVar(&cliConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") - kubeVipSampleConfig.Flags().BoolVar(&cliConfig.EnableARP, "arp", true, "Use ARP broadcasts to improve VIP re-allocations") - kubeVipSampleConfig.Flags().StringVar(&cliLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") - kubeVipSampleConfig.Flags().StringSliceVar(&cliRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma separated remotePeers, format: id:address:port") - // Load Balancer flags - kubeVipSampleConfig.Flags().BoolVar(&cliConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP") - kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)") - kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance") - kubeVipSampleConfig.Flags().IntVar(&cliConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") - kubeVipSampleConfig.Flags().StringSliceVar(&cliBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") - kubeVipSampleConfig.Flags().StringVar(&cliConfigLB.ForwardingMethod, "lbForwardingMethod", "local", "The forwarding method of a load balancer instance") -} - -var kubeVipSampleConfig = &cobra.Command{ - Use: "config", - Short: "Generate a Sample configuration", - Run: func(cmd *cobra.Command, args []string) { - - // // Parse localPeer - // p, err := kubevip.ParsePeerConfig(cliLocalPeer) - // if err != nil { - // cmd.Help() - // log.Fatalln(err) - // } - // cliConfig.LocalPeer = *p - - // // Parse remotePeers - // //Iterate backends - // for i := range cliRemotePeers { - // p, err := kubevip.ParsePeerConfig(cliRemotePeers[i]) - // if err != nil { - // cmd.Help() - // log.Fatalln(err) - // } - // cliConfig.RemotePeers = append(cliConfig.RemotePeers, *p) - // } - - // //Iterate backends - // for i := range cliBackends { - // b, err := kubevip.ParseBackendConfig(cliBackends[i]) - // if err != nil { - // cmd.Help() - // log.Fatalln(err) - // } - // cliConfigLB.Backends = append(cliConfigLB.Backends, *b) - // } - - // Add the basic Load-Balancer to the configuration - cliConfig.LoadBalancers = append(cliConfig.LoadBalancers, cliConfigLB) - - err := cliConfig.ParseFlags(cliLocalPeer, cliRemotePeers, cliBackends) - if err != nil { - _ = cmd.Help() - log.Fatalln(err) - } - - err = kubevip.ParseEnvironment(&cliConfig) - if err != nil { - _ = cmd.Help() - log.Fatalln(err) - } - - cliConfig.PrintConfig() - }, -} - -var kubeVipSampleManifest = &cobra.Command{ - Use: "manifest", - Short: "Generate a Sample kubernetes manifest", - Run: func(cmd *cobra.Command, args []string) { - // Generate the sample manifest specification - p := &appv1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "kube-vip", - Namespace: "kube-system", - }, - Spec: appv1.PodSpec{ - Containers: []appv1.Container{ - { - Name: "kube-vip", - Image: fmt.Sprintf("ghcr.io/kube-vip/kube-vip:%s", Release.Version), - SecurityContext: &appv1.SecurityContext{ - Capabilities: &appv1.Capabilities{ - Add: []appv1.Capability{ - "NET_ADMIN", - "SYS_TIME", - }, - }, - }, - Args: []string{ - "start", - "-c", - "/etc/kube-vip/config.yaml", - }, - VolumeMounts: []appv1.VolumeMount{ - { - Name: "config", - MountPath: "/etc/kube-vip/", - }, - }, - }, - }, - Volumes: []appv1.Volume{ - { - Name: "config", - VolumeSource: appv1.VolumeSource{ - HostPath: &appv1.HostPathVolumeSource{ - Path: "/etc/kube-vip/", - }, - }, - }, - }, - HostNetwork: true, - }, - } - - b, _ := yaml.Marshal(p) - fmt.Print(string(b)) - }, -} diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index b441e9c1..253e20b6 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -127,11 +127,6 @@ func init() { kubeVipCmd.AddCommand(kubeVipService) kubeVipCmd.AddCommand(kubeVipStart) kubeVipCmd.AddCommand(kubeVipVersion) - - // Sample commands - kubeVipSample.AddCommand(kubeVipSampleConfig) - kubeVipSample.AddCommand(kubeVipSampleManifest) - } // Execute - starts the command parsing process diff --git a/testing/e2e/kube-vip.yaml.tmpl b/testing/e2e/kube-vip.yaml.tmpl index a8c77b32..063a7b12 100644 --- a/testing/e2e/kube-vip.yaml.tmpl +++ b/testing/e2e/kube-vip.yaml.tmpl @@ -30,7 +30,7 @@ spec: capabilities: add: - NET_ADMIN - - SYS_TIME + - NET_RAW volumeMounts: - mountPath: /etc/kubernetes/admin.conf name: kubeconfig From 179cfef6e25b4e00833b69d1a10c89b428503422 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 22 Dec 2021 11:06:55 +0000 Subject: [PATCH 204/542] New 0.4.1 release --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bf4222ac..7d881b17 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.4.0 +VERSION := v0.4.1 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 0f391a00321b2d8ec9c3486b26a066fa92374711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Wed, 22 Dec 2021 13:32:34 +0100 Subject: [PATCH 205/542] docs: Generate manifests for 0.4.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml | 70 ++++++++++++++++ docs/manifests/v0.4.1/kube-vip-arp-ds.yaml | 64 ++++++++++++++ docs/manifests/v0.4.1/kube-vip-arp-lb.yaml | 66 +++++++++++++++ docs/manifests/v0.4.1/kube-vip-arp.yaml | 60 ++++++++++++++ docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml | 73 ++++++++++++++++ docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml | 83 +++++++++++++++++++ docs/manifests/v0.4.1/kube-vip-bgp.yaml | 61 ++++++++++++++ 7 files changed, 477 insertions(+) create mode 100644 docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-arp-ds.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-arp-lb.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-arp.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml create mode 100644 docs/manifests/v0.4.1/kube-vip-bgp.yaml diff --git a/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml b/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml new file mode 100644 index 00000000..91e6c7c8 --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: lb_enable + value: "true" + - name: lb_port + value: "6443" + - name: lb_fwdmethod + value: local + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml b/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml new file mode 100644 index 00000000..c37cf21a --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml b/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml new file mode 100644 index 00000000..81746ccf --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml @@ -0,0 +1,66 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: lb_enable + value: "true" + - name: lb_port + value: "6443" + - name: lb_fwdmethod + value: local + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.4.1/kube-vip-arp.yaml b/docs/manifests/v0.4.1/kube-vip-arp.yaml new file mode 100644 index 00000000..f3fe9c68 --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-arp.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "true" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + diff --git a/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml b/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml new file mode 100644 index 00000000..c8bebaf4 --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + hostNetwork: true + serviceAccountName: kube-vip + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml new file mode 100644 index 00000000..6b4eb5b1 --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml @@ -0,0 +1,83 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + creationTimestamp: null + name: kube-vip-ds + namespace: kube-system +spec: + selector: + matchLabels: + name: kube-vip-ds + template: + metadata: + creationTimestamp: null + labels: + name: kube-vip-ds + spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "5" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: provider_config + value: /etc/cloud-sa/cloud-sa.json + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + - mountPath: /etc/cloud-sa + name: cloud-sa-volume + readOnly: true + hostNetwork: true + serviceAccountName: kube-vip + volumes: + - name: cloud-sa-volume + secret: + secretName: metal-cloud-config + updateStrategy: {} +status: + currentNumberScheduled: 0 + desiredNumberScheduled: 0 + numberMisscheduled: 0 + numberReady: 0 + diff --git a/docs/manifests/v0.4.1/kube-vip-bgp.yaml b/docs/manifests/v0.4.1/kube-vip-bgp.yaml new file mode 100644 index 00000000..03b22bf5 --- /dev/null +++ b/docs/manifests/v0.4.1/kube-vip-bgp.yaml @@ -0,0 +1,61 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: kube-vip + namespace: kube-system +spec: + containers: + - args: + - manager + env: + - name: vip_arp + value: "false" + - name: port + value: "6443" + - name: vip_interface + value: eth0 + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: svc_enable + value: "true" + - name: bgp_enable + value: "true" + - name: bgp_routerid + - name: bgp_as + value: "65000" + - name: bgp_peeraddress + - name: bgp_peerpass + - name: bgp_peeras + value: "65000" + - name: vip_address + value: 192.168.0.1 + image: ghcr.io/kube-vip/kube-vip:v0.4.1 + imagePullPolicy: Always + name: kube-vip + resources: {} + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/admin.conf + name: kubeconfig +status: {} + From 306ce2440e90342dbcb332931aedd9dd61de43d2 Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Wed, 22 Dec 2021 20:37:35 +0800 Subject: [PATCH 206/542] Monitor default VIP interface The kube-vip chooses the default interface based on the default route. Once the default route changes, the default interface may be invalid. In this case, it would be better to crash the process. The pod will restart immediately if the kube-vip is deployed as a daemonset. Signed-off-by: yaocw2020 --- cmd/kube-vip.go | 6 ++++++ pkg/vip/util.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index b441e9c1..7806630c 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -224,6 +224,12 @@ var kubeVipManager = &cobra.Command{ } initConfig.Interface = defaultIF.Name log.Infof("kube-vip will bind to interface [%s]", initConfig.Interface) + + go func() { + if err := vip.MonitorDefaultInterface(context.TODO(), defaultIF); err != nil { + log.Fatalf("crash: %s", err.Error()) + } + }() } go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ diff --git a/pkg/vip/util.go b/pkg/vip/util.go index a7335a46..6b8899bb 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -1,12 +1,14 @@ package vip import ( + "context" "fmt" "net" "strings" "syscall" "github.com/pkg/errors" + log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" ) @@ -85,3 +87,23 @@ func GetDefaultGatewayInterface() (*net.Interface, error) { return nil, errors.New("Unable to find default route") } + +// MonitorDefaultInterface monitor the default interface and catch the event of the default route +func MonitorDefaultInterface(ctx context.Context, defaultIF *net.Interface) error { + routeCh := make(chan netlink.RouteUpdate) + if err := netlink.RouteSubscribe(routeCh, ctx.Done()); err != nil { + return fmt.Errorf("subscribe route failed, error: %w", err) + } + + for { + select { + case r := <-routeCh: + log.Infof("route event: %+v", r) + 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") + } + case <-ctx.Done(): + return nil + } + } +} From afd9029474a38827fc0841f14c44d2a65aad0e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Wed, 22 Dec 2021 13:50:46 +0100 Subject: [PATCH 207/542] config: Use recommended labels in manifests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ Fixes: https://github.com/kube-vip/kube-vip/issues/315 Signed-off-by: Manuel Rüger --- cmd/kube-vip-manifests.go | 2 +- pkg/kubevip/config_generator.go | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index ec01e096..093a3a02 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -75,7 +75,7 @@ var kubeManifestDaemon = &cobra.Command{ _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GenerateDeamonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) + cfg := kubevip.GenerateDaemonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) fmt.Println(cfg) }, diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 636203d7..874b08fe 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -703,8 +703,8 @@ func GeneratePodManifestFromConfig(c *Config, imageVersion string, inCluster boo return string(b) } -// GenerateDeamonsetManifestFromConfig will take a kube-vip config and generate a manifest -func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inCluster, taint bool) string { +// GenerateDaemonsetManifestFromConfig will take a kube-vip config and generate a manifest +func GenerateDaemonsetManifestFromConfig(c *Config, imageVersion string, inCluster, taint bool) string { podSpec := generatePodSpec(c, imageVersion, inCluster).Spec newManifest := &appv1.DaemonSet{ @@ -715,17 +715,22 @@ func GenerateDeamonsetManifestFromConfig(c *Config, imageVersion string, inClust ObjectMeta: metav1.ObjectMeta{ Name: "kube-vip-ds", Namespace: "kube-system", + Labels: map[string]string{ + "app.kubernetes.io/name": "kube-vip-ds", + "app.kubernetes.io/version": imageVersion, + }, }, Spec: appv1.DaemonSetSpec{ Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "name": "kube-vip-ds", + "app.kubernetes.io/name": "kube-vip-ds", }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - "name": "kube-vip-ds", + "app.kubernetes.io/name": "kube-vip-ds", + "app.kubernetes.io/version": imageVersion, }, }, Spec: podSpec, From 98f0a9505b5ae9ea85bf62572c5d9797d3fdd2ae Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Wed, 22 Dec 2021 22:44:16 +0800 Subject: [PATCH 208/542] set route event log as debug level Signed-off-by: yaocw2020 --- pkg/vip/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vip/util.go b/pkg/vip/util.go index 6b8899bb..48a2050d 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -98,7 +98,7 @@ func MonitorDefaultInterface(ctx context.Context, defaultIF *net.Interface) erro for { select { case r := <-routeCh: - log.Infof("route event: %+v", r) + log.Debugf("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") } From ec0014d9ea96cd482088df60c317040886c445ac Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 23 Dec 2021 10:23:05 +0000 Subject: [PATCH 209/542] Add logo --- kube-vip.png | Bin 0 -> 57966 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 kube-vip.png diff --git a/kube-vip.png b/kube-vip.png new file mode 100644 index 0000000000000000000000000000000000000000..f2f7bf963a55df3b68131933c9b0e1f2d24db544 GIT binary patch literal 57966 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

a%dbO{8*mR1SI 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

6&UI-lHwuf`=P=4@OL9w;w6nmn^ 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 bd*}tX%ihO&1cUxL5%{UAXd%m$tY7{gkX`?& literal 0 HcmV?d00001 From 056a6c5c16c9b5434be442d6723f29088524e22c Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 23 Dec 2021 10:23:56 +0000 Subject: [PATCH 210/542] Update readme with correct URL for logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21f32b08..185f1a64 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ High Availability and Load-Balancing -![](https://kube-vip.io/kube-vip.png) +![](https://github.com/kube-vip/kube-vip/raw/main/kube-vip.png) ## Overview Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services From c037ac35617936b4e25b5b8bc188ebaf89691635 Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Thu, 6 Jan 2022 00:32:31 +0800 Subject: [PATCH 211/542] Build and publish the main image every day Signed-off-by: yaocw2020 --- .github/workflows/ci.yaml | 1 - .github/workflows/main.yaml | 24 +++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a426b169..b07777a6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,7 +2,6 @@ name: For each commit and PR on: push: pull_request: - jobs: validation: runs-on: ubuntu-latest diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 03891912..678c51c0 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -1,43 +1,37 @@ -name: Publish the latest dev image +name: Build and publish main image regularly on: - push: - branches: - - 'master' + schedule: + - cron: '25 0 * * *' jobs: - docker: + docker-publish: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - - name: Prepare Names id: prep run: | DOCKER_IMAGE=plndr/kube-vip - VERSION=$(echo ${GITHUB_SHA} | cut -c1-8) - TAGS="${DOCKER_IMAGE}:${VERSION}" - TAGS="$TAGS,${DOCKER_IMAGE}:nightly" + VERSION=main + TAGS="${DOCKER_IMAGE}:${VERSION},ghcr.io/kube-vip/kube-vip:${VERSION}" echo ::set-output name=tags::${TAGS} - - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push main branch + - name: Build and push main branch uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.prep.outputs.tags }} - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file + run: echo ${{ steps.docker_build.outputs.digest }} From 1a4465ebcce6134e86a9934a67ea3722dfbb6087 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Mon, 10 Jan 2022 11:22:54 -0600 Subject: [PATCH 212/542] Don't check interface is up if it's loopback. Signed-off-by: Chris Privitere --- pkg/kubevip/config_manager.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 8a0fca8a..8b5f8248 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -3,6 +3,7 @@ package kubevip import ( "fmt" "io/ioutil" + "net" "os" "strconv" "strings" @@ -205,6 +206,10 @@ func isValidInterface(iface string) error { return fmt.Errorf("get %s failed, error: %w", iface, err) } + if l.Attrs().Flags&net.FlagLoopback == net.FlagLoopback { + return nil + } + if l.Attrs().OperState != netlink.OperUp { return fmt.Errorf("%s is not up", iface) } From 0d5a140f0dcd31a4046e886311aafc7b25cd2ed2 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:07:19 -0600 Subject: [PATCH 213/542] Rename to docker since it's also building. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 678c51c0..e55b7eb0 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -5,7 +5,7 @@ on: - cron: '25 0 * * *' jobs: - docker-publish: + docker: runs-on: ubuntu-latest steps: - name: Checkout From 777eddafd8bbac85cc34d5f628e2910ecf3a295b Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:08:05 -0600 Subject: [PATCH 214/542] Move from env vars to github contexts. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index e55b7eb0..a7acdc38 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -10,13 +10,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Prepare Names - id: prep - run: | - DOCKER_IMAGE=plndr/kube-vip - VERSION=main - TAGS="${DOCKER_IMAGE}:${VERSION},ghcr.io/kube-vip/kube-vip:${VERSION}" - echo ::set-output name=tags::${TAGS} - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx From ad355fb6f672e33fd9463e6a97726062f470a7e4 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:08:30 -0600 Subject: [PATCH 215/542] Add login for github packages. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a7acdc38..f1a2507e 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -19,6 +19,12 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Github Packages + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push main branch uses: docker/build-push-action@v2 with: From ae22483f088d042d99e7bcf6815290aaeaa2d654 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:08:50 -0600 Subject: [PATCH 216/542] Add id as per docker-build-push pattern. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index f1a2507e..baec9dc3 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -26,6 +26,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push main branch + id: docker_build uses: docker/build-push-action@v2 with: context: . From d1aa8bcb6f58aeb71f8776c5dfc8c72cf54579d2 Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:09:22 -0600 Subject: [PATCH 217/542] Switch to doing the tags with a github context. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index baec9dc3..492401d0 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -32,6 +32,6 @@ jobs: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.prep.outputs.tags }} + tags: plndr/kube-vip:${{ github.ref_name }},ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} + run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file From 1e0523fa8afe4b24cb063412bcc589fb381026ea Mon Sep 17 00:00:00 2001 From: Chris Privitere Date: Tue, 11 Jan 2022 15:28:56 -0600 Subject: [PATCH 218/542] Use same formatting for main and release. Signed-off-by: Chris Privitere --- .github/workflows/main.yaml | 4 +++- .github/workflows/release.yaml | 21 +++++++-------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 492401d0..3538a368 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -32,6 +32,8 @@ jobs: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} - tags: plndr/kube-vip:${{ github.ref_name }},ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} + tags: >- + plndr/kube-vip:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bc5ecf40..5d465c5e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -10,16 +10,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - - name: Prepare Names - id: prep - run: | - DOCKER_IMAGE=plndr/kube-vip - VERSION=${GITHUB_REF#refs/tags/} - TAGS="${DOCKER_IMAGE}:${VERSION},ghcr.io/kube-vip/kube-vip:${VERSION}" - TAGS="$TAGS,${DOCKER_IMAGE}:latest,ghcr.io/kube-vip/kube-vip:latest" - echo ::set-output name=tags::${TAGS} - - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx @@ -35,14 +25,17 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push main branch + - name: Build and push main branch + id: docker_build uses: docker/build-push-action@v2 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.prep.outputs.tags }} - + tags: >- + plndr/kube-vip:${{ github.ref_name }}, + plndr/kube-vip:latest, + ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip:latest - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} From 8448c1224e1405ce50615bb58de58f2cf7e4f855 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 9 Feb 2022 11:10:37 +0000 Subject: [PATCH 219/542] Bump new release to 4.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d881b17..b801af35 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.4.1 +VERSION := v0.4.2 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From e9ea9056934c3252580c597383a4a742d1b93cab Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 9 Feb 2022 11:16:42 +0000 Subject: [PATCH 220/542] Fix environment variable and tidy --- pkg/kubevip/config_endpoints.go | 71 ------- pkg/kubevip/config_environment.go | 329 ++++++++++++++++++++++++++++++ pkg/kubevip/config_envvar.go | 4 +- pkg/kubevip/config_generator.go | 329 ------------------------------ pkg/kubevip/config_manager.go | 10 +- 5 files changed, 335 insertions(+), 408 deletions(-) delete mode 100644 pkg/kubevip/config_endpoints.go create mode 100644 pkg/kubevip/config_environment.go diff --git a/pkg/kubevip/config_endpoints.go b/pkg/kubevip/config_endpoints.go deleted file mode 100644 index c9717319..00000000 --- a/pkg/kubevip/config_endpoints.go +++ /dev/null @@ -1,71 +0,0 @@ -package kubevip - -import ( - "fmt" - "net/url" - "strconv" - - log "github.com/sirupsen/logrus" -) - -func init() { - // Start the index negative as it will be incrememnted of first approach - endPointIndex = -1 -} - -// ValidateBackEndURLS will run through the endpoints and ensure that they're a valid URL -func ValidateBackEndURLS(endpoints *[]BackEnd) error { - - for i := range *endpoints { - log.Debugf("Parsing [%s]", (*endpoints)[i].RawURL) - u, err := url.Parse((*endpoints)[i].RawURL) - if err != nil { - return err - } - - // No error is returned if the prefix/schema is missing - // If the Host is empty then we were unable to parse correctly (could be prefix is missing) - if u.Host == "" { - return fmt.Errorf("Unable to parse [%s], ensure it's prefixed with http(s)://", (*endpoints)[i].RawURL) - } - (*endpoints)[i].Address = u.Hostname() - // if a port is specified then update the internal endpoint stuct, if not rely on the schema - if u.Port() != "" { - portNum, err := strconv.Atoi(u.Port()) - if err != nil { - return err - } - (*endpoints)[i].Port = portNum - } - (*endpoints)[i].ParsedURL = u - } - return nil -} - -// ReturnEndpointAddr - returns an endpoint -func (lb LoadBalancer) ReturnEndpointAddr() (string, error) { - if len(lb.Backends) == 0 { - return "", fmt.Errorf("No Backends configured") - } - if endPointIndex < len(lb.Backends)-1 { - endPointIndex++ - } else { - // reset the index to the beginning - endPointIndex = 0 - } - // TODO - weighting, decision algorythmn - return fmt.Sprintf("%s:%d", lb.Backends[endPointIndex].Address, lb.Backends[endPointIndex].Port), nil -} - -// ReturnEndpointURL - returns an endpoint -func (lb LoadBalancer) ReturnEndpointURL() *url.URL { - - if endPointIndex != len(lb.Backends)-1 { - endPointIndex++ - } else { - // reset the index to the beginning - endPointIndex = 0 - } - // TODO - weighting, decision algorythmn - return lb.Backends[endPointIndex].ParsedURL -} diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go new file mode 100644 index 00000000..5718914a --- /dev/null +++ b/pkg/kubevip/config_environment.go @@ -0,0 +1,329 @@ +package kubevip + +import ( + "os" + "strconv" + + "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/detector" + log "github.com/sirupsen/logrus" +) + +// ParseEnvironment - will popultate the configuration from environment variables +func ParseEnvironment(c *Config) error { + + // Ensure that logging is set through the environment variables + env := os.Getenv(vipLogLevel) + if env != "" { + logLevel, err := strconv.Atoi(env) + if err != nil { + panic("Unable to parse environment variable [vip_loglevel], should be int") + } + log.SetLevel(log.Level(logLevel)) + } + + // Find interface + env = os.Getenv(vipInterface) + if env != "" { + c.Interface = env + } + + // Find (services) interface + env = os.Getenv(vipServicesInterface) + if env != "" { + c.ServicesInterface = env + } + + // Find provider configuration + env = os.Getenv(providerConfig) + if env != "" { + c.ProviderConfig = env + } + + // Find Kubernetes Leader Election configuration + env = os.Getenv(vipLeaderElection) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableLeaderElection = b + } + + // Attempt to find the Lease configuration from the environment variables + env = os.Getenv(vipLeaseDuration) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.LeaseDuration = int(i) + } + + env = os.Getenv(vipRenewDeadline) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.RenewDeadline = int(i) + } + + env = os.Getenv(vipRetryPeriod) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.RetryPeriod = int(i) + } + + // Find vip address + env = os.Getenv(vipAddress) + if env != "" { + // TODO - parse address net.Host() + c.VIP = env + // } else { + // c.VIP = os.Getenv(address) + } + + // Find address + env = os.Getenv(address) + if env != "" { + // TODO - parse address net.Host() + c.Address = env + } + + // Find vip port + env = os.Getenv(port) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.Port = int(i) + } + + // Find vipDdns + env = os.Getenv(vipDdns) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.DDNS = b + } + + // Find the namespace that the control pane should use (for leaderElection lock) + env = os.Getenv(cpNamespace) + if env != "" { + c.Namespace = env + } + + // Find controlplane toggle + env = os.Getenv(cpEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableControlPane = b + } + + // Find Services toggle + env = os.Getenv(svcEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableServices = b + } + + // Find vip address cidr range + env = os.Getenv(vipCidr) + if env != "" { + c.VIPCIDR = env + } + + // Find Single Node + env = os.Getenv(vipSingleNode) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.SingleNode = b + } + + // Find annotation configuration + env = os.Getenv(annotations) + if env != "" { + c.Annotations = env + } + + // Find Start As Leader + // TODO - does this need depricating? + // Required when the host sets itself as leader before the state change + env = os.Getenv(vipStartLeader) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.StartAsLeader = b + } + + // Find ARP + env = os.Getenv(vipArp) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableARP = b + } + + // BGP Server options + env = os.Getenv(bgpEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableBGP = b + } + + // BGP Router interface determines an interface that we can use to find an address for + env = os.Getenv(bgpRouterInterface) + if env != "" { + _, address, err := detector.FindIPAddress(env) + if err != nil { + return err + } + c.BGPConfig.RouterID = address + } + + // RouterID + env = os.Getenv(bgpRouterID) + if env != "" { + c.BGPConfig.RouterID = env + } + + // AS + env = os.Getenv(bgpRouterAS) + if env != "" { + u64, err := strconv.ParseUint(env, 10, 32) + if err != nil { + return err + } + c.BGPConfig.AS = uint32(u64) + } + + // Peer AS + env = os.Getenv(bgpPeerAS) + if env != "" { + u64, err := strconv.ParseUint(env, 10, 32) + if err != nil { + return err + } + c.BGPPeerConfig.AS = uint32(u64) + } + + // Peer AS + env = os.Getenv(bgpPeers) + if env != "" { + peers, err := bgp.ParseBGPPeerConfig(env) + if err != nil { + return err + } + c.BGPConfig.Peers = peers + } + + // BGP Peer mutlihop + env = os.Getenv(bgpMultiHop) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.BGPPeerConfig.MultiHop = b + } + + // BGP Peer password + env = os.Getenv(bgpPeerPassword) + if env != "" { + c.BGPPeerConfig.Password = env + } + + // BGP Source Interface + env = os.Getenv(bgpSourceIF) + if env != "" { + c.BGPConfig.SourceIF = env + } + + // BGP Source Address + env = os.Getenv(bgpSourceIP) + if env != "" { + c.BGPConfig.SourceIP = env + } + + // BGP Peer options, add them if relevant + env = os.Getenv(bgpPeerAddress) + if env != "" { + c.BGPPeerConfig.Address = env + // If we've added in a peer configuration, then we should add it to the BGP configuration + c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig) + } + + // Enable the Packet API calls + env = os.Getenv(vipPacket) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableMetal = b + } + + // Find the Packet project name + env = os.Getenv(vipPacketProject) + if env != "" { + // TODO - parse address net.Host() + c.MetalProject = env + } + + // Find the Packet project ID + env = os.Getenv(vipPacketProjectID) + if env != "" { + // TODO - parse address net.Host() + c.MetalProjectID = env + } + + // Enable the load-balancer + env = os.Getenv(lbEnable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableLoadBalancer = b + } + + // Find loadbalancer port + env = os.Getenv(lbPort) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.LoadBalancerPort = int(i) + } + + // Find loadbalancer forwarding method + env = os.Getenv(lbForwardingMethod) + if env != "" { + c.LoadBalancerForwardingMethod = env + } + return nil +} diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 76cd3248..9e4584c3 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -90,9 +90,9 @@ const ( //bgpMultiHop enables mulithop routing bgpMultiHop = "bgp_multihop" //bgpSourceIF defines the source interface for BGP peering - bgpSourceIF = "bgp_source_if" + bgpSourceIF = "bgp_sourceif" //bgpSourceIP defines the source address for BGP peering - bgpSourceIP = "bgp_source_ip" + bgpSourceIP = "bgp_sourceip" //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 874b08fe..28671d01 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -2,343 +2,14 @@ package kubevip import ( "fmt" - "os" "strconv" "github.com/ghodss/yaml" - "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/detector" - log "github.com/sirupsen/logrus" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// ParseEnvironment - will popultate the configuration from environment variables -func ParseEnvironment(c *Config) error { - - // Ensure that logging is set through the environment variables - env := os.Getenv(vipLogLevel) - if env != "" { - logLevel, err := strconv.Atoi(env) - if err != nil { - panic("Unable to parse environment variable [vip_loglevel], should be int") - } - log.SetLevel(log.Level(logLevel)) - } - - // Find interface - env = os.Getenv(vipInterface) - if env != "" { - c.Interface = env - } - - // Find (services) interface - env = os.Getenv(vipServicesInterface) - if env != "" { - c.ServicesInterface = env - } - - // Find provider configuration - env = os.Getenv(providerConfig) - if env != "" { - c.ProviderConfig = env - } - - // Find Kubernetes Leader Election configuration - env = os.Getenv(vipLeaderElection) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableLeaderElection = b - } - - // Attempt to find the Lease configuration from the environment variables - env = os.Getenv(vipLeaseDuration) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.LeaseDuration = int(i) - } - - env = os.Getenv(vipRenewDeadline) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.RenewDeadline = int(i) - } - - env = os.Getenv(vipRetryPeriod) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.RetryPeriod = int(i) - } - - // Find vip address - env = os.Getenv(vipAddress) - if env != "" { - // TODO - parse address net.Host() - c.VIP = env - // } else { - // c.VIP = os.Getenv(address) - } - - // Find address - env = os.Getenv(address) - if env != "" { - // TODO - parse address net.Host() - c.Address = env - } - - // Find vip port - env = os.Getenv(port) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.Port = int(i) - } - - // Find vipDdns - env = os.Getenv(vipDdns) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.DDNS = b - } - - // Find vip address cidr range - env = os.Getenv(cpNamespace) - if env != "" { - c.Namespace = env - } - - // Find the namespace that the control pane should use (for leaderElection lock) - env = os.Getenv(cpNamespace) - if env != "" { - c.Namespace = env - } - - // Find controlplane toggle - env = os.Getenv(cpEnable) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableControlPane = b - } - - // Find Services toggle - env = os.Getenv(svcEnable) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableServices = b - } - - // Find vip address cidr range - env = os.Getenv(vipCidr) - if env != "" { - c.VIPCIDR = env - } - - // Find Single Node - env = os.Getenv(vipSingleNode) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.SingleNode = b - } - - // Find annotation configuration - env = os.Getenv(annotations) - if env != "" { - c.Annotations = env - } - - // Find Start As Leader - // TODO - does this need depricating? - // Required when the host sets itself as leader before the state change - env = os.Getenv(vipStartLeader) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.StartAsLeader = b - } - - // Find ARP - env = os.Getenv(vipArp) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableARP = b - } - - // BGP Server options - env = os.Getenv(bgpEnable) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableBGP = b - } - - // BGP Router interface determines an interface that we can use to find an address for - env = os.Getenv(bgpRouterInterface) - if env != "" { - _, address, err := detector.FindIPAddress(env) - if err != nil { - return err - } - c.BGPConfig.RouterID = address - } - - // RouterID - env = os.Getenv(bgpRouterID) - if env != "" { - c.BGPConfig.RouterID = env - } - - // AS - env = os.Getenv(bgpRouterAS) - if env != "" { - u64, err := strconv.ParseUint(env, 10, 32) - if err != nil { - return err - } - c.BGPConfig.AS = uint32(u64) - } - - // Peer AS - env = os.Getenv(bgpPeerAS) - if env != "" { - u64, err := strconv.ParseUint(env, 10, 32) - if err != nil { - return err - } - c.BGPPeerConfig.AS = uint32(u64) - } - - // Peer AS - env = os.Getenv(bgpPeers) - if env != "" { - peers, err := bgp.ParseBGPPeerConfig(env) - if err != nil { - return err - } - c.BGPConfig.Peers = peers - } - - // BGP Peer mutlihop - env = os.Getenv(bgpMultiHop) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.BGPPeerConfig.MultiHop = b - } - - // BGP Peer password - env = os.Getenv(bgpPeerPassword) - if env != "" { - c.BGPPeerConfig.Password = env - } - - // BGP Source Interface - env = os.Getenv(bgpSourceIF) - if env != "" { - c.BGPConfig.SourceIF = env - } - - // BGP Source Address - env = os.Getenv(bgpSourceIP) - if env != "" { - c.BGPConfig.SourceIP = env - } - - // BGP Peer options, add them if relevant - env = os.Getenv(bgpPeerAddress) - if env != "" { - c.BGPPeerConfig.Address = env - // If we've added in a peer configuration, then we should add it to the BGP configuration - c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig) - } - - // Enable the Packet API calls - env = os.Getenv(vipPacket) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableMetal = b - } - - // Find the Packet project name - env = os.Getenv(vipPacketProject) - if env != "" { - // TODO - parse address net.Host() - c.MetalProject = env - } - - // Find the Packet project ID - env = os.Getenv(vipPacketProjectID) - if env != "" { - // TODO - parse address net.Host() - c.MetalProjectID = env - } - - // Enable the load-balancer - env = os.Getenv(lbEnable) - if env != "" { - b, err := strconv.ParseBool(env) - if err != nil { - return err - } - c.EnableLoadBalancer = b - } - - // Find loadbalancer port - env = os.Getenv(lbPort) - if env != "" { - i, err := strconv.ParseInt(env, 10, 32) - if err != nil { - return err - } - c.LoadBalancerPort = int(i) - } - - // Find loadbalancer forwarding method - env = os.Getenv(lbForwardingMethod) - if env != "" { - c.LoadBalancerForwardingMethod = env - } - return nil -} - // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 8b5f8248..6bca2245 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -13,13 +13,11 @@ import ( "github.com/vishvananda/netlink" ) -var endPointIndex int // Holds the previous endpoint (for determining decisions on next endpoint) - //ParseBackendConfig - func ParseBackendConfig(ep string) (*BackEnd, error) { endpoint := strings.Split(ep, ":") if len(endpoint) != 2 { - return nil, fmt.Errorf("Ensure a backend is in in the format address:port, e.g. 10.0.0.1:8080") + return nil, fmt.Errorf("ensure a backend is in in the format address:port, e.g. 10.0.0.1:8080") } p, err := strconv.Atoi(endpoint[1]) if err != nil { @@ -32,7 +30,7 @@ func ParseBackendConfig(ep string) (*BackEnd, error) { func ParsePeerConfig(ep string) (*RaftPeer, error) { endpoint := strings.Split(ep, ":") if len(endpoint) != 3 { - return nil, fmt.Errorf("Ensure a peer is in in the format id:address:port, e.g. server1:10.0.0.1:8080") + return nil, fmt.Errorf("ensure a peer is in in the format id:address:port, e.g. server1:10.0.0.1:8080") } p, err := strconv.Atoi(endpoint[2]) if err != nil { @@ -44,7 +42,7 @@ func ParsePeerConfig(ep string) (*RaftPeer, error) { //OpenConfig will attempt to read a file and parse it's contents into a configuration func OpenConfig(path string) (*Config, error) { if path == "" { - return nil, fmt.Errorf("Path cannot be blank") + return nil, fmt.Errorf("path cannot be blank") } log.Infof("Reading configuration from [%s]", path) @@ -66,7 +64,7 @@ func OpenConfig(path string) (*Config, error) { return &c, nil } - return nil, fmt.Errorf("Error reading [%s]", path) + return nil, fmt.Errorf("error reading [%s]", path) } //PrintConfig - will print out an instance of the kubevip config From ff3a010a8d2e61253588b7f2d40e549b5a03e35d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 9 Feb 2022 11:37:47 +0000 Subject: [PATCH 221/542] Security fix for unit --- pkg/kubevip/config_environment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 5718914a..018c7cb4 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -15,7 +15,7 @@ func ParseEnvironment(c *Config) error { // Ensure that logging is set through the environment variables env := os.Getenv(vipLogLevel) if env != "" { - logLevel, err := strconv.Atoi(env) + logLevel, err := strconv.ParseUint(env, 10, 32) if err != nil { panic("Unable to parse environment variable [vip_loglevel], should be int") } From 1fb1de9990e5641c9768cbfa9d6bb7746011a6fe Mon Sep 17 00:00:00 2001 From: David Flanagan Date: Mon, 14 Feb 2022 18:50:46 +0000 Subject: [PATCH 222/542] fix: spell prometheus correctly --- cmd/kube-vip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 4e69b61d..e9ed03e9 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -118,7 +118,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") // Prometheus HTTP Server - kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "promethuesHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) From 58da24127eef05f72398ae7b7482d5902f8c5eec Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 17 Feb 2022 14:42:56 +0000 Subject: [PATCH 223/542] Adds retry to status update --- pkg/manager/services.go | 10 +++++++--- pkg/manager/watcher_test.go | 3 +-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 5e039428..1e1d3452 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -10,6 +10,7 @@ import ( "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -170,9 +171,12 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { // go sm.serviceWatcher(&newService, sm.config.Namespace) // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it - service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) - if err != nil { + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} + _, updateErr := sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) + return updateErr + }) + if retryErr != nil { log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) } sm.serviceInstances = append(sm.serviceInstances, newService) diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index 7b12383f..5b65bef9 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -7,7 +7,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -61,7 +60,7 @@ func TestParseBgpAnnotations(t *testing.T) { func Test_parseBgpAnnotations(t *testing.T) { type args struct { - node *v1.Node + node *corev1.Node prefix string } tests := []struct { From 3f91c045d4a43626c29cfc981be177808adcac1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Fri, 18 Feb 2022 12:59:23 +0100 Subject: [PATCH 224/542] Build with go-1.17, bump dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 4 +- CONTRIBUTING.md | 2 +- Dockerfile | 2 +- go.mod | 94 ++++++++++++++++++++++++++++++++------- go.sum | 81 ++++++++++++++++++--------------- 5 files changed, 128 insertions(+), 55 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b07777a6..9f6601bd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,9 +15,9 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: '1.16' + go-version: '1.17' - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.42.1 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2 - name: checks run: make check - name: test docker build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cdd706d7..46528ad4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,7 +154,7 @@ the `$GOPATH`. To develop locally, you can follow these steps: - 1. [Install Go 1.15](https://golang.org/doc/install) + 1. [Install Go 1.17](https://golang.org/doc/install) 2. Checkout your feature branch and `cd` into it. 3. To build all Go files and install them under `bin`, run `make bin` 4. To run all Go unit tests, run `make test-unit` diff --git a/Dockerfile b/Dockerfile index e09b6cf0..7ac3882d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.16.12-alpine3.15 as dev +FROM golang:1.17.6-alpine3.15 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/go.mod b/go.mod index 063599c7..06758117 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,100 @@ module github.com/kube-vip/kube-vip -go 1.14 +go 1.17 require ( github.com/cloudflare/ipvs v0.8.0 github.com/davecgh/go-spew v1.1.1 github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 - github.com/google/gofuzz v1.2.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 + github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 - github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5 - github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect + github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045 github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.1 github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee - github.com/packethost/packngo v0.20.0 + github.com/packethost/packngo v0.22.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - k8s.io/api v0.22.5 - k8s.io/apimachinery v0.22.5 - k8s.io/client-go v0.22.5 + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 + k8s.io/api v0.23.4 + k8s.io/apimachinery v0.23.4 + k8s.io/client-go v0.23.4 k8s.io/klog/v2 v2.40.1 sigs.k8s.io/kind v0.11.1 ) + +require ( + github.com/BurntSushi/toml v0.4.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/eapache/channels v1.1.0 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/evanphx/json-patch/v5 v5.2.0 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/logr v1.2.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/k-sone/critbitgo v1.4.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect + github.com/mdlayher/genetlink v1.0.0 // indirect + github.com/mdlayher/netlink v1.4.1 // indirect + github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect + github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.10.0 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect + github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect + golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect + google.golang.org/grpc v1.42.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect + k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) diff --git a/go.sum b/go.sum index befc6b0c..b88a8269 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,6 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= @@ -149,8 +148,8 @@ github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPO github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.2.0 h1:8ozOH5xxoMYDt5/u+yMTsVXydVCbTORFnOOoq2lumco= github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= @@ -159,12 +158,12 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -179,11 +178,11 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= @@ -285,6 +284,7 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -340,8 +340,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as= -github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= +github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd h1:efcJu2Vzz6DoSq245deWNzTz6l/gsqdphm3FjmI88/g= +github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -385,7 +385,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -418,8 +417,8 @@ github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JA github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5 h1:w1Lne6x7QKrrkAviNvSd0M3NYblM1n76Pv2FsGkNzzI= -github.com/mdlayher/ndp v0.0.0-20210831201139-f982b8766fb5/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= +github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045 h1:cLcATbaiT+9tZwgtOqN1Duhp5bBkHLBxKlrXCf6srtI= +github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -465,8 +464,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -482,8 +482,8 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee h1:p9cPdDaBWf5r9+arw2pUuc0aDT/tkfCEBVqfx/UBb2o= github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee/go.mod h1:QvEj9qq9o66TvTyFC0Yyn1zgSSFrno8MsptfrjyMR7A= -github.com/packethost/packngo v0.20.0 h1:vUU1z2q+x6/pfNCwHbmdoMrXl/lin8LBk24yqtp4ZjQ= -github.com/packethost/packngo v0.20.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= +github.com/packethost/packngo v0.22.0 h1:7syZ1jDN5rbdkkrh9A5rA/ijXe0AHNovNqlUUf0L+uM= +github.com/packethost/packngo v0.22.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -505,8 +505,9 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -517,20 +518,21 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -630,7 +632,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -723,8 +724,8 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -842,16 +843,18 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -909,6 +912,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1118,32 +1122,37 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8= -k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E= +k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.22.5 h1:cIPwldOYm1Slq9VLBRPtEYpyhjIm1C6aAMAoENuvN9s= -k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= -k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo= -k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= +k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/client-go v0.23.4 h1:YVWvPeerA2gpUudLelvsolzH7c2sFoXXR5wM/sWqNFU= +k8s.io/client-go v0.23.4/go.mod h1:PKnIL4pqLuvYUK1WU7RLTMYKPiIh7MYShLshtRY9cj0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c h1:jvamsI1tn9V0S8jicyX82qaFC0H/NKxv2e5mbqsgR80= -k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA= sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 8afd9487ff6c70f89a4bef64adc154264f1d1fbb Mon Sep 17 00:00:00 2001 From: Venkata Krishna Rohit Sakala Date: Mon, 28 Feb 2022 14:34:13 +0100 Subject: [PATCH 225/542] Add s390x arch support Signed-off-by: Venkata Krishna Rohit Sakala --- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- Makefile | 6 +++--- demo/Makefile | 2 +- docs/architecture/index.md | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 3538a368..512aaf26 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -30,7 +30,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x push: ${{ github.event_name != 'pull_request' }} tags: >- plndr/kube-vip:${{ github.ref_name }}, diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5d465c5e..1498333a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,7 +30,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x push: ${{ github.event_name != 'pull_request' }} tags: >- plndr/kube-vip:${{ github.ref_name }}, diff --git a/Makefile b/Makefile index b801af35..1281a4c0 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ fmt: demo: @cd demo - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created @cd .. @@ -60,7 +60,7 @@ dockerx86: docker: @-rm ./kube-vip - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created ## Local (docker load of images) @@ -77,7 +77,7 @@ dockerx86Action: dockerLocal: @-rm ./kube-vip - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created simplify: diff --git a/demo/Makefile b/demo/Makefile index 1804f5e8..d02d5e3d 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -45,7 +45,7 @@ fmt: @gofmt -l -w $(SRC) docker: - @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @echo New Multi Architecture Docker image created simplify: diff --git a/docs/architecture/index.md b/docs/architecture/index.md index f8030074..fae1f691 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -7,7 +7,7 @@ This section covers two parts of the architecture: The `kube-vip` project is designed to provide both a highly available networking endpoint and load balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control plane for Kubernetes but has since expanded to provide the same functionality for Service resources within a Kubernetes cluster. -Additionally, `kube-vip` is designed to be lightweight and multi-architecture. All of the components are built for Linux on `x86`, `armv7`, `armhvf`, and `ppc64le` architectures. This means that `kube-vip` will run fine in bare metal, virtual, and edge (Raspberry Pi or small ARM SoC) use cases. +Additionally, `kube-vip` is designed to be lightweight and multi-architecture. All of the components are built for Linux on `x86`, `armv7`, `armhvf`, `ppc64le` and `s390x` architectures. This means that `kube-vip` will run fine in bare metal, virtual, and edge (Raspberry Pi or small ARM SoC) use cases. ## Technologies From 9bd837f0c6104ee941f3c7966bc1e2cbcbdb05cc Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Thu, 24 Mar 2022 12:18:47 +0800 Subject: [PATCH 226/542] The gratuitous arp should be sent periodically Related issue: https://github.com/kube-vip/kube-vip/issues/382 Signed-off-by: yaocw2020 --- pkg/cluster/service.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 1ba458cd..5ad12a7e 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -166,7 +166,6 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // want to step down //nolint ctxArp, cancelArp := context.WithCancel(context.Background()) - defer cancelArp() cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) @@ -199,7 +198,6 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } for { - select { case <-ctx.Done(): // if cancel() execute return From c81c8c1865f9a9d2c1725fc3a72a103000af928e Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Mon, 28 Mar 2022 21:31:10 +0800 Subject: [PATCH 227/542] support changing the VIP of services - Support changing the VIP of services - Refactory the manager.syncServices to improve code readability Signed-off-by: yaocw2020 --- .gitignore | 2 +- pkg/cluster/cluster.go | 2 - pkg/cluster/service.go | 3 +- pkg/manager/instance.go | 191 +++++++++++++++++++++++++++++++++++ pkg/manager/manager.go | 28 +---- pkg/manager/services.go | 173 ++++++++++++++----------------- pkg/manager/services_dhcp.go | 145 -------------------------- pkg/manager/watcher.go | 24 ++--- pkg/service/services.go | 6 +- pkg/service/services_dhcp.go | 6 +- 10 files changed, 279 insertions(+), 301 deletions(-) create mode 100644 pkg/manager/instance.go delete mode 100644 pkg/manager/services_dhcp.go diff --git a/.gitignore b/.gitignore index 258fffdc..723ef36f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -./idea/ \ No newline at end of file +.idea \ No newline at end of file diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index e42b89a0..b8819bc2 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -15,8 +15,6 @@ type Cluster struct { // InitCluster - Will attempt to initialise all of the required settings for the cluster func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) { - - // TODO - Check for root (needed to netlink) var network vip.Network var err error diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 5ad12a7e..59b8d55b 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -158,7 +158,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co } // StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle -func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) error { +func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) { // Start a kube-vip loadbalancer service log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) @@ -265,5 +265,4 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } }() log.Infoln("Started Load Balancer and Virtual IP") - return nil } diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go new file mode 100644 index 00000000..a7c18502 --- /dev/null +++ b/pkg/manager/instance.go @@ -0,0 +1,191 @@ +package manager + +import ( + "fmt" + "net" + "time" + + "github.com/insomniacslk/dhcp/dhcpv4/nclient4" + "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/vip" + log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" + v1 "k8s.io/api/core/v1" + + "github.com/kube-vip/kube-vip/pkg/cluster" +) + +const dhcpTimeout = 10 * time.Second + +// Instance defines an instance of everything needed to manage a vip +type Instance struct { + // Virtual IP / Load Balancer configuration + vipConfig *kubevip.Config + + // cluster instance + cluster *cluster.Cluster + + // Service uses DHCP + isDHCP bool + dhcpInterface string + dhcpInterfaceHwaddr string + dhcpInterfaceIP string + dhcpClient *vip.DHCPClient + + // Kubernetes service mapping + Vip string + Port int32 + UID string + Type string + + ServiceName string + ServiceNamespace string +} + +func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) { + instanceAddress := service.Spec.LoadBalancerIP + instanceUID := string(service.UID) + + // Detect if we're using a specific interface for services + var serviceInterface string + if config.ServicesInterface != "" { + serviceInterface = config.ServicesInterface + } else { + serviceInterface = config.Interface + } + + // Generate new Virtual IP configuration + newVip := &kubevip.Config{ + VIP: instanceAddress, //TODO support more than one vip? + Interface: serviceInterface, + SingleNode: true, + EnableARP: config.EnableARP, + EnableBGP: config.EnableBGP, + VIPCIDR: config.VIPCIDR, + } + + // Create new service + instance := &Instance{ + UID: instanceUID, + Vip: instanceAddress, + ServiceName: service.Name, + ServiceNamespace: service.Namespace, + } + if len(service.Spec.Ports) > 0 { + instance.Type = string(service.Spec.Ports[0].Protocol) + instance.Port = service.Spec.Ports[0].Port + } + if service.Annotations != nil { + instance.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] + instance.dhcpInterfaceIP = service.Annotations[requestedIP] + } + + // Generate Load Balancer config + newLB := kubevip.LoadBalancer{ + Name: fmt.Sprintf("%s-load-balancer", instance.ServiceName), + Port: int(instance.Port), + Type: instance.Type, + BindToVip: true, + } + // Add Load Balancer Configuration + newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + // Create Add configuration to the new service + instance.vipConfig = newVip + + // If this was purposely created with the address 0.0.0.0, + // we will create a macvlan on the main interface and a DHCP client + if instanceAddress == "0.0.0.0" { + ipChan, err := instance.startDHCP() + if err != nil { + return nil, err + } + select { + case <-time.After(dhcpTimeout): + return nil, fmt.Errorf("timeout to request the IP from DHCP server for service %s/%s", + instance.ServiceNamespace, instance.ServiceName) + case ip := <-ipChan: + instance.vipConfig.VIP = ip + instance.dhcpInterfaceIP = ip + } + } + + c, err := cluster.InitCluster(instance.vipConfig, false) + if err != nil { + log.Errorf("Failed to add Service %s/%s", instance.ServiceNamespace, instance.ServiceName) + return nil, err + } + instance.cluster = c + + return instance, nil +} + +func (i *Instance) startDHCP() (chan string, error) { + parent, err := netlink.LinkByName(i.vipConfig.Interface) + if err != nil { + return nil, fmt.Errorf("error finding VIP Interface, for building DHCP Link : %v", err) + } + + // Generate name from UID + interfaceName := fmt.Sprintf("vip-%s", i.UID[0:8]) + + // 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) + + hwaddr, err := net.ParseMAC(i.dhcpInterfaceHwaddr) + if i.dhcpInterfaceHwaddr != "" && err != nil { + return nil, err + } + + mac := &netlink.Macvlan{ + LinkAttrs: netlink.LinkAttrs{ + Name: interfaceName, + ParentIndex: parent.Attrs().Index, + HardwareAddr: hwaddr, + }, + Mode: netlink.MACVLAN_MODE_DEFAULT, + } + + err = netlink.LinkAdd(mac) + if err != nil { + return nil, fmt.Errorf("could not add %s: %v", interfaceName, err) + } + + err = netlink.LinkSetUp(mac) + if err != nil { + return nil, fmt.Errorf("could not bring up interface [%s] : %v", interfaceName, err) + } + iface, err = net.InterfaceByName(interfaceName) + if err != nil { + return nil, fmt.Errorf("error finding new DHCP interface by name [%v]", err) + } + } else { + log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) + } + + var initRebootFlag bool + if i.dhcpInterfaceHwaddr != "" { + initRebootFlag = true + } + + ipChan := make(chan string) + + client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP, func(lease *nclient4.Lease) { + ipChan <- lease.ACK.YourIPAddr.String() + + log.Infof("DHCP VIP [%s] for [%s/%s] ", i.vipConfig.VIP, i.ServiceNamespace, i.ServiceName) + }) + + go client.Start() + + // Set that DHCP is enabled + i.isDHCP = true + // Set the name of the interface so that it can be removed on Service deletion + i.dhcpInterface = interfaceName + i.dhcpInterfaceHwaddr = iface.HardwareAddr.String() + // Add the client so that we can call it to stop function + i.dhcpClient = client + + return ipChan, nil +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 8980f68c..e4a7b1b2 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -13,9 +13,7 @@ import ( "github.com/kamhlos/upnp" "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/vip" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" @@ -33,7 +31,7 @@ type Manager struct { // service bool // Keeps track of all running instances - serviceInstances []Instance + serviceInstances []*Instance // Additional functionality upnp *upnp.Upnp @@ -49,30 +47,6 @@ type Manager struct { countServiceWatchEvent *prometheus.CounterVec } -// Instance defines an instance of everything needed to manage a vip -type Instance struct { - // Virtual IP / Load Balancer configuration - vipConfig kubevip.Config - - // cluster instance - cluster cluster.Cluster - - // Service uses DHCP - isDHCP bool - dhcpInterface string - dhcpInterfaceHwaddr string - dhcpInterfaceIP string - dhcpClient *vip.DHCPClient - - // Kubernetes service mapping - Vip string - Port int32 - UID string - Type string - - ServiceName string -} - // New will create a new managing object func New(configMap string, config *kubevip.Config) (*Manager, error) { diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 1e1d3452..6455dae5 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -11,9 +11,6 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" ) const ( @@ -21,22 +18,8 @@ const ( requestedIP = "kube-vip.io/requestedIP" ) -func (sm *Manager) stopService(uid string) error { - found := false - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == uid { - found = true - sm.serviceInstances[x].cluster.Stop() - } - } - if !found { - return fmt.Errorf("unable to find/stop service [%s]", uid) - } - return nil -} - func (sm *Manager) deleteService(uid string) error { - var updatedInstances []Instance + var updatedInstances []*Instance found := false for x := range sm.serviceInstances { // Add the running services to the new array @@ -45,6 +28,7 @@ func (sm *Manager) deleteService(uid string) error { } else { // Flip the found when we match found = true + sm.serviceInstances[x].cluster.Stop() if sm.serviceInstances[x].isDHCP { sm.serviceInstances[x].dhcpClient.Stop() macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) @@ -56,7 +40,6 @@ func (sm *Manager) deleteService(uid string) error { if err != nil { return fmt.Errorf("error deleting DHCP Link : %v", err) } - } if sm.serviceInstances[x].vipConfig.EnableBGP { cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) @@ -89,97 +72,52 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { for x := range sm.serviceInstances { if sm.serviceInstances[x].UID == newServiceUID { - // We have found this instance in the manager, we can determine if it needs updating + log.Debugf("isDHCP: %t, newServiceAddress: %s", sm.serviceInstances[x].isDHCP, newServiceAddress) + // 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" || + !sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0" || + !sm.serviceInstances[x].isDHCP && len(service.Status.LoadBalancer.Ingress) > 0 && + newServiceAddress != service.Status.LoadBalancer.Ingress[0].IP { + if err := sm.deleteService(newServiceUID); err != nil { + return err + } + break + } foundInstance = true } - - } - - // Detect if we're using a specific interface for services - var serviceInterface string - if sm.config.ServicesInterface != "" { - serviceInterface = sm.config.ServicesInterface - } else { - serviceInterface = sm.config.Interface - } - - // Generate new Virtual IP configuration - newVip := kubevip.Config{ - VIP: newServiceAddress, //TODO support more than one vip? - Interface: serviceInterface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, } // This instance wasn't found, we need to add it to the manager - if !foundInstance { - // Create new service - var newService Instance - newService.UID = newServiceUID - newService.Vip = newServiceAddress - newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types - newService.Port = service.Spec.Ports[0].Port - newService.ServiceName = service.Name - newService.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] - newService.dhcpInterfaceIP = service.Annotations[requestedIP] - - // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP - if newServiceAddress == "0.0.0.0" { - err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) - if err != nil { - return err - } - return nil - } - - log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceName, newService.UID) - - // Generate Load Balancer config - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", newService.ServiceName), - Port: int(newService.Port), - Type: newService.Type, - BindToVip: true, + if !foundInstance && newServiceAddress != "" { + log.Infof("add the service [%s/%s] with external address %s", service.Namespace, service.Name, newServiceAddress) + if err := sm.addService(service); err != nil { + return err } + } - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + return nil +} - // Create Add configuration to the new service - newService.vipConfig = newVip +func (sm *Manager) addService(service *v1.Service) error { + newService, err := NewInstance(service, sm.config) + if err != nil { + return err + } - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - return err - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - return err - } + log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) - sm.upnpMap(newService) + newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) - newService.cluster = *c + sm.upnpMap(newService) - // Begin watching this service - // TODO - we may need this - // go sm.serviceWatcher(&newService, sm.config.Namespace) + sm.serviceInstances = append(sm.serviceInstances, newService) - // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, updateErr := sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) - return updateErr - }) - if retryErr != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) + if err := sm.updateStatus(newService); err != nil { + // delete service to collect garbage + if deleteErr := sm.deleteService(newService.UID); err != nil { + return deleteErr } - sm.serviceInstances = append(sm.serviceInstances, newService) + return err } log.Debugf("[COMPLETE] Service Sync") @@ -187,11 +125,10 @@ func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { return nil } -func (sm *Manager) upnpMap(s Instance) { +func (sm *Manager) upnpMap(s *Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() if sm.upnp != nil { - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { log.Infof("Service should be accessible externally on port [%d]", s.Port) @@ -201,3 +138,43 @@ func (sm *Manager) upnpMap(s Instance) { } } } + +func (sm *Manager) updateStatus(i *Instance) error { + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(i.ServiceNamespace).Get(context.TODO(), i.ServiceName, metav1.GetOptions{}) + if err != nil { + return err + } + + currentServiceCopy := currentService.DeepCopy() + if i.dhcpInterfaceHwaddr != "" || i.dhcpInterfaceIP != "" { + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + currentServiceCopy.Annotations[hwAddrKey] = i.dhcpInterfaceHwaddr + currentServiceCopy.Annotations[requestedIP] = i.dhcpInterfaceIP + } + + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", i.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + return retryErr + } + return nil +} diff --git a/pkg/manager/services_dhcp.go b/pkg/manager/services_dhcp.go deleted file mode 100644 index 87ef6430..00000000 --- a/pkg/manager/services_dhcp.go +++ /dev/null @@ -1,145 +0,0 @@ -package manager - -import ( - "context" - "fmt" - "net" - - "github.com/insomniacslk/dhcp/dhcpv4/nclient4" - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/util/retry" - - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/vip" -) - -func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { - parent, err := netlink.LinkByName(sm.config.Interface) - if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) - } - - // Generate name from UID - interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) - - // 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) - - hwaddr, err := net.ParseMAC(newService.dhcpInterfaceHwaddr) - if newService.dhcpInterfaceHwaddr != "" && err != nil { - return err - } - - mac := &netlink.Macvlan{ - LinkAttrs: netlink.LinkAttrs{ - Name: interfaceName, - ParentIndex: parent.Attrs().Index, - HardwareAddr: hwaddr, - }, - Mode: netlink.MACVLAN_MODE_DEFAULT, - } - - err = netlink.LinkAdd(mac) - if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) - } - - err = netlink.LinkSetUp(mac) - if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) - } - iface, err = net.InterfaceByName(interfaceName) - if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) - } - } else { - log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) - } - - var initRebootFlag bool - if newService.dhcpInterfaceHwaddr != "" { - initRebootFlag = true - } - - client := vip.NewDHCPClient(iface, initRebootFlag, newService.dhcpInterfaceIP, func(lease *nclient4.Lease) { - newVip.VIP = lease.ACK.YourIPAddr.String() - - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - - // Create Add configuration to the new service - newService.vipConfig = *newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return - } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Load Balancer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return - } - newService.cluster = *c - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - currentServiceCopy := currentService.DeepCopy() - if currentServiceCopy.Annotations == nil { - currentServiceCopy.Annotations = make(map[string]string) - } - currentServiceCopy.Annotations[hwAddrKey] = iface.HardwareAddr.String() - currentServiceCopy.Annotations[requestedIP] = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - log.Errorf("Failed to set Services: %v", retryErr) - } - // Find an update our array - - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - sm.serviceInstances[x] = *newService - } - } - sm.upnpMap(*newService) - }) - - // Set that DHCP is enabled - newService.isDHCP = true - // Set the name of the interface so that it can be removed on Service deletion - newService.dhcpInterface = interfaceName - // Add the client so that we can call it's stop function - newService.dhcpClient = client - - sm.serviceInstances = append(sm.serviceInstances, *newService) - - go client.Start() - - return nil -} diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index c6ff2878..f39a304d 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -63,35 +63,27 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { break } - if svc.Spec.LoadBalancerIP == "" { - log.Infof("Service [%s] has been added/modified, it has no assigned external addresses", svc.Name) - } else { - log.Infof("Service [%s] has been added/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) - wg.Add(1) - err = sm.syncServices(svc, &wg) - if err != nil { - log.Error(err) - } - wg.Wait() + log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + wg.Add(1) + err = sm.syncServices(svc, &wg) + if err != nil { + log.Error(err) } + wg.Wait() case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) + log.Infof("Service [%s/%s] has an ignore annotation for kube-vip", svc.Namespace, svc.Name) break } - err = sm.stopService(string(svc.UID)) - if err != nil { - log.Error(err) - } err = sm.deleteService(string(svc.UID)) if err != nil { log.Error(err) } - log.Infof("Service [%s] has been deleted", svc.Name) + log.Infof("Service [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used diff --git a/pkg/service/services.go b/pkg/service/services.go index 499d6df6..3bcb19f7 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -139,11 +139,7 @@ func (sm *Manager) syncServices(service *v1.Service) error { log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) return err } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - return err - } + c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) sm.upnpMap(newService) diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index dc8a6ed1..997ac69f 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -83,11 +83,7 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) return } - err = c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - if err != nil { - log.Errorf("Failed to add Load Balancer service Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return - } + c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) newService.cluster = *c retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { From 7b0bd4061f7ea2d9b609f4582a0e04fd6ec5a9d3 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 1 Apr 2022 15:59:54 +0100 Subject: [PATCH 228/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1281a4c0..37dc1d9e 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.4.2 +VERSION := v0.4.3 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From d7b49a0f0fd8724b54b9bc5fb542bd960295c58b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 4 Apr 2022 14:49:38 +0100 Subject: [PATCH 229/542] Update to automated testing and clear msg --- cmd/kube-vip.go | 1 + pkg/cluster/service.go | 2 +- pkg/vip/arp.go | 3 +- testing/k3s/create.sh | 48 ++++++++----- testing/kubeadm/create.sh | 144 ++++++++++++++++++++++--------------- testing/kubeadm/service.sh | 34 +++++++++ testing/logging.bash | 46 ++++++++++++ 7 files changed, 201 insertions(+), 77 deletions(-) create mode 100755 testing/kubeadm/service.sh create mode 100644 testing/logging.bash diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index e9ed03e9..21db04b2 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -197,6 +197,7 @@ var kubeVipManager = &cobra.Command{ Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { + log.Infof("Starting kube-vip.io [%s]", Release.Version) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) if err != nil { diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 59b8d55b..d2d3aff5 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -117,7 +117,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co if ndp != nil { defer ndp.Close() } - + log.Infof("Gratuitous Arp broadcast will repeat every 3 seconds for [%s]", ipString) for { select { case <-ctx.Done(): // if cancel() execute diff --git a/pkg/vip/arp.go b/pkg/vip/arp.go index 6038f0a8..62a53551 100644 --- a/pkg/vip/arp.go +++ b/pkg/vip/arp.go @@ -168,7 +168,8 @@ func ARPSendGratuitous(address, ifaceName string) error { return fmt.Errorf("failed to parse address %s", ip) } - log.Infof("Broadcasting ARP update for %s (%s) via %s", address, iface.HardwareAddr, iface.Name) + // This is a debug message, enable debugging to ensure that the gratuitous arp is repeating + log.Debugf("Broadcasting ARP update for %s (%s) via %s", address, iface.HardwareAddr, iface.Name) m, err := gratuitousARP(ip, iface.HardwareAddr) if err != nil { return err diff --git a/testing/k3s/create.sh b/testing/k3s/create.sh index dcdac2f7..b9ebf0c8 100755 --- a/testing/k3s/create.sh +++ b/testing/k3s/create.sh @@ -1,4 +1,20 @@ #!/bin/bash + +set -e + +# Read node configuration +source ./testing/nodes + +# Read logging function +source ./testing/logging.bash + +## Main() + +# Ensure we have an entirely new logfile +reset_logfile + +logr "INFO" "Starting kube-vip.io testing with k3s" +logr "DEFAULT" "Creating Logfile $logfile" if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then echo "Usage:" @@ -10,34 +26,34 @@ if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then exit 1 fi -case "$2" in +# Sane variable renaming +kubernetes_version=$4 +kube_vip_version=$1 +kube_vip_vip=$3 -"controlplane") echo "Creating control plane only cluster" - mode="--controlplane" +case "$2" in +"controlplane") logr "INFO" "Creating in control plane only mode" + kube_vip_mode="--controlplane" ;; -"services") echo "Creating services only cluster" - mode="--services" +"services") logr "INFO" "Creating in services-only mode" + kube_vip_mode="--services" ;; -"hybrid") echo "Creating hybrid cluster" - mode="--controlplane --services" +"hybrid") logr "INFO" "Creating in hybrid mode" + kube_vip_mode="--controlplane --services" ;; -*) echo "Unknown kube-vip mode [$2]" +*) echo "Unknown kube-vip mode [$3]" exit -1 ;; esac -source ./testing/nodes - -echo "Creating First node!" - ssh $NODE01 "sudo mkdir -p /var/lib/rancher/k3s/server/manifests/" -ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest daemonset $mode --interface ens160 --vip $3 --arp --leaderElection --inCluster --taint | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml" +ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest daemonset $kube_vip_mode --interface ens160 --vip $kube_vip_vip --arp --leaderElection --inCluster --taint | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml" ssh $NODE01 "sudo curl https://kube-vip.io/manifests/rbac.yaml | sudo tee /var/lib/rancher/k3s/server/manifests/rbac.yaml" -ssh $NODE01 "sudo screen -dmSL k3s k3s server --cluster-init --tls-san $3 --no-deploy servicelb --disable-cloud-controller --token=test" +ssh $NODE01 "sudo screen -dmSL k3s k3s server --cluster-init --tls-san $kube_vip_vip --no-deploy servicelb --disable-cloud-controller --token=test" echo "Started first node, sleeping for 60 seconds" sleep 60 echo "Adding additional nodes" -ssh $NODE02 "sudo screen -dmSL k3s k3s server --server https://$3:6443 --token=test" -ssh $NODE03 "sudo screen -dmSL k3s k3s server --server https://$3:6443 --token=test" +ssh $NODE02 "sudo screen -dmSL k3s k3s server --server https://$kube_vip_vip:6443 --token=test" +ssh $NODE03 "sudo screen -dmSL k3s k3s server --server https://$kube_vip_vip:6443 --token=test" sleep 20 ssh $NODE01 "sudo k3s kubectl get node -o wide" diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 8c1f3bb1..8ff23943 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -1,4 +1,67 @@ #!/bin/bash +set -e + +# Read node configuration +source ./testing/nodes + +# Read logging function +source ./testing/logging.bash + +install_deps() { + echo "Installing Kubernetes dependencies for Kubernetes $kubernetes_version on all nodes" + ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" +} + +first_node() { + logr "INFO" "Creating First node!" + #ssh $NODE01 "sudo modprobe ip_vs_rr" + #ssh $NODE01 "sudo modprobe nf_conntrack" + logr "INFO" "$(ssh $NODE01 "docker rmi plndr/kube-vip:$kube_vip_version" 2>&1)" + + # echo "echo "ip_vs | tee -a /etc/modules" + logr "INFO" "Creating Kube-vip.io Manifest" + ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + logr "INFO" "Deploying first Kubernetes node $NODE01" + FIRST_NODE=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $kubernetes_version --control-plane-endpoint $kube_vip_vip --upload-certs --pod-network-cidr=10.0.0.0/16") + echo "$FIRST_NODE" >> $logfile + CONTROLPLANE_CMD=$(echo "$FIRST_NODE" | grep -m1 certificate-key) + #CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $kubernetes_version --control-plane-endpoint $kube_vip_vip --upload-certs --pod-network-cidr=10.0.0.0/16 | grep -m1 certificate-key") + ssh $NODE01 "sudo rm -rf ~/.kube/" + ssh $NODE01 "mkdir -p .kube" + ssh $NODE01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" + ssh $NODE01 "sudo chown dan:dan .kube/config" + logr "INFO" "Enabling strict ARP on kube-proxy" + ssh $NODE01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" + ssh $NODE01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" + logr "INFO" "Deploying Calico to the Kubernetes Cluster" + ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" >> $logfile + logr "INFO" "Retrieving Join command" + JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") +} + + +additional_controlplane() { + logr "INFO" "Adding $NODE02" + ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile + sleep 1 + ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + logr "INFO" "Adding $NODE03" + ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile + sleep 1 + ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile +} + +## Main() + +# Ensure we have an entirely new logfile +reset_logfile + +logr "INFO" "Starting kube-vip.io testing with Kubeadm" +logr "DEFAULT" "Creating Logfile $logfile" if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then echo "Usage:" @@ -7,77 +70,40 @@ if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then echo " Param 3: Kube-Vip mode [\"controlplane\"/\"services\"/\"hybrid\"]" echo " Param 4: Vip address" echo "" - echo "" ./create_k8s.sh 1.18.5 0.4.0 hybrid 192.168.0.40 + echo "" ./create.sh 1.18.5 0.4.0 hybrid 192.168.0.40 exit 1 fi -case "$3" in +# Sane variable renaming +kubernetes_version=$1 +kube_vip_version=$2 +kube_vip_vip=$4 -"controlplane") echo "Creating in control plane only mode" - mode="--controlplane" +case "$3" in +"controlplane") logr "INFO" "Creating in control plane only mode" + kube_vip_mode="--controlplane" ;; -"services") echo "Creating in services-only mode" - mode="--services" +"services") logr "INFO" "Creating in services-only mode" + kube_vip_mode="--services" ;; -"hybrid") echo "Creating in hybrid mode" - mode="--controlplane --services" +"hybrid") logr "INFO" "Creating in hybrid mode" + kube_vip_mode="--controlplane --services" ;; *) echo "Unknown kube-vip mode [$3]" exit -1 ;; esac -install_deps() { - echo "Installing Kubernetes dependencies for Kubernetes $! on all nodes" - ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" - ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" - ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" - ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" - ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$1-00 kubectl=$1-00 kubeadm=$1-00" -} - -source ./testing/nodes - -first_node() { -echo "Creating First node!" -#ssh $NODE01 "sudo modprobe ip_vs_rr" -#ssh $NODE01 "sudo modprobe nf_conntrack" -ssh $NODE01 "docker rmi plndr/kube-vip:dev" - -# echo "echo "ip_vs | tee -a /etc/modules" -ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$2 manifest pod --interface ens160 --vip $4 --arp --leaderElection --enableLoadBalancer $5 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" -CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $1 --control-plane-endpoint $4 --upload-certs --pod-network-cidr=10.0.0.0/16 | grep certificate-key") -ssh $NODE01 "sudo rm -rf ~/.kube/" -ssh $NODE01 "mkdir -p .kube" -ssh $NODE01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" -ssh $NODE01 "sudo chown dan:dan .kube/config" -echo "Enabling strict ARP on kube-proxy" -ssh $NODE01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" -ssh $NODE01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" -ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" -JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") -} - - -additional_controlplane() { -ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" -sleep 3 -ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest pod --interface ens160 --vip $2 --arp --leaderElection --enableLoadBalancer $3 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" - -ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" -sleep 3 -ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$1 manifest pod --interface ens160 --vip $2 --arp --leaderElection --enableLoadBalancer $3 | sed \"s/image:.*/image: plndr\/kube-vip:dev/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" -} - -first_node $1 $2 $3 $4 $mode -additional_controlplane $2 $4 $mode - -ssh $NODE04 "sudo $JOIN_CMD" -ssh $NODE05 "sudo $JOIN_CMD" +first_node +additional_controlplane +logr "INFO" "Adding $NODE04" +ssh $NODE04 "sudo $JOIN_CMD" >> $logfile +logr "INFO" "Adding $NODE05" +ssh $NODE05 "sudo $JOIN_CMD" >> $logfile +logr "DEFAULT" "Nodes should be deployed at this point, waiting 5 secs and querying the deployment" echo -echo " Nodes should be deployed at this point, waiting 5 secs and querying the deployment" sleep 5 -ssh $NODE01 "kubectl get nodes" -ssh $NODE01 "kubectl get pods -A" +ssh $NODE01 "kubectl get nodes" | tee >> $logfile +ssh $NODE01 "kubectl get pods -A" | tee >> $logfile echo -echo "Kubernetes: $1, Kube-vip $2, Advertising VIP: $4" +logr "INFO" "Kubernetes: $kubernetes_version, Kube-vip $kube_vip_version, Advertising VIP: $kube_vip_vip" diff --git a/testing/kubeadm/service.sh b/testing/kubeadm/service.sh new file mode 100755 index 00000000..8ac810a0 --- /dev/null +++ b/testing/kubeadm/service.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -e + +# Read node configuration +source ./testing/nodes + +# Read logging function +source ./testing/logging.bash + + +logr "INFO" "Starting kube-vip.io service testing with Kubeadm" +logr "DEFAULT" "Creating Logfile $logfile" + +# Adding Controller +logr "INFO" "Creating network range configmap" +ssh $NODE01 "kubectl create configmap -n kube-system kubevip --from-literal range-global=192.168.0.220-192.168.0.222" >> $logfile + +logr "INFO" "Deploying kube-vip.io Controller" +ssh $NODE01 "kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml" >> $logfile + +logr "INFO" "Creating \"nginx\" deployment" +ssh $NODE01 "kubectl apply -f https://k8s.io/examples/application/deployment.yaml" >> $logfile +sleep 5 + +logr "DEFAULT" "Creating \"nginx\" service" +ssh $NODE01 "kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx" >> $logfile + +logr "INFO" "Sleeping for 20 seconds to give the controller time to \"reconcile\"" +sleep 20 + +logr "INFO" "Retrieving logs from kube-vip.io cloud provider" +ssh $NODE01 "kubectl logs -n kube-system kube-vip-cloud-provider-0" >> $logfile +logr "INFO" "Retrieving service configuration" +ssh $NODE01 "kubectl describe svc nginx" | tee >> $logfile diff --git a/testing/logging.bash b/testing/logging.bash new file mode 100644 index 00000000..fb81b6a4 --- /dev/null +++ b/testing/logging.bash @@ -0,0 +1,46 @@ +LOG_ON_FILE=true + +logfile="/tmp/kube-vip-testing.$(date +'%Y-%m-%d').log" + + +echo_timing() { + #-------------------------------------------------------- + # Out: [19/01/2020 18h19:56] Hello + #-------------------------------------------------------- + echo [`date +%d"/"%m"/"%Y" "%H"h"%M":"%S`] $@ +} + +echo_color(){ + COLOR=$1; MSG=$2; + + if [[ ${COLOR} == *"WHITE"* ]]; then echo -e "\\e[39m"${MSG}"\\e[0m"; + elif [[ ${COLOR} == *"RED"* ]]; then echo -e "\\e[31m"${MSG}"\\e[0m"; + elif [[ ${COLOR} == *"GREEN"* ]]; then echo -e "\\e[32m"${MSG}"\\e[0m"; + elif [[ ${COLOR} == *"YELLOW"* ]]; then echo -e "\\e[33m"${MSG}"\\e[0m"; + elif [[ ${COLOR} == *"BLUE"* ]]; then echo -e "\\e[34m"${MSG}"\\e[0m"; + fi; +} + +echo_console(){ + TYPE_OF_MSG=$1; MSG=$2; + + if [[ ${TYPE_OF_MSG} == *"1"* ]] || [[ ${TYPE_OF_MSG} == *"SUCCESS"* ]]; then echo_timing "$(echo_color "GREEN" "[+]: ${MSG}")"; + elif [[ ${TYPE_OF_MSG} == *"2"* ]] || [[ ${TYPE_OF_MSG} == *"FAIL"* ]]; then echo_timing "$(echo_color "RED" "[-]: ${MSG}")"; + elif [[ ${TYPE_OF_MSG} == *"3"* ]] || [[ ${TYPE_OF_MSG} == *"WARNING"* ]]; then echo_timing "$(echo_color "YELLOW" "[!]: ${MSG}")"; + elif [[ ${TYPE_OF_MSG} == *"4"* ]] || [[ ${TYPE_OF_MSG} == *"INFO"* ]]; then echo_timing "$(echo_color "BLUE" "[i]: ${MSG}")"; + elif [[ ${TYPE_OF_MSG} == *"0"* ]] || [[ ${TYPE_OF_MSG} == *"DEFAULT"* ]]; then echo_timing "$(echo_color "WHITE" "[:]: ${MSG}")"; + else MSG=${TYPE_OF_MSG}; echo_timing "$(echo_color "WHITE" "[:]: ${MSG}")"; + fi; +} + +logr(){ + TYPE_OF_MSG=$1; MSG=$2; + + if [[ ${LOG_ON_FILE} ]]; then echo_console "${TYPE_OF_MSG}" "${MSG}" | tee -a "${logfile}"; + else echo_console "${TYPE_OF_MSG}" "${MSG}"; fi; +} + +reset_logfile() { + touch $logfile + cat /dev/null > $logfile +} \ No newline at end of file From fae208e45988287219faf08c2e0380fdf3515b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Mon, 4 Apr 2022 18:07:46 +0200 Subject: [PATCH 230/542] Update to gobgp/v3, ndp/v0.10.0 / go 1.18 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 2 +- CONTRIBUTING.md | 2 +- Dockerfile | 2 +- go.mod | 36 ++++---- go.sum | 171 ++++++++++++------------------------- pkg/bgp/hosts.go | 2 +- pkg/bgp/peers.go | 4 +- pkg/bgp/server.go | 12 ++- pkg/bgp/types.go | 2 +- pkg/vip/arp_unsupported.go | 1 + pkg/vip/ndp.go | 9 +- 11 files changed, 93 insertions(+), 150 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9f6601bd..344eab20 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: '1.17' + go-version: '1.18' - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2 - name: checks diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46528ad4..08d4c7e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,7 +154,7 @@ the `$GOPATH`. To develop locally, you can follow these steps: - 1. [Install Go 1.17](https://golang.org/doc/install) + 1. [Install Go 1.18](https://golang.org/doc/install) 2. Checkout your feature branch and `cd` into it. 3. To build all Go files and install them under `bin`, run `make bin` 4. To run all Go unit tests, run `make test-unit` diff --git a/Dockerfile b/Dockerfile index 7ac3882d..70119912 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.17.6-alpine3.15 as dev +FROM golang:1.18.0-alpine3.15 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/go.mod b/go.mod index 06758117..75cc2c2a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/kube-vip/kube-vip -go 1.17 +go 1.18 require ( github.com/cloudflare/ipvs v0.8.0 @@ -10,39 +10,39 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 - github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045 + github.com/mdlayher/ndp v0.10.0 github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.1 - github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee + github.com/osrg/gobgp/v3 v3.1.0 github.com/packethost/packngo v0.22.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.3.0 - github.com/stretchr/testify v1.7.0 + github.com/spf13/cobra v1.4.0 + github.com/stretchr/testify v1.7.1 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 - k8s.io/api v0.23.4 - k8s.io/apimachinery v0.23.4 - k8s.io/client-go v0.23.4 - k8s.io/klog/v2 v2.40.1 - sigs.k8s.io/kind v0.11.1 + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b + golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb + k8s.io/api v0.23.5 + k8s.io/apimachinery v0.23.5 + k8s.io/client-go v0.23.5 + k8s.io/klog/v2 v2.60.1 + sigs.k8s.io/kind v0.12.0 ) require ( - github.com/BurntSushi/toml v0.4.1 // indirect + github.com/BurntSushi/toml v1.0.0 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/evanphx/json-patch/v5 v5.2.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/go-logr/logr v1.2.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-cmp v0.5.7 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/gnostic v0.5.5 // indirect @@ -73,7 +73,7 @@ require ( github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.10.0 // indirect + github.com/spf13/viper v1.10.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect @@ -85,7 +85,7 @@ require ( golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - google.golang.org/grpc v1.42.0 // indirect + google.golang.org/grpc v1.45.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect @@ -96,5 +96,5 @@ require ( k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index b88a8269..22464c1d 100644 --- a/go.sum +++ b/go.sum @@ -25,7 +25,6 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -55,8 +54,9 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -82,10 +82,9 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -109,26 +108,18 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= @@ -147,11 +138,10 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.2.0 h1:8ozOH5xxoMYDt5/u+yMTsVXydVCbTORFnOOoq2lumco= -github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -164,7 +154,6 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -180,25 +169,18 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= -github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -246,8 +228,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -271,7 +254,6 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -279,7 +261,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= @@ -287,12 +268,9 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -321,13 +299,10 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= @@ -344,7 +319,6 @@ github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd h1:efcJu2Vzz6DoS github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -374,8 +348,6 @@ github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrb github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -387,12 +359,10 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -417,8 +387,8 @@ github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JA github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045 h1:cLcATbaiT+9tZwgtOqN1Duhp5bBkHLBxKlrXCf6srtI= -github.com/mdlayher/ndp v0.0.0-20220213140253-2a2b53cd2045/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8= +github.com/mdlayher/ndp v0.10.0 h1:Zdwol2bq1EHY8xSnejIYkq6LEj7dLjLymJX0o/2tjGw= +github.com/mdlayher/ndp v0.10.0/go.mod h1:Uv6IWvgvqirNUu2N3ZXJEB86xu6foyUsG0NrClSSfek= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -448,6 +418,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= @@ -467,27 +438,23 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee h1:p9cPdDaBWf5r9+arw2pUuc0aDT/tkfCEBVqfx/UBb2o= -github.com/osrg/gobgp v0.0.0-20210901090119-8ab84f8636ee/go.mod h1:QvEj9qq9o66TvTyFC0Yyn1zgSSFrno8MsptfrjyMR7A= +github.com/osrg/gobgp/v3 v3.1.0 h1:mnAPYsx4V0xPpbDJL0r1qmU6FvoXg7R7ZHfb4kJSaSU= +github.com/osrg/gobgp/v3 v3.1.0/go.mod h1:PX9HMux6z+A4/X01NNvOad1k/xEJXuvsfHRVLHcFaVI= github.com/packethost/packngo v0.22.0 h1:7syZ1jDN5rbdkkrh9A5rA/ijXe0AHNovNqlUUf0L+uM= github.com/packethost/packngo v0.22.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -501,7 +468,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -513,8 +479,6 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= @@ -522,22 +486,19 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -547,45 +508,37 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= @@ -594,7 +547,6 @@ github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:tw github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -602,9 +554,11 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -614,18 +568,14 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -676,7 +626,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -704,7 +653,6 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -724,8 +672,9 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -737,6 +686,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -760,7 +710,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -773,7 +722,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -804,7 +752,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -813,7 +760,6 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -848,11 +794,11 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb h1:PVGECzEo9Y3uOidtkHGdd347NjLtITfJFO9BxFpmRoo= +golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -872,9 +818,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -885,7 +829,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -958,6 +901,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -968,7 +912,7 @@ google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1037,8 +981,6 @@ google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -1068,8 +1010,9 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1095,13 +1038,11 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1122,22 +1063,18 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E= -k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI= -k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= -k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/client-go v0.23.4 h1:YVWvPeerA2gpUudLelvsolzH7c2sFoXXR5wM/sWqNFU= -k8s.io/client-go v0.23.4/go.mod h1:PKnIL4pqLuvYUK1WU7RLTMYKPiIh7MYShLshtRY9cj0= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA= +k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8= +k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= -k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -1148,11 +1085,11 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/kind v0.11.1 h1:pVzOkhUwMBrCB0Q/WllQDO3v14Y+o2V0tFgjTqIUjwA= -sigs.k8s.io/kind v0.11.1/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= +sigs.k8s.io/kind v0.12.0 h1:LFynXwQkH1MrWI8pM1FQty0oUwEKjU5EkMaVZaPld8E= +sigs.k8s.io/kind v0.12.0/go.mod h1:EcgDSBVxz8Bvm19fx8xkioFrf9dC30fMJdOTXBSGNoM= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/bgp/hosts.go b/pkg/bgp/hosts.go index 8952d168..2d283e99 100644 --- a/pkg/bgp/hosts.go +++ b/pkg/bgp/hosts.go @@ -5,7 +5,7 @@ import ( "fmt" "net" - api "github.com/osrg/gobgp/api" + api "github.com/osrg/gobgp/v3/api" ) // AddHost will update peers of a host diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index c04b404c..400536b0 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -9,7 +9,7 @@ import ( "github.com/golang/protobuf/ptypes" //nolint "github.com/golang/protobuf/ptypes/any" - api "github.com/osrg/gobgp/api" + api "github.com/osrg/gobgp/v3/api" ) // AddPeer will add peers to the BGP configuration @@ -27,7 +27,7 @@ func (b *Server) AddPeer(peer Peer) (err error) { p := &api.Peer{ Conf: &api.PeerConf{ NeighborAddress: peer.Address, - PeerAs: peer.AS, + PeerAsn: peer.AS, AuthPassword: peer.Password, }, diff --git a/pkg/bgp/server.go b/pkg/bgp/server.go index 33f42e9f..dd1cbd0d 100644 --- a/pkg/bgp/server.go +++ b/pkg/bgp/server.go @@ -6,8 +6,8 @@ import ( "log" "time" - api "github.com/osrg/gobgp/api" - gobgp "github.com/osrg/gobgp/pkg/server" + api "github.com/osrg/gobgp/v3/api" + gobgp "github.com/osrg/gobgp/v3/pkg/server" ) // NewBGPServer takes a configuration and returns a running BGP server instance @@ -32,7 +32,7 @@ func NewBGPServer(c *Config) (b *Server, err error) { if err = b.s.StartBgp(context.Background(), &api.StartBgpRequest{ Global: &api.Global{ - As: c.AS, + Asn: c.AS, RouterId: c.RouterID, ListenPort: -1, }, @@ -40,7 +40,11 @@ func NewBGPServer(c *Config) (b *Server, err error) { return } - if err = b.s.MonitorPeer(context.Background(), &api.MonitorPeerRequest{}, func(p *api.Peer) { log.Println(p) }); err != nil { + 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.Println(p) + } + }); err != nil { return } diff --git a/pkg/bgp/types.go b/pkg/bgp/types.go index 2e06f888..2eaad2bc 100644 --- a/pkg/bgp/types.go +++ b/pkg/bgp/types.go @@ -1,6 +1,6 @@ package bgp -import gobgp "github.com/osrg/gobgp/pkg/server" +import gobgp "github.com/osrg/gobgp/v3/pkg/server" // Peer defines a BGP Peer type Peer struct { diff --git a/pkg/vip/arp_unsupported.go b/pkg/vip/arp_unsupported.go index 5d732582..c6230b53 100644 --- a/pkg/vip/arp_unsupported.go +++ b/pkg/vip/arp_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package vip diff --git a/pkg/vip/ndp.go b/pkg/vip/ndp.go index 75235971..d7ebec35 100644 --- a/pkg/vip/ndp.go +++ b/pkg/vip/ndp.go @@ -3,6 +3,7 @@ package vip import ( "fmt" "net" + "net/netip" "github.com/mdlayher/ndp" @@ -44,16 +45,16 @@ func (n *NdpResponder) Close() error { // SendGratuitous broadcasts an NDP update or returns error if encountered. func (n *NdpResponder) SendGratuitous(address string) error { - ip := net.ParseIP(address) - if ip == nil { + ip, err := netip.ParseAddr(address) + if err != nil { return fmt.Errorf("failed to parse address %s", ip) } log.Infof("Broadcasting NDP update for %s (%s) via %s", address, n.hardwareAddr, n.intf) - return n.advertise(net.IPv6linklocalallnodes, ip, true) + return n.advertise(netip.IPv6LinkLocalAllNodes(), ip, true) } -func (n *NdpResponder) advertise(dst, target net.IP, gratuitous bool) error { +func (n *NdpResponder) advertise(dst, target netip.Addr, gratuitous bool) error { m := &ndp.NeighborAdvertisement{ Solicited: !gratuitous, Override: gratuitous, // Should clients replace existing cache entries From 88c9075116937250419dca8f357f635535548429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Mon, 4 Apr 2022 18:27:04 +0200 Subject: [PATCH 231/542] Update golangci-lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 344eab20..2db4d50c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,7 @@ jobs: with: go-version: '1.18' - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.2 - name: checks run: make check - name: test docker build From 051bb1f414e8fb6fe35ffbe14bdf2d0bbf66b0af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Sat, 9 Apr 2022 00:18:53 +0200 Subject: [PATCH 232/542] Don't check status on Point-To-Point interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- pkg/kubevip/config_manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 6bca2245..d4a2965a 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -208,6 +208,10 @@ func isValidInterface(iface string) error { return nil } + if l.Attrs().Flags&net.FlagPointToPoint == net.FlagPointToPoint { + return nil + } + if l.Attrs().OperState != netlink.OperUp { return fmt.Errorf("%s is not up", iface) } From 5fbb11fa069d45f9135f72e0b002f6ff28dfb5f8 Mon Sep 17 00:00:00 2001 From: Claudio Yanes Date: Mon, 11 Apr 2022 23:49:52 +0100 Subject: [PATCH 233/542] Treat interfaces with unknown state as valid Previous commits addressed the issue of interface being incorrectly marked as down for loopback (1a4465e) and point-to-point (051bb1f) interfaces by directly passing the test when the interface is identified a any of those types. Both commits failed to address the core issue, those interfaces (and many others) do not publish their operational state resulting in the state UNKOWN. With this commit, now interfaces with unknown status are accepted but the user is warned as he needs to manually ensure that the interface is ready to handle traffic. Fix #385 Signed-off-by: Claudio Yanes --- pkg/kubevip/config_manager.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index d4a2965a..41037bb6 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -3,7 +3,6 @@ package kubevip import ( "fmt" "io/ioutil" - "net" "os" "strconv" "strings" @@ -203,16 +202,16 @@ func isValidInterface(iface string) error { if err != nil { return fmt.Errorf("get %s failed, error: %w", iface, err) } + attrs := l.Attrs() - if l.Attrs().Flags&net.FlagLoopback == net.FlagLoopback { - return nil - } - - if l.Attrs().Flags&net.FlagPointToPoint == net.FlagPointToPoint { - return nil - } - - if l.Attrs().OperState != netlink.OperUp { + // Some interfaces (included but not limited to lo and point-to-point + // interfaces) do not provide a operational status but are safe to use. + // From kernek.org: "Interface is in unknown state, neither driver nor + // 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") + } else if attrs.OperState != netlink.OperUp { return fmt.Errorf("%s is not up", iface) } From 428d3060309b4d7b97177f9f9b7cc88dd01c5b95 Mon Sep 17 00:00:00 2001 From: Claudio Yanes Date: Thu, 14 Apr 2022 13:30:53 +0100 Subject: [PATCH 234/542] Fix missing interface name in warning message Signed-off-by: Claudio Yanes --- pkg/kubevip/config_manager.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 41037bb6..25ef6a7d 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -210,7 +210,10 @@ 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.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", + iface, + ) } else if attrs.OperState != netlink.OperUp { return fmt.Errorf("%s is not up", iface) } From e6edf3a3de5f28be9f85abe0db7f4718e20b2494 Mon Sep 17 00:00:00 2001 From: yaocw2020 Date: Wed, 19 Jan 2022 00:22:23 +0800 Subject: [PATCH 235/542] Fix DHCP release bug The macvlan interface could not be deleted until the DHCP client has released the IP. If the network manager in the operating system uses DHCP to obtain an IP for the network card, it will occupy the DHCP client port. In this case the release function will fail because the unicast connection with UDP socket need the same port. Update dhcp package and use a raw socket. Signed-off-by: yaocw2020 --- go.mod | 3 +++ go.sum | 12 ++++++++++-- pkg/manager/manager_arp.go | 3 ++- pkg/vip/dhcp.go | 17 ++++++++++++----- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 75cc2c2a..71d7c9e1 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/kube-vip/kube-vip go 1.18 +replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 + require ( github.com/cloudflare/ipvs v0.8.0 github.com/davecgh/go-spew v1.1.1 @@ -55,6 +57,7 @@ require ( github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc // indirect github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect github.com/mdlayher/genetlink v1.0.0 // indirect github.com/mdlayher/netlink v1.4.1 // indirect diff --git a/go.sum b/go.sum index 22464c1d..9160767b 100644 --- a/go.sum +++ b/go.sum @@ -269,6 +269,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 h1:StGYqyAyFXHsJAZgFD4xLzfCrLOaHd86ZhX/5pZY/4I= +github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3/go.mod h1:DwyLjKGwSxRt84j0FEB58tAFgjuEDEu20dyJG2canEI= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -315,8 +317,6 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd h1:efcJu2Vzz6DoSq245deWNzTz6l/gsqdphm3FjmI88/g= -github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= @@ -381,6 +381,9 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc h1:m7rJJJeXrYCFpsxXYapkDW53wJCDmf9bsIXUg0HoeQY= +github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ6yv+WafaKzY37MFZ58TdfIhQ+8nQbiis= +github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= @@ -400,6 +403,7 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1 h1:I154BCU+mKlIf7BgcAJB2r7QjveNPty6uNY1g9ChVfI= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= +github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= @@ -542,8 +546,10 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= @@ -629,6 +635,7 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -722,6 +729,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index b5558837..d240c02c 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -8,11 +8,12 @@ import ( "time" "github.com/kamhlos/upnp" - "github.com/kube-vip/kube-vip/pkg/cluster" 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" + + "github.com/kube-vip/kube-vip/pkg/cluster" ) // Start will begin the Manager, which will start services and watch the configmap diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index 4c8be0b2..25d47066 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -24,7 +24,8 @@ type DHCPClient struct { lease *nclient4.Lease initRebootFlag bool requestedIP net.IP - stopChan chan struct{} + stopChan chan struct{} // used as a signal to release the IP and stop the dhcp client daemon + releasedChan chan struct{} // indicate that the IP has been released onBound Callback } @@ -33,6 +34,7 @@ func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string return &DHCPClient{ iface: iface, stopChan: make(chan struct{}), + releasedChan: make(chan struct{}), initRebootFlag: initRebootFlag, requestedIP: net.ParseIP(requestedIP), onBound: onBound, @@ -47,6 +49,8 @@ func (c *DHCPClient) WithHostName(hostname string) *DHCPClient { // Stop state-transition process and close dhcp client func (c *DHCPClient) Stop() { close(c.stopChan) + + <-c.releasedChan } // Start state-transition process of dhcp client @@ -159,10 +163,13 @@ func (c *DHCPClient) Start() { // release if err := c.release(); err != nil { log.Errorf("release lease failed, error: %s, lease: %+v", err.Error(), c.lease) + } else { + log.Infof("release, lease: %+v", c.lease) } - log.Infof("release, lease: %+v", c.lease) t1.Stop() t2.Stop() + + close(c.releasedChan) return } } @@ -187,10 +194,10 @@ func (c *DHCPClient) request() (*nclient4.Lease, error) { } func (c *DHCPClient) release() error { - unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(&net.UDPAddr{Port: nclient4.ClientPort}), + unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(c.iface.Name, &net.UDPAddr{IP: c.lease.ACK.YourIPAddr, Port: nclient4.ClientPort}), nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) if err != nil { - return fmt.Errorf("create unicast client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) + return fmt.Errorf("create unicast client failed, error: %w, iface: %s, server ip: %v", err, c.iface.Name, c.lease.ACK.ServerIPAddr) } defer unicast.Close() @@ -224,7 +231,7 @@ func (c *DHCPClient) initReboot() (*nclient4.Lease, error) { } func (c *DHCPClient) renew() (*nclient4.Lease, error) { - unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(&net.UDPAddr{Port: nclient4.ClientPort}), + unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(c.iface.Name, &net.UDPAddr{IP: c.lease.ACK.YourIPAddr, Port: nclient4.ClientPort}), nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) if err != nil { return nil, fmt.Errorf("create unicast client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) From 7a7425efdfd6a8649410230cbe3acb2a5b729773 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 21 Apr 2022 09:24:11 +0100 Subject: [PATCH 236/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 37dc1d9e..b7b08e46 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.4.3 +VERSION := v0.4.4 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 75a2323448804eac3dc752c5235b27ddaad41a19 Mon Sep 17 00:00:00 2001 From: AxiomSamarth Date: Fri, 13 May 2022 18:25:24 +0530 Subject: [PATCH 237/542] set api-endpoint to host for incluster deployment Signed-off-by: AxiomSamarth --- pkg/cluster/clusterLeaderElection.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 4b42c496..8b284658 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -43,9 +43,13 @@ type Manager struct { func NewManager(path string, inCluster bool, port int) (*Manager, error) { var hostname string - // If the path passed is empty and not running in the cluster, + // If inCluster is set then it will likely have started as a static pod or won't have the + // VIP up before trying to connect to the API server, we set the API endpoint to this machine to + // ensure connectivity. Else if the path passed is empty and not running in the cluster, // attempt to look for a kubeconfig in the default HOME dir. - if len(path) == 0 && !inCluster { + if inCluster { + hostname = fmt.Sprintf("kubernetes:%v", port) + } else if len(path) == 0 && !inCluster { path = filepath.Join(os.Getenv("HOME"), ".kube", "config") // We modify the config so that we can always speak to the correct host From b9014ae32a180620bd61e3f6c8b03c45147adaae Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 13 May 2022 15:32:47 +0100 Subject: [PATCH 238/542] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 185f1a64..57d9cde0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ High Availability and Load-Balancing ![](https://github.com/kube-vip/kube-vip/raw/main/kube-vip.png) +[![Build and publish main image regularly](https://github.com/kube-vip/kube-vip/actions/workflows/main.yaml/badge.svg)](https://github.com/kube-vip/kube-vip/actions/workflows/main.yaml) + ## Overview Kubernetes Virtual IP and Load-Balancer for both control plane and Kubernetes services From da7ba0b9a6e6bc5450802f487ed797914e956291 Mon Sep 17 00:00:00 2001 From: AxiomSamarth Date: Sat, 14 May 2022 13:00:19 +0530 Subject: [PATCH 239/542] set kubernetes:6443 as default hostname Signed-off-by: AxiomSamarth --- pkg/cluster/clusterLeaderElection.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 8b284658..f69d850d 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -47,9 +47,10 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. Else if the path passed is empty and not running in the cluster, // attempt to look for a kubeconfig in the default HOME dir. - if inCluster { - hostname = fmt.Sprintf("kubernetes:%v", port) - } else if len(path) == 0 && !inCluster { + + hostname = fmt.Sprintf("kubernetes:%v", port) + + if len(path) == 0 && !inCluster { path = filepath.Join(os.Getenv("HOME"), ".kube", "config") // We modify the config so that we can always speak to the correct host From f1841f70efcc0a517551926e303f7af5c95ee9c3 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 30 May 2022 11:15:07 +0100 Subject: [PATCH 240/542] Packet to equinixmetal --- cmd/kube-vip.go | 4 +- pkg/cluster/clusterLeaderElection.go | 6 +-- pkg/cluster/service.go | 4 +- pkg/{packet => equinixmetal}/bgp.go | 2 +- pkg/{packet => equinixmetal}/eip.go | 2 +- pkg/{packet => equinixmetal}/utils.go | 2 +- pkg/manager/manager_bgp.go | 6 +-- pkg/manager/watcher.go | 78 +++++++++++++++++++++++++++ pkg/manager/watcher_test.go | 39 ++++++++++++++ pkg/service/manager_bgp.go | 4 +- pkg/vip/address.go | 1 - testing/kubeadm/create.sh | 15 ++++-- 12 files changed, 142 insertions(+), 21 deletions(-) rename pkg/{packet => equinixmetal}/bgp.go (98%) rename pkg/{packet => equinixmetal}/eip.go (98%) rename pkg/{packet => equinixmetal}/utils.go (98%) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 21db04b2..cfb455be 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -12,9 +12,9 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/manager" - "github.com/kube-vip/kube-vip/pkg/packet" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -241,7 +241,7 @@ var kubeVipManager = &cobra.Command{ // If Packet is enabled and there is a provider configuration passed if initConfig.EnableMetal { if providerConfig != "" { - providerAPI, providerProject, err := packet.GetPacketConfig(providerConfig) + providerAPI, providerProject, err := equinixmetal.GetPacketConfig(providerConfig) if err != nil { log.Fatalf("%v", err) } diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 4b42c496..9500794c 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -11,10 +11,10 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/kube-vip/kube-vip/pkg/k8s" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/loadbalancer" - "github.com/kube-vip/kube-vip/pkg/packet" "github.com/packethost/packngo" @@ -140,7 +140,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * var packetClient *packngo.Client if c.EnableMetal { if c.ProviderConfig != "" { - key, project, err := packet.GetPacketConfig(c.ProviderConfig) + key, project, err := equinixmetal.GetPacketConfig(c.ProviderConfig) if err != nil { log.Error(err) } else { @@ -158,7 +158,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * // We're using Packet with BGP, popuplate the Peer information from the API if c.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, c) + err = equinixmetal.BGPLookup(packetClient, c) if err != nil { log.Error(err) } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index d2d3aff5..148ebb5d 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -9,9 +9,9 @@ import ( "time" "github.com/kube-vip/kube-vip/pkg/bgp" + "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/loadbalancer" - "github.com/kube-vip/kube-vip/pkg/packet" "github.com/kube-vip/kube-vip/pkg/vip" "github.com/packethost/packngo" log "github.com/sirupsen/logrus" @@ -56,7 +56,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co if !c.EnableBGP { // Attempt to attach the EIP in the standard manner log.Debugf("Attaching the Packet EIP through the API to this host") - err = packet.AttachEIP(packetClient, c, id) + err = equinixmetal.AttachEIP(packetClient, c, id) if err != nil { log.Error(err) } diff --git a/pkg/packet/bgp.go b/pkg/equinixmetal/bgp.go similarity index 98% rename from pkg/packet/bgp.go rename to pkg/equinixmetal/bgp.go index 778055ca..49dfb936 100644 --- a/pkg/packet/bgp.go +++ b/pkg/equinixmetal/bgp.go @@ -1,4 +1,4 @@ -package packet +package equinixmetal import ( "fmt" diff --git a/pkg/packet/eip.go b/pkg/equinixmetal/eip.go similarity index 98% rename from pkg/packet/eip.go rename to pkg/equinixmetal/eip.go index 0ecb3558..031c982a 100644 --- a/pkg/packet/eip.go +++ b/pkg/equinixmetal/eip.go @@ -1,4 +1,4 @@ -package packet +package equinixmetal import ( "fmt" diff --git a/pkg/packet/utils.go b/pkg/equinixmetal/utils.go similarity index 98% rename from pkg/packet/utils.go rename to pkg/equinixmetal/utils.go index 6cbe0406..9c982aff 100644 --- a/pkg/packet/utils.go +++ b/pkg/equinixmetal/utils.go @@ -1,4 +1,4 @@ -package packet +package equinixmetal import ( "encoding/json" diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 2c2522a5..554848fe 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -7,7 +7,7 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/packethost/packngo" log "github.com/sirupsen/logrus" ) @@ -22,7 +22,7 @@ func (sm *Manager) startBGP() error { var packetClient *packngo.Client if sm.config.EnableMetal { if sm.config.ProviderConfig != "" { - key, project, err := packet.GetPacketConfig(sm.config.ProviderConfig) + key, project, err := equinixmetal.GetPacketConfig(sm.config.ProviderConfig) if err != nil { log.Error(err) } else { @@ -40,7 +40,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config) + err = equinixmetal.BGPLookup(packetClient, sm.config) if err != nil { log.Error(err) } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index f39a304d..d13707b9 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -284,3 +284,81 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er return bgpConfig, bgpPeer, nil } + +// New annotation structure + +// Node, or local, ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-node-asn +// Peer ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-asn +// Peer IP, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-ip +// Source IP to use when communicating with peer, default annotation metal.equinix.com/bgp-peers-{{n}}-src-ip +// BGP password for peer, default annotation metal.equinix.com/bgp-peers-{{n}}-bgp-pass + +// parseNodeAnnotations parses the annotations on the node and updates the configuration +// returning an error if the annotations are not valid or missing; and nil if everything is OK +// to continue +func parseNewBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { + bgpConfig := bgp.Config{} + bgpPeer := bgp.Peer{} + + nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] + if nodeASN == "" { + return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") + } + + u64, err := strconv.ParseUint(nodeASN, 10, 32) + if err != nil { + return bgpConfig, bgpPeer, err + } + + bgpConfig.AS = uint32(u64) + + srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] + if srcIP == "" { + return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") + } + + // Set the routerID (Unique ID for BGP) to the source IP + // Also set the BGP peering to the sourceIP + bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP + + peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] + if peerASN == "" { + return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") + } + + u64, err = strconv.ParseUint(peerASN, 10, 32) + if err != nil { + return bgpConfig, bgpPeer, err + } + + bgpPeer.AS = uint32(u64) + + peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] + + peerIPs := strings.Split(peerIPString, ",") + + for _, peerIP := range peerIPs { + ipAddr := strings.TrimSpace(peerIP) + + if ipAddr != "" { + bgpPeer.Address = ipAddr + // Check if we're also expecting a password for this peer + base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] + if base64BGPPassword != "" { + // Decode base64 encoded string + decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) + if err != nil { + return bgpConfig, bgpPeer, err + } + // Set the password for each peer + bgpPeer.Password = string(decodedPassword) + } + bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) + } + } + + log.Debugf("BGPConfig: %v\n", bgpConfig) + log.Debugf("BGPPeerConfig: %v\n", bgpPeer) + + return bgpConfig, bgpPeer, nil +} diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index 5b65bef9..a2a18999 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -58,6 +58,45 @@ func TestParseBgpAnnotations(t *testing.T) { assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") } +// Node, or local, ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-node-asn +// Peer ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-asn +// Peer IP, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-ip +// Source IP to use when communicating with peer, default annotation metal.equinix.com/bgp-peers-{{n}}-src-ip +// BGP password for peer, default annotation metal.equinix.com/bgp-peers-{{n}}-bgp-pass + +func TestParseNewBgpAnnotations(t *testing.T) { + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{}}, + } + + _, _, err := parseBgpAnnotations(node, "bgp") + if err == nil { + t.Fatal("Parsing BGP annotations should return an error when no annotations exist") + } + + node.Annotations = map[string]string{ + "bgp/bgp-peers-0-node-asn": "65000", + "bgp/bgp-peers-0-peer-asn": "64000", + "bgp/bgp-peers-0-peer-ip": "10.0.0.254", + "bgp/bgp-peers-0-src-ip": "10.0.0.1,10.0.0.2,10.0.0.3", + "bgp/bgp-peers-0-bgp-pass": "cGFzc3dvcmQ=", // password + } + + bgpConfig, bgpPeer, err := parseBgpAnnotations(node, "bgp") + if err != nil { + t.Fatalf("Parsing BGP annotations should return nil when minimum config is met [%v]", err) + } + + bgpPeers := []bgp.Peer{ + {Address: "10.0.0.1", AS: uint32(64000), Password: "password"}, + {Address: "10.0.0.2", AS: uint32(64000), Password: "password"}, + {Address: "10.0.0.3", AS: uint32(64000), Password: "password"}, + } + assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") + assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") + assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") +} + func Test_parseBgpAnnotations(t *testing.T) { type args struct { node *corev1.Node diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 11d017e1..a46fce1f 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -7,7 +7,7 @@ import ( "syscall" "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/packet" + "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/packethost/packngo" log "github.com/sirupsen/logrus" ) @@ -27,7 +27,7 @@ func (sm *Manager) startBGP() error { // We're using Packet with BGP, popuplate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") - err = packet.BGPLookup(packetClient, sm.config) + err = equinixmetal.BGPLookup(packetClient, sm.config) if err != nil { log.Error(err) } diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 2a3eb814..3c99ace2 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -70,7 +70,6 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { // address is DNS result.isDDNS = isDDNS result.dnsName = address - // try to resolve the address ip, err := lookupHost(address) if err != nil { diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 8ff23943..728ab0c8 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -9,11 +9,11 @@ source ./testing/logging.bash install_deps() { echo "Installing Kubernetes dependencies for Kubernetes $kubernetes_version on all nodes" - ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" } first_node() { @@ -94,6 +94,11 @@ case "$3" in ;; esac +if [[ -z "$DEPS" ]]; then + logr "INFO" "Installing specific version of Kubernetes Dependancies" + install_deps +fi + first_node additional_controlplane logr "INFO" "Adding $NODE04" From f8d3152e93949ad2df254ff5a56ec8b79a098211 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 30 May 2022 13:30:20 +0100 Subject: [PATCH 241/542] disable new annotations --- pkg/manager/watcher.go | 132 ++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index d13707b9..d29aa034 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -296,69 +296,69 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er // parseNodeAnnotations parses the annotations on the node and updates the configuration // returning an error if the annotations are not valid or missing; and nil if everything is OK // to continue -func parseNewBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { - bgpConfig := bgp.Config{} - bgpPeer := bgp.Peer{} - - nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] - if nodeASN == "" { - return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") - } - - u64, err := strconv.ParseUint(nodeASN, 10, 32) - if err != nil { - return bgpConfig, bgpPeer, err - } - - bgpConfig.AS = uint32(u64) - - srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] - if srcIP == "" { - return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") - } - - // Set the routerID (Unique ID for BGP) to the source IP - // Also set the BGP peering to the sourceIP - bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP - - peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] - if peerASN == "" { - return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") - } - - u64, err = strconv.ParseUint(peerASN, 10, 32) - if err != nil { - return bgpConfig, bgpPeer, err - } - - bgpPeer.AS = uint32(u64) - - peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] - - peerIPs := strings.Split(peerIPString, ",") - - for _, peerIP := range peerIPs { - ipAddr := strings.TrimSpace(peerIP) - - if ipAddr != "" { - bgpPeer.Address = ipAddr - // Check if we're also expecting a password for this peer - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] - if base64BGPPassword != "" { - // Decode base64 encoded string - decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) - if err != nil { - return bgpConfig, bgpPeer, err - } - // Set the password for each peer - bgpPeer.Password = string(decodedPassword) - } - bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) - } - } - - log.Debugf("BGPConfig: %v\n", bgpConfig) - log.Debugf("BGPPeerConfig: %v\n", bgpPeer) - - return bgpConfig, bgpPeer, nil -} +// func parseNewBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { +// bgpConfig := bgp.Config{} +// bgpPeer := bgp.Peer{} + +// nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] +// if nodeASN == "" { +// return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") +// } + +// u64, err := strconv.ParseUint(nodeASN, 10, 32) +// if err != nil { +// return bgpConfig, bgpPeer, err +// } + +// bgpConfig.AS = uint32(u64) + +// srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] +// if srcIP == "" { +// return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") +// } + +// // Set the routerID (Unique ID for BGP) to the source IP +// // Also set the BGP peering to the sourceIP +// bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP + +// peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] +// if peerASN == "" { +// return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") +// } + +// u64, err = strconv.ParseUint(peerASN, 10, 32) +// if err != nil { +// return bgpConfig, bgpPeer, err +// } + +// bgpPeer.AS = uint32(u64) + +// peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] + +// peerIPs := strings.Split(peerIPString, ",") + +// for _, peerIP := range peerIPs { +// ipAddr := strings.TrimSpace(peerIP) + +// if ipAddr != "" { +// bgpPeer.Address = ipAddr +// // Check if we're also expecting a password for this peer +// base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] +// if base64BGPPassword != "" { +// // Decode base64 encoded string +// decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) +// if err != nil { +// return bgpConfig, bgpPeer, err +// } +// // Set the password for each peer +// bgpPeer.Password = string(decodedPassword) +// } +// bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) +// } +// } + +// log.Debugf("BGPConfig: %v\n", bgpConfig) +// log.Debugf("BGPPeerConfig: %v\n", bgpPeer) + +// return bgpConfig, bgpPeer, nil +// } From cef185209929df448432f99dd6c5cd7e5ab9d89f Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 1 Jun 2022 11:52:19 +0100 Subject: [PATCH 242/542] Ignore services that aren't LoadBalancers --- pkg/manager/manager_arp.go | 3 ++- pkg/manager/watcher.go | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index d240c02c..f3ac596b 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -71,7 +71,8 @@ func (sm *Manager) startARP() error { } else { ns, err = returnNameSpace() if err != nil { - return err + log.Errorf("Unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) + ns = sm.config.Namespace } } diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index d29aa034..c1935725 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -58,6 +58,13 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } + + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } + + // We can ignore this service if svc.Annotations["kube-vip.io/ignore"] == "true" { log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) break @@ -75,10 +82,18 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } + + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } + + // We can ignore this service if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("Service [%s/%s] has an ignore annotation for kube-vip", svc.Namespace, svc.Name) + log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) break } + err = sm.deleteService(string(svc.UID)) if err != nil { log.Error(err) From 7c22c78a75734616f9a5b0233db7f077883851ec Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 1 Jun 2022 16:14:55 +0100 Subject: [PATCH 243/542] e2e test --- testing/e2e/kube-vip.yaml.tmpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testing/e2e/kube-vip.yaml.tmpl b/testing/e2e/kube-vip.yaml.tmpl index 063a7b12..2a82d1f7 100644 --- a/testing/e2e/kube-vip.yaml.tmpl +++ b/testing/e2e/kube-vip.yaml.tmpl @@ -34,6 +34,10 @@ spec: volumeMounts: - mountPath: /etc/kubernetes/admin.conf name: kubeconfig + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 hostNetwork: true volumes: - hostPath: From 840a2ba2b17694ab534c3e338624cc6d9237bc20 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 8 Jun 2022 12:57:56 +0100 Subject: [PATCH 244/542] Initial design of leaderElection per service --- pkg/kubevip/config_types.go | 5 +- pkg/manager/manager_arp.go | 110 ++++++++++++++++++---------------- pkg/manager/manager_bgp.go | 3 +- pkg/manager/servicesLeader.go | 92 ++++++++++++++++++++++++++++ pkg/manager/watcher.go | 6 +- 5 files changed, 161 insertions(+), 55 deletions(-) create mode 100644 pkg/manager/servicesLeader.go diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 8fba0f01..9d05c0a4 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -18,9 +18,12 @@ type Config struct { // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPane bool `yaml:"enableControlPane"` - // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) + // EnableControlPane, will enable the services functionality (used for hybrid behaviour) EnableServices bool `yaml:"enableServices"` + // EnableServicesElection, will enable leaderElection per service + EnableServicesElection bool `yaml:"enableServicesElection"` + // Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations Annotations string diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index f3ac596b..c09a81ce 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -96,59 +96,69 @@ func (sm *Manager) startARP() error { } } - log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ - LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, - Namespace: ns, - }, - Client: sm.clientSet.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{ - Identity: id, - }, - } + // 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") + err = sm.startServicesWatchForLeaderElection(ctx) + if err != nil { + return err + } + } else { - // start the leader election code loop - leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ - Lock: lock, - // IMPORTANT: you MUST ensure that any code you have that - // is protected by the lease must terminate **before** - // you call cancel. Otherwise, you could have a background - // loop still running and another process could - // get elected before your background loop finished, violating - // the stated goal of the lease. - ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, - Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - err = sm.servicesWatcher(ctx) - if err != nil { - log.Error(err) - } + log.Infof("Beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: ns, }, - OnStoppedLeading: func() { - // we can do cleanup here - log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() - } - - log.Fatal("lost leadership, restarting kube-vip") + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, }, - OnNewLeader: func(identity string) { - // we're notified when new leader elected - if identity == id { - // I just got the lock - return - } - log.Infof("new leader elected: %s", identity) - }, - }, - }) + } + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + err = sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + log.Error(err) + } + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + + log.Fatal("lost leadership, restarting kube-vip") + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + } return nil } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 554848fe..89bd18b5 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -52,6 +52,7 @@ func (sm *Manager) startBGP() error { if err != nil { return err } + // use a Go context so we can tell the leaderelection code when we // want to step down ctx, cancel := context.WithCancel(context.Background()) @@ -107,7 +108,7 @@ func (sm *Manager) startBGP() error { } } - err = sm.servicesWatcher(ctx) + err = sm.servicesWatcher(ctx, sm.syncServices) if err != nil { return err } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go new file mode 100644 index 00000000..74025ed4 --- /dev/null +++ b/pkg/manager/servicesLeader.go @@ -0,0 +1,92 @@ +package manager + +import ( + "context" + "fmt" + "os" + "sync" + "time" + + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/leaderelection" + "k8s.io/client-go/tools/leaderelection/resourcelock" +) + +// The startServicesWatchForLeaderElection function will start a services watcher, the +func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) error { + + err := sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + return err + } + + log.Infof("Shutting down kube-Vip") + + return nil +} + +// The startServicesWatchForLeaderElection function will start a services watcher, the +func (sm *Manager) startServicesLeaderElection(service *v1.Service, wg *sync.WaitGroup) error { + id, err := os.Hostname() + if err != nil { + return err + } + + serviceLease := fmt.Sprintf("kubevip-%s", service.Name) + log.Infof("Beginning services leadership, namespace [%s], lock name [%s], id [%s]", service.Namespace, serviceLease, 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: service.Namespace, + }, + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, + }, + } + + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + err = sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + log.Error(err) + } + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + + log.Fatal("lost leadership, restarting kube-vip") + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + return nil +} diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index c1935725..58777ab4 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -25,7 +25,7 @@ import ( ) // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -func (sm *Manager) servicesWatcher(ctx context.Context) error { +func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(s *v1.Service, wg *sync.WaitGroup) error) error { // Watch function var wg sync.WaitGroup @@ -69,10 +69,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) break } - log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) wg.Add(1) - err = sm.syncServices(svc, &wg) + err = serviceFunc(svc, &wg) + //err = sm.syncServices(svc, &wg) if err != nil { log.Error(err) } From b2df1cba3d8d91ce238009e851215e8be1b63d46 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 8 Jun 2022 13:14:38 +0100 Subject: [PATCH 245/542] Fixes to function signature --- pkg/manager/services.go | 2 +- pkg/manager/servicesLeader.go | 4 ++-- pkg/manager/watcher.go | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 6455dae5..42a7b54d 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -61,7 +61,7 @@ func (sm *Manager) deleteService(uid string) error { return nil } -func (sm *Manager) syncServices(service *v1.Service, wg *sync.WaitGroup) error { +func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() log.Debugf("[STARTING] Service Sync") diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 74025ed4..55a5eeaa 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -17,7 +17,7 @@ import ( // The startServicesWatchForLeaderElection function will start a services watcher, the func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) error { - err := sm.servicesWatcher(ctx, sm.syncServices) + err := sm.servicesWatcher(ctx, sm.startServicesLeaderElection) if err != nil { return err } @@ -28,7 +28,7 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro } // The startServicesWatchForLeaderElection function will start a services watcher, the -func (sm *Manager) startServicesLeaderElection(service *v1.Service, wg *sync.WaitGroup) error { +func (sm *Manager) startServicesLeaderElection(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error { id, err := os.Hostname() if err != nil { return err diff --git a/pkg/manager/watcher.go b/pkg/manager/watcher.go index 58777ab4..b99ae172 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watcher.go @@ -25,7 +25,7 @@ import ( ) // This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(s *v1.Service, wg *sync.WaitGroup) error) error { +func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { // Watch function var wg sync.WaitGroup @@ -71,8 +71,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(s *v1.S } log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) wg.Add(1) - err = serviceFunc(svc, &wg) - //err = sm.syncServices(svc, &wg) + err = serviceFunc(ctx, svc, &wg) if err != nil { log.Error(err) } From 8d4f0e5206d947e4d43445bca96390bbf41d1045 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 21 Jun 2022 13:57:13 +0100 Subject: [PATCH 246/542] annotations and working leaderElection --- cmd/kube-vip.go | 17 ++- pkg/manager/manager.go | 2 - pkg/manager/services.go | 23 +++- pkg/manager/servicesLeader.go | 41 ++++-- .../{watcher.go => watch_annotations.go} | 99 ------------- pkg/manager/watch_services.go | 130 ++++++++++++++++++ pkg/vip/arp.go | 3 +- 7 files changed, 191 insertions(+), 124 deletions(-) rename pkg/manager/{watcher.go => watch_annotations.go} (72%) create mode 100644 pkg/manager/watch_services.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index cfb455be..a145f624 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -105,7 +105,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") // Control plane specific flags - kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The configuration map defined within the cluster") + kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The namespace for the configmap defined within the cluster") // Manage logging kubeVipCmd.PersistentFlags().Uint32Var(&logLevel, "log", 4, "Set the level of logging") @@ -114,8 +114,11 @@ func init() { kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") // Behaviour flags - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane, hybrid mode") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services, hybrid mode") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services") + + // Extended behaviour flags + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServicesElection, "servicesElection", false, "Enable leader election per kubernetes service") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") @@ -204,6 +207,14 @@ var kubeVipManager = &cobra.Command{ log.Fatalln(err) } + // Provide configuration to output/logging + log.Infof("namespace [%s], Mode(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, initConfig.EnableControlPane, initConfig.EnableServices) + + // End if nothing is enabled + if !initConfig.EnableServices && !initConfig.EnableControlPane { + log.Fatalln("no modes are enabled") + } + if err := initConfig.CheckInterface(); err != nil { log.Fatalln(err) } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index e4a7b1b2..d85b7741 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -124,14 +124,12 @@ func (sm *Manager) Start() error { } log.Infoln("Starting Kube-vip Manager with the BGP engine") - log.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane && sm.config.EnableServices) return sm.startBGP() } // 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.Infof("Namespace [%s], Hybrid mode [%t]", sm.config.Namespace, sm.config.EnableControlPane && sm.config.EnableServices) return sm.startARP() } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 42a7b54d..9e98882b 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -3,6 +3,7 @@ package manager import ( "context" "fmt" + "os" "strings" "sync" @@ -16,6 +17,7 @@ import ( const ( hwAddrKey = "kube-vip.io/hwaddr" requestedIP = "kube-vip.io/requestedIP" + vipHost = "kube-vip.io/vipHost" ) func (sm *Manager) deleteService(uid string) error { @@ -89,7 +91,7 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy // This instance wasn't found, we need to add it to the manager if !foundInstance && newServiceAddress != "" { - log.Infof("add the service [%s/%s] with external address %s", service.Namespace, service.Name, newServiceAddress) + log.Infof("add the service [%s/%s] with external address [%s]", service.Namespace, service.Name, newServiceAddress) if err := sm.addService(service); err != nil { return err } @@ -104,7 +106,7 @@ func (sm *Manager) addService(service *v1.Service) error { return err } - log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) + log.Infof("new VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) @@ -148,11 +150,22 @@ func (sm *Manager) updateStatus(i *Instance) error { return err } + id, err := os.Hostname() + if err != nil { + return err + } + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + + // If we're using ARP then we can only broadcast the VIP from one place, add an annotation to the service + if sm.config.EnableARP { + // Add the current host + currentServiceCopy.Annotations[vipHost] = id + } if i.dhcpInterfaceHwaddr != "" || i.dhcpInterfaceIP != "" { - if currentServiceCopy.Annotations == nil { - currentServiceCopy.Annotations = make(map[string]string) - } currentServiceCopy.Annotations[hwAddrKey] = i.dhcpInterfaceHwaddr currentServiceCopy.Annotations[requestedIP] = i.dhcpInterfaceIP } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 55a5eeaa..89eb0814 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -14,9 +14,14 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" ) +// activeService keeps track of services that already have a leaderElection in place +var activeService map[string]bool + // The startServicesWatchForLeaderElection function will start a services watcher, the func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) error { + activeService = make(map[string]bool) + err := sm.servicesWatcher(ctx, sm.startServicesLeaderElection) if err != nil { return err @@ -29,18 +34,23 @@ 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 { + // No leader election is necessary + if activeService[string(service.UID)] { + return nil + } + id, err := os.Hostname() if err != nil { return err } serviceLease := fmt.Sprintf("kubevip-%s", service.Name) - log.Infof("Beginning services leadership, namespace [%s], lock name [%s], id [%s]", service.Namespace, serviceLease, id) + log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", service.Namespace, serviceLease, 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{ LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, + Name: serviceLease, Namespace: service.Namespace, }, Client: sm.clientSet.CoordinationV1(), @@ -48,7 +58,7 @@ func (sm *Manager) startServicesLeaderElection(ctx context.Context, service *v1. Identity: id, }, } - + activeService[string(service.UID)] = true // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -59,24 +69,27 @@ func (sm *Manager) startServicesLeaderElection(ctx context.Context, service *v1. // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, + LeaseDuration: 60 * time.Second, + RenewDeadline: 15 * time.Second, + RetryPeriod: 5 * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - err = sm.servicesWatcher(ctx, sm.syncServices) - if err != nil { - log.Error(err) - } + // we run this in background as it's blocking + go func() { + log.Infof("adding the service [%s/%s] with external address [%s]", service.Namespace, service.Name, service.Spec.LoadBalancerIP) + if err := sm.addService(service); err != nil { + log.Errorln(err) + } + }() }, OnStoppedLeading: func() { // we can do cleanup here log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + if err := sm.deleteService(string(service.UID)); err != nil { + log.Errorln(err) } - - log.Fatal("lost leadership, restarting kube-vip") + // Mark this service is inactive + activeService[string(service.UID)] = false }, OnNewLeader: func(identity string) { // we're notified when new leader elected diff --git a/pkg/manager/watcher.go b/pkg/manager/watch_annotations.go similarity index 72% rename from pkg/manager/watcher.go rename to pkg/manager/watch_annotations.go index b99ae172..536b0b1f 100644 --- a/pkg/manager/watcher.go +++ b/pkg/manager/watch_annotations.go @@ -7,10 +7,8 @@ import ( "os" "strconv" "strings" - "sync" "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" "github.com/davecgh/go-spew/spew" @@ -24,103 +22,6 @@ import ( "k8s.io/client-go/tools/cache" ) -// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { - // Watch function - var wg sync.WaitGroup - - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) - }, - }) - if err != nil { - return fmt.Errorf("error creating services watcher: %s", err.Error()) - } - go func() { - <-sm.signalChan - // Cancel the context - rw.Stop() - }() - ch := rw.ResultChan() - //defer rw.Stop() - log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") - - for event := range ch { - sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - svc, ok := event.Object.(*v1.Service) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") - } - - // We only care about LoadBalancer services - if svc.Spec.Type != v1.ServiceTypeLoadBalancer { - break - } - - // We can ignore this service - if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) - break - } - log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) - wg.Add(1) - err = serviceFunc(ctx, svc, &wg) - if err != nil { - log.Error(err) - } - wg.Wait() - case watch.Deleted: - svc, ok := event.Object.(*v1.Service) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") - } - - // We only care about LoadBalancer services - if svc.Spec.Type != v1.ServiceTypeLoadBalancer { - break - } - - // We can ignore this service - if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) - break - } - - err = sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } - log.Infof("Service [%s/%s] has been deleted", svc.Namespace, svc.Name) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Error("Error attempting to watch Kubernetes services") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - default: - } - } - log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") - return nil -} - // This file handles the watching of node annotations for configuration, it will exit once the annotations are // present func (sm *Manager) annotationsWatcher() error { diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go new file mode 100644 index 00000000..0b4541fa --- /dev/null +++ b/pkg/manager/watch_services.go @@ -0,0 +1,130 @@ +package manager + +import ( + "context" + "fmt" + "sync" + + "github.com/davecgh/go-spew/spew" + "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" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" + watchtools "k8s.io/client-go/tools/watch" +) + +// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { + // Watch function + var wg sync.WaitGroup + + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + return fmt.Errorf("error creating services watcher: %s", err.Error()) + } + go func() { + <-sm.signalChan + // Cancel the context + rw.Stop() + }() + ch := rw.ResultChan() + //defer rw.Stop() + log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") + + for event := range ch { + sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("unable to parse Kubernetes services from API watcher") + } + + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } + + // We only care about LoadBalancer services that have been allocated an address + if svc.Spec.LoadBalancerIP == "" { + break + } + + // We can ignore this service + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } + log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + wg.Add(1) + // Background the services election + if sm.config.EnableServicesElection { + go func() { + err = serviceFunc(ctx, svc, &wg) + if err != nil { + log.Error(err) + } + wg.Wait() + }() + } else { + err = serviceFunc(ctx, svc, &wg) + if err != nil { + log.Error(err) + } + wg.Wait() + } + case watch.Deleted: + svc, ok := event.Object.(*v1.Service) + if !ok { + return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + } + + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } + + // We can ignore this service + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("Service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } + + err = sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) + } + log.Infof("Service [%s/%s] has been deleted", svc.Namespace, svc.Name) + + case watch.Bookmark: + // Un-used + case watch.Error: + log.Error("Error attempting to watch Kubernetes services") + + // This round trip allows us to handle unstructured status + errObject := apierrors.FromObject(event.Object) + statusErr, ok := errObject.(*apierrors.StatusError) + if !ok { + log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) + + } + + status := statusErr.ErrStatus + log.Errorf("%v", status) + default: + } + } + log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") + return nil +} diff --git a/pkg/vip/arp.go b/pkg/vip/arp.go index 62a53551..c2770c3d 100644 --- a/pkg/vip/arp.go +++ b/pkg/vip/arp.go @@ -137,7 +137,8 @@ func sendARP(iface *net.Interface, m *arpMessage) error { Halen: m.hardwareAddressLength, } target := ethernetBroadcast - for i := 0; i < len(target); i++ { + for i := 0; i < len(target); i++ { //nolint + ll.Addr[i] = target[i] } From 7d9062fd0e85cb304f0155393931e101e4472566 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 21 Jun 2022 13:59:27 +0100 Subject: [PATCH 247/542] linting --- pkg/manager/manager_bgp.go | 2 +- pkg/vip/arp.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 89bd18b5..2cc72802 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -52,7 +52,7 @@ func (sm *Manager) startBGP() error { if err != nil { return err } - + // use a Go context so we can tell the leaderelection code when we // want to step down ctx, cancel := context.WithCancel(context.Background()) diff --git a/pkg/vip/arp.go b/pkg/vip/arp.go index c2770c3d..4338d52a 100644 --- a/pkg/vip/arp.go +++ b/pkg/vip/arp.go @@ -138,7 +138,6 @@ func sendARP(iface *net.Interface, m *arpMessage) error { } target := ethernetBroadcast for i := 0; i < len(target); i++ { //nolint - ll.Addr[i] = target[i] } From efea371edccc06414f0b89a6b80d9568e5fc7134 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 21 Jun 2022 15:14:47 +0100 Subject: [PATCH 248/542] Security fixes --- pkg/manager/watch_annotations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index 536b0b1f..a4dd8ea8 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -194,8 +194,8 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er } } - log.Debugf("BGPConfig: %v\n", bgpConfig) - log.Debugf("BGPPeerConfig: %v\n", bgpPeer) + //log.Debugf("BGPConfig: %v\n", bgpConfig) + //log.Debugf("BGPPeerConfig: %v\n", bgpPeer) return bgpConfig, bgpPeer, nil } From f51aa1f60f1bad8836bf3a6fb064434f1da44b43 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 21 Jun 2022 15:19:59 +0100 Subject: [PATCH 249/542] formatting fixes --- pkg/manager/manager.go | 3 +-- pkg/manager/manager_arp.go | 4 ++-- pkg/manager/watch_annotations.go | 4 ++-- pkg/manager/watch_services.go | 11 +++++------ 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index d85b7741..dcc47e7c 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -111,8 +111,7 @@ func (sm *Manager) Start() error { signal.Notify(sm.signalChan, syscall.SIGTERM) // Add Notification for SIGKILL (sent from Kubernetes) - //nolint - signal.Notify(sm.signalChan, syscall.SIGKILL) + signal.Notify(sm.signalChan, syscall.SIGKILL) //nolint // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index c09a81ce..4db0d305 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -99,14 +99,14 @@ func (sm *Manager) startARP() 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.Infof("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.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index a4dd8ea8..c7c7c9db 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -85,7 +85,7 @@ func (sm *Manager) annotationsWatcher() error { case watch.Added, watch.Modified: node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } bgpConfig, bgpPeer, err := parseBgpAnnotations(node, sm.config.Annotations) @@ -101,7 +101,7 @@ func (sm *Manager) annotationsWatcher() error { case watch.Deleted: node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Kubernetes watcher") + return fmt.Errorf("unable to parse Kubernetes Node from Kubernetes watcher") } log.Infof("Node [%s] has been deleted", node.Name) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 0b4541fa..6b8855bd 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -37,7 +37,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context }() ch := rw.ResultChan() //defer rw.Stop() - log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") for event := range ch { sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) @@ -63,10 +62,10 @@ 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("Service [%s] has an ignore annotation for kube-vip", svc.Name) + log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) break } - log.Infof("Service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) wg.Add(1) // Background the services election if sm.config.EnableServicesElection { @@ -87,7 +86,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") + return fmt.Errorf("unable to parse Kubernetes services from API watcher") } // We only care about LoadBalancer services @@ -97,7 +96,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("Service [%s] has an ignore annotation for kube-vip", svc.Name) + log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) break } @@ -105,7 +104,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } - log.Infof("Service [%s/%s] has been deleted", svc.Namespace, svc.Name) + log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used From 5485bbdcabb9229c20ba1a38846788dc9b6059dd Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 21 Jun 2022 15:53:41 +0100 Subject: [PATCH 250/542] This enables local traffic policy --- pkg/manager/watch_services.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 6b8855bd..956df890 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -3,6 +3,7 @@ package manager import ( "context" "fmt" + "os" "sync" "github.com/davecgh/go-spew/spew" @@ -21,6 +22,11 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Watch function var wg sync.WaitGroup + id, err := os.Hostname() + if err != nil { + return err + } + // Use a restartable watcher, as this should help in the event of etcd or timeout issues rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { @@ -60,6 +66,29 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } + // We need to see if the pod is local to this kube-vip pod + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + ep, err := sm.clientSet.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("unable to parse service endpoints [%v]", err) + } + exists := false + for subset := range ep.Subsets { + for address := range ep.Subsets[subset].Addresses { + // Check the node is populated + if ep.Subsets[subset].Addresses[address].NodeName != nil { + if id == *ep.Subsets[subset].Addresses[address].NodeName { + exists = true + } + } + } + } + if !exists { + log.Warnf("loadBalancer has External Traffic Policy: Local, no local pods found") + break + } + } + // We can ignore this service if svc.Annotations["kube-vip.io/ignore"] == "true" { log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) From ccee5ab7bd2cebd03d4cc3ebc89887d57b6487a4 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sat, 25 Jun 2022 16:42:26 +0100 Subject: [PATCH 251/542] Wireguard support (basic) --- cmd/kube-vip.go | 97 ++++++++++++++------ go.mod | 16 ++-- go.sum | 23 +++++ pkg/kubevip/config_environment.go | 10 +++ pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_generator.go | 11 +++ pkg/kubevip/config_types.go | 3 + pkg/manager/manager.go | 7 +- pkg/manager/manager_wireguard.go | 142 ++++++++++++++++++++++++++++++ pkg/wireguard/architecture.md | 23 +++++ pkg/wireguard/wireguard.go | 66 ++++++++++++++ 11 files changed, 367 insertions(+), 34 deletions(-) create mode 100644 pkg/manager/manager_wireguard.go create mode 100644 pkg/wireguard/architecture.md create mode 100644 pkg/wireguard/wireguard.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index a145f624..34aacec1 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -5,12 +5,14 @@ import ( "fmt" "net/http" "os" + "strings" "time" "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" "github.com/kube-vip/kube-vip/pkg/equinixmetal" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -68,7 +70,8 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "Port for the VIP") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for Vip changes") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for VIP changes") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableWireguard, "wireguard", false, "Enable Wireguard for services VIPs") // LoadBalancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS") @@ -200,6 +203,13 @@ var kubeVipManager = &cobra.Command{ Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { + // Set the logging level for all subsequent functions + log.SetLevel(log.Level(logLevel)) + + go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ + Addr: initConfig.PrometheusHTTPServer, + }) + log.Infof("Starting kube-vip.io [%s]", Release.Version) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) @@ -207,41 +217,74 @@ var kubeVipManager = &cobra.Command{ log.Fatalln(err) } + // Determine the kube-vip mode + var mode string + if initConfig.EnableARP { + mode = "ARP" + } + + if initConfig.EnableBGP { + mode = "BGP" + } + + if initConfig.EnableWireguard { + mode = "Wireguard" + } // Provide configuration to output/logging - log.Infof("namespace [%s], Mode(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, initConfig.EnableControlPane, initConfig.EnableServices) + log.Infof("namespace [%s], Mode: [%s], Features(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, mode, initConfig.EnableControlPane, initConfig.EnableServices) // End if nothing is enabled if !initConfig.EnableServices && !initConfig.EnableControlPane { log.Fatalln("no modes are enabled") } - if err := initConfig.CheckInterface(); err != nil { - log.Fatalln(err) - } - - // Set the logging level for all subsequent functions - log.SetLevel(log.Level(logLevel)) - - if initConfig.Interface == "" { - log.Infof("No interface is specified for VIP in config, auto-detecting default Interface") - defaultIF, err := vip.GetDefaultGatewayInterface() + // If we're using wireguard then all traffic goes through the wg0 interface + if initConfig.EnableWireguard { + log.Infof("configuring Wireguard networking") + l, err := netlink.LinkByName("wg0") + if err != nil { + if strings.Contains(err.Error(), "Link not found") { + log.Warnf("interface \"wg0\" doesn't exist, attempting to create wireguard interface ") + err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: "wg0"}}) + if err != nil { + log.Fatalln(err) + } else { + l, err = netlink.LinkByName("wg0") + if err != nil { + log.Fatalln(err) + } + } + } + } + err = netlink.LinkSetUp(l) if err != nil { - _ = cmd.Help() - log.Fatalf("unable to detect default interface -> [%v]", err) + log.Fatalln(err) } - initConfig.Interface = defaultIF.Name - log.Infof("kube-vip will bind to interface [%s]", initConfig.Interface) - - go func() { - if err := vip.MonitorDefaultInterface(context.TODO(), defaultIF); err != nil { - log.Fatalf("crash: %s", err.Error()) + // Set the vip interface to the wireguard interface + initConfig.Interface = "wg0" + } 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") + defaultIF, err := vip.GetDefaultGatewayInterface() + if err != nil { + _ = cmd.Help() + log.Fatalf("unable to detect default interface -> [%v]", err) } - }() + initConfig.Interface = defaultIF.Name + log.Infof("kube-vip will bind to interface [%s]", initConfig.Interface) + + go func() { + if err := vip.MonitorDefaultInterface(context.TODO(), defaultIF); err != nil { + log.Fatalf("crash: %s", err.Error()) + } + }() + } + } + // Perform a check on th state of the interface + if err := initConfig.CheckInterface(); err != nil { + log.Fatalln(err) } - - go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ - Addr: initConfig.PrometheusHTTPServer, - }) // User Environment variables as an option to make manifest clearer envConfigMap := os.Getenv("vip_configmap") @@ -299,11 +342,11 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC } }() - log.Printf("server started") + log.Printf("prometheus HTTP server started") <-ctx.Done() - log.Printf("server stopped") + log.Printf("prometheus HTTP server stopped") ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer func() { diff --git a/go.mod b/go.mod index 71d7c9e1..3e8d517a 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,9 @@ require ( github.com/spf13/cobra v1.4.0 github.com/stretchr/testify v1.7.1 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.0.0-20220403103023-749bd193bc2b - golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b k8s.io/api v0.23.5 k8s.io/apimachinery v0.23.5 k8s.io/client-go v0.23.5 @@ -51,7 +52,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect + github.com/josharian/native v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect github.com/magiconair/properties v1.8.5 // indirect @@ -59,10 +60,10 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc // indirect github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect - github.com/mdlayher/genetlink v1.0.0 // indirect - github.com/mdlayher/netlink v1.4.1 // indirect + github.com/mdlayher/genetlink v1.2.0 // indirect + github.com/mdlayher/netlink v1.6.0 // indirect github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect - github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 // indirect + github.com/mdlayher/socket v0.2.3 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -81,11 +82,14 @@ require ( github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/grpc v1.45.0 // indirect diff --git a/go.sum b/go.sum index 9160767b..efec4ad3 100644 --- a/go.sum +++ b/go.sum @@ -321,6 +321,8 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -390,6 +392,8 @@ github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JA github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= +github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= github.com/mdlayher/ndp v0.10.0 h1:Zdwol2bq1EHY8xSnejIYkq6LEj7dLjLymJX0o/2tjGw= github.com/mdlayher/ndp v0.10.0/go.mod h1:Uv6IWvgvqirNUu2N3ZXJEB86xu6foyUsG0NrClSSfek= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= @@ -403,6 +407,8 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1 h1:I154BCU+mKlIf7BgcAJB2r7QjveNPty6uNY1g9ChVfI= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= +github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= +github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= @@ -410,6 +416,9 @@ github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 h1:qEtkL8n1DAHpi5/AOgAckwGQUlMe4+jhL/GMt+GKIks= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= +github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= +github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -590,6 +599,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -678,10 +689,14 @@ golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -711,6 +726,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -805,8 +821,11 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb h1:PVGECzEo9Y3uOidtkHGdd347NjLtITfJFO9BxFpmRoo= golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -888,6 +907,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0= +golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b h1:9JncmKXcUwE918my+H6xmjBdhK2jM/UTUNXxhRG1BAk= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 018c7cb4..3c80da3a 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -194,6 +194,16 @@ func ParseEnvironment(c *Config) error { c.EnableBGP = b } + // BGP Server options + env = os.Getenv(vipWireguard) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableWireguard = b + } + // BGP Router interface determines an interface that we can use to find an address for env = os.Getenv(bgpRouterInterface) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 9e4584c3..ef5f2a36 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -94,6 +94,9 @@ const ( //bgpSourceIP defines the source address for BGP peering bgpSourceIP = "bgp_sourceip" + //vipWireguard - defines if wireguard will be used for vips + vipWireguard = "vip_wireguard" + //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 28671d01..46556d88 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -177,6 +177,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, packet...) } + // If BGP, but we're not using packet + if c.EnableWireguard { + bgp := []corev1.EnvVar{ + { + Name: vipWireguard, + Value: strconv.FormatBool(c.EnableWireguard), + }, + } + newEnvironment = append(newEnvironment, bgp...) + } + // If BGP, but we're not using packet if c.EnableBGP { bgp := []corev1.EnvVar{ diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 9d05c0a4..00ae2ecb 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -15,6 +15,9 @@ type Config struct { // EnableBGP, will use BGP to advertise the VIP address EnableBGP bool `yaml:"enableBGP"` + // EnableWireguard, will use wireguard to advertise the VIP address + EnableWireguard bool `yaml:"enableWireguard"` + // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPane bool `yaml:"enableControlPane"` diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index dcc47e7c..eda96efb 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -132,7 +132,12 @@ func (sm *Manager) Start() error { return sm.startARP() } - log.Infoln("Prematurely exiting Load-balancer as neither Layer2 or Layer3 is enabled") + if sm.config.EnableWireguard { + log.Infoln("Starting Kube-vip Manager with the Wireguard engine") + return sm.startWireguard() + } + + log.Errorln("prematurely exiting Load-balancer as no modes [ARP/BGP/Wireguard] are enabled") return nil } diff --git a/pkg/manager/manager_wireguard.go b/pkg/manager/manager_wireguard.go new file mode 100644 index 00000000..517508a0 --- /dev/null +++ b/pkg/manager/manager_wireguard.go @@ -0,0 +1,142 @@ +package manager + +import ( + "context" + "os" + "strconv" + "time" + + "github.com/kamhlos/upnp" + "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" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startWireguard() error { + var ns string + var err error + + id, err := os.Hostname() + if err != nil { + return err + } + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + log.Infoln("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 + } + // parse all the details needed for Wireguard + peerPublicKey := s.Data["peerPublicKey"] + peerEndpoint := s.Data["peerEndpoint"] + privateKey := s.Data[id] + + // Configure the interface to join the Wireguard VPN + err = wireguard.ConfigureInterface(string(privateKey), string(peerPublicKey), string(peerEndpoint)) + if err != nil { + return err + } + + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-sm.signalChan + log.Info("Received termination, signaling shutdown") + + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + ns, err = returnNameSpace() + if err != nil { + log.Errorf("Unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) + ns = sm.config.Namespace + } + + // Before starting the leader Election enable any additional functionality + upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) + + if upnpEnabled { + sm.upnp = new(upnp.Upnp) + err := sm.upnp.ExternalIPAddr() + if err != nil { + log.Errorf("Error Enabling UPNP %s", err.Error()) + // Set the struct to nil so nothing should use it in future + sm.upnp = nil + } else { + log.Infof("Successfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) + } + } + + // 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") + 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) + // 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: ns, + }, + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, + }, + } + + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + err = sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + log.Error(err) + } + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + + log.Fatal("lost leadership, restarting kube-vip") + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + } + return nil +} diff --git a/pkg/wireguard/architecture.md b/pkg/wireguard/architecture.md new file mode 100644 index 00000000..458ca16d --- /dev/null +++ b/pkg/wireguard/architecture.md @@ -0,0 +1,23 @@ +# Wireguard Architecture + +This brief document is largely for my own notes about how this functionality is added to `kube-vip`. + +## Overview + +- New Flags +- Startup +- Secret(s) + +### New Flags + +A `--wireguard` flag or `vip_wireguard` environment variable will determine if the Wireguard mode is enabled, if this is the case then it will start the wireguard manager process. + +### Startup + +This will require `kube-vip` starting as a daemonset as it will need to read existing data (secrets) from inside the cluster. + +### Secrets + +The secrets map is `[hostname]pubkey` + +`kubectl create secret generic wireguard --from-literal=k8s01=abcdef12345` \ No newline at end of file diff --git a/pkg/wireguard/wireguard.go b/pkg/wireguard/wireguard.go new file mode 100644 index 00000000..6942e67b --- /dev/null +++ b/pkg/wireguard/wireguard.go @@ -0,0 +1,66 @@ +package wireguard + +import ( + "fmt" + "net" + "os" + "time" + + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func ConfigureInterface(priKey, peerPublicKey, endpoint string) error { + + client, err := wgctrl.New() + if err != nil { + return fmt.Errorf("failed to open client: %v", err) + } + defer client.Close() + + pri, err := wgtypes.ParseKey(priKey) + wgtypes.GenerateKey() + if err != nil { + return fmt.Errorf("failed to generate private key: %v", err) + } + + pub, err := wgtypes.ParseKey(peerPublicKey) // Should be generated by the remote peer + if err != nil { + return fmt.Errorf("failed to parse public key: %v", err) + } + + //log.Printf("Public Key [%s]", pri.PublicKey()) + + port := 51820 + ka := 20 * time.Second + + conf := wgtypes.Config{ + PrivateKey: &pri, + ListenPort: &port, + ReplacePeers: true, + Peers: []wgtypes.PeerConfig{{ + PublicKey: pub, + Remove: false, + UpdateOnly: false, + Endpoint: &net.UDPAddr{ + IP: net.ParseIP(endpoint), + Port: 51820, + }, + PersistentKeepaliveInterval: &ka, + ReplaceAllowedIPs: true, + AllowedIPs: []net.IPNet{{ + IP: net.ParseIP("10.0.0.0"), + Mask: net.ParseIP("0.0.0.0").DefaultMask(), + }}, + }}, + } + + if err := client.ConfigureDevice("wg0", conf); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("wg0 doesn't exist [%s]", err) + } else { + return fmt.Errorf("Unknown config error: %v", err) + } + } + return nil +} From 8d0db81225c7780841ba0a8087f0c018a83ca838 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Sat, 25 Jun 2022 16:57:10 +0100 Subject: [PATCH 252/542] linter fixes --- go.sum | 12 +----------- pkg/kubevip/config_envvar.go | 2 +- pkg/wireguard/wireguard.go | 4 +--- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/go.sum b/go.sum index efec4ad3..2a4c1148 100644 --- a/go.sum +++ b/go.sum @@ -319,7 +319,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -333,7 +332,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR7 github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= -github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190 h1:iycCSDo8EKVueI9sfVBBJmtNn9DnXV/K1YWwEJO+uOs= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -388,9 +386,7 @@ github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= -github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= @@ -405,7 +401,6 @@ github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= -github.com/mdlayher/netlink v1.4.1 h1:I154BCU+mKlIf7BgcAJB2r7QjveNPty6uNY1g9ChVfI= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= @@ -414,7 +409,6 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00 h1:qEtkL8n1DAHpi5/AOgAckwGQUlMe4+jhL/GMt+GKIks= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= @@ -422,6 +416,7 @@ github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaU github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -597,7 +592,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -693,8 +687,6 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= -golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -822,8 +814,6 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb h1:PVGECzEo9Y3uOidtkHGdd347NjLtITfJFO9BxFpmRoo= -golang.org/x/sys v0.0.0-20220403205710-6acee93ad0eb/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index ef5f2a36..d003a18b 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -95,7 +95,7 @@ const ( bgpSourceIP = "bgp_sourceip" //vipWireguard - defines if wireguard will be used for vips - vipWireguard = "vip_wireguard" + vipWireguard = "vip_wireguard" //nolint //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/wireguard/wireguard.go b/pkg/wireguard/wireguard.go index 6942e67b..0eac845b 100644 --- a/pkg/wireguard/wireguard.go +++ b/pkg/wireguard/wireguard.go @@ -19,7 +19,6 @@ func ConfigureInterface(priKey, peerPublicKey, endpoint string) error { defer client.Close() pri, err := wgtypes.ParseKey(priKey) - wgtypes.GenerateKey() if err != nil { return fmt.Errorf("failed to generate private key: %v", err) } @@ -58,9 +57,8 @@ func ConfigureInterface(priKey, peerPublicKey, endpoint string) error { if err := client.ConfigureDevice("wg0", conf); err != nil { if os.IsNotExist(err) { return fmt.Errorf("wg0 doesn't exist [%s]", err) - } else { - return fmt.Errorf("Unknown config error: %v", err) } + return fmt.Errorf("unknown config error: %v", err) } return nil } From fcb24e7eabb4ad48d601c1a8c0164b0d1d550188 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 27 Jun 2022 17:41:33 +0100 Subject: [PATCH 253/542] Fixes to the design --- cmd/kube-vip.go | 16 ++++++++++------ pkg/manager/manager_wireguard.go | 2 +- pkg/wireguard/architecture.md | 12 +++++++++--- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 34aacec1..44d6800a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -240,16 +240,21 @@ var kubeVipManager = &cobra.Command{ // If we're using wireguard then all traffic goes through the wg0 interface if initConfig.EnableWireguard { + if initConfig.Interface == "" { + // Set the vip interface to the wireguard interface + initConfig.Interface = "wg0" + } + log.Infof("configuring Wireguard networking") - l, err := netlink.LinkByName("wg0") + l, err := netlink.LinkByName(initConfig.Interface) if err != nil { if strings.Contains(err.Error(), "Link not found") { - log.Warnf("interface \"wg0\" doesn't exist, attempting to create wireguard interface ") - err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: "wg0"}}) + log.Warnf("interface \"%s\" doesn't exist, attempting to create wireguard interface", initConfig.Interface) + err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: initConfig.Interface}}) if err != nil { log.Fatalln(err) } else { - l, err = netlink.LinkByName("wg0") + l, err = netlink.LinkByName(initConfig.Interface) if err != nil { log.Fatalln(err) } @@ -260,8 +265,7 @@ var kubeVipManager = &cobra.Command{ if err != nil { log.Fatalln(err) } - // Set the vip interface to the wireguard interface - initConfig.Interface = "wg0" + } 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 == "" { diff --git a/pkg/manager/manager_wireguard.go b/pkg/manager/manager_wireguard.go index 517508a0..e362c9d8 100644 --- a/pkg/manager/manager_wireguard.go +++ b/pkg/manager/manager_wireguard.go @@ -36,7 +36,7 @@ func (sm *Manager) startWireguard() error { // parse all the details needed for Wireguard peerPublicKey := s.Data["peerPublicKey"] peerEndpoint := s.Data["peerEndpoint"] - privateKey := s.Data[id] + privateKey := s.Data["privateKey"] // Configure the interface to join the Wireguard VPN err = wireguard.ConfigureInterface(string(privateKey), string(peerPublicKey), string(peerEndpoint)) diff --git a/pkg/wireguard/architecture.md b/pkg/wireguard/architecture.md index 458ca16d..47de96f9 100644 --- a/pkg/wireguard/architecture.md +++ b/pkg/wireguard/architecture.md @@ -18,6 +18,12 @@ This will require `kube-vip` starting as a daemonset as it will need to read exi ### Secrets -The secrets map is `[hostname]pubkey` - -`kubectl create secret generic wireguard --from-literal=k8s01=abcdef12345` \ No newline at end of file +Create a private key for the cluster: + +``` +PRIKEY=$(wg genkey) +PUBKEY=$(echo $PRIKEY | wg pubkey) +PEERKEY=$(sudo wg show wg0 public-key) +echo "kubectl create -n kube-system secret generic wireguard --from-literal=privateKey=$PRIKEY --from-literal=peerPublicKey=$PEERKEY --from-literal=peerEndpoint=192.168.0.179" +sudo wg set wg0 peer $PUBKEY allowed-ips 10.0.0.0/8 +``` From 169eb0c7aaecfd29b5001da3630381b91d8f7c01 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 27 Jun 2022 18:08:09 +0100 Subject: [PATCH 254/542] Adds loadBalancerClass --- pkg/manager/watch_services.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 956df890..3dbc5679 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -89,11 +89,21 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } } - // We can ignore this service + // Check the loadBalancer class + 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 != "kube-vip.io/kube-vip-class" { + log.Infof("service [%s] specified the loadBalancer class [%s], ignoring", *svc.Spec.LoadBalancerClass) + break + } + } + + // Check if we ignore this service if svc.Annotations["kube-vip.io/ignore"] == "true" { log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) break } + log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) wg.Add(1) // Background the services election From 46b4325187a234311b65d29aa78898402c4530eb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 27 Jun 2022 18:59:25 +0100 Subject: [PATCH 255/542] linting fix --- pkg/manager/watch_services.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 3dbc5679..bbe1467d 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -93,7 +93,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context 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 != "kube-vip.io/kube-vip-class" { - log.Infof("service [%s] specified the loadBalancer class [%s], ignoring", *svc.Spec.LoadBalancerClass) + log.Infof("service [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass) break } } From 1bcd101b536bec365e30e96cad5bbd929ac76c94 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 29 Jun 2022 16:08:02 +0100 Subject: [PATCH 256/542] Table mode is now added to kube-vip --- cmd/kube-vip-kubeadm.go | 37 ---------- cmd/kube-vip.go | 21 ++++-- pkg/cluster/cluster.go | 3 +- pkg/cluster/service.go | 15 ++-- pkg/kubevip/config_environment.go | 20 ++++-- pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_generator.go | 21 ++++-- pkg/kubevip/config_manager.go | 64 +---------------- pkg/kubevip/config_types.go | 27 +++----- pkg/manager/instance.go | 15 ++-- pkg/manager/manager.go | 5 ++ pkg/manager/manager_arp.go | 2 +- pkg/manager/manager_table.go | 110 ++++++++++++++++++++++++++++++ pkg/manager/manager_wireguard.go | 2 +- pkg/manager/servicesLeader.go | 4 ++ pkg/vip/address.go | 50 ++++++++++++-- 16 files changed, 247 insertions(+), 152 deletions(-) create mode 100644 pkg/manager/manager_table.go diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index abf322a2..0646e097 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -1,16 +1,12 @@ package cmd import ( - "context" "fmt" "os" - "github.com/kube-vip/kube-vip/pkg/k8s" "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // kubeadm adds two subcommands for managing a vip during a kubeadm init/join @@ -91,39 +87,6 @@ var kubeKubeadmJoin = &cobra.Command{ log.Fatalf("Unable to find file [%s]", kubeConfigPath) } - // We will use kubeconfig in order to find all the master nodes - // use the current context in kubeconfig - clientset, err := k8s.NewClientset(kubeConfigPath, false, "") - if err != nil { - log.Fatal(err.Error()) - } - - opts := metav1.ListOptions{} - opts.LabelSelector = "node-role.kubernetes.io/master" - nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), opts) - if err != nil { - log.Fatal(err.Error()) - } - // Iterate over all nodes that are masters and find the details to build a peer list - for x := range nodes.Items { - // Get hostname and address - var nodeAddress, nodeHostname string - for y := range nodes.Items[x].Status.Addresses { - switch nodes.Items[x].Status.Addresses[y].Type { - case corev1.NodeHostName: - nodeHostname = nodes.Items[x].Status.Addresses[y].Address - case corev1.NodeInternalIP: - nodeAddress = nodes.Items[x].Status.Addresses[y].Address - } - } - - newPeer, err := kubevip.ParsePeerConfig(fmt.Sprintf("%s:%s:%d", nodeHostname, nodeAddress, 10000)) - if err != nil { - panic(err.Error()) - } - initConfig.RemotePeers = append(initConfig.RemotePeers, *newPeer) - - } // Generate manifest and print cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) fmt.Println(cfg) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 44d6800a..707d46ec 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -68,16 +68,20 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPSubnet, "vipSubnet", "", "The Virtual IP address subnet e.g. /32 /24 /8 etc..") + + kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") // todo: deprecate + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Address, "address", "", "an address (IP or DNS name) to use as a VIP") kubeVipCmd.PersistentFlags().IntVar(&initConfig.Port, "port", 6443, "Port for the VIP") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableARP, "arp", false, "Enable Arp for VIP changes") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableWireguard, "wireguard", false, "Enable Wireguard for services VIPs") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableRoutingTable, "table", false, "Enable Routing Table for services VIPs") // LoadBalancer flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLoadBalancer, "enableLoadBalancer", false, "enable loadbalancing on the VIP with IPVS") kubeVipCmd.PersistentFlags().IntVar(&initConfig.LoadBalancerPort, "lbPort", 6443, "loadbalancer port for the VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerForwardingMethod, "lbForwardingMethod", "local", "loadbalancer forwarding method") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DDNS, "ddns", false, "use Dynamic DNS + DHCP to allocate VIP for address") // Clustering type (leaderElection) @@ -86,7 +90,7 @@ func init() { kubeVipCmd.PersistentFlags().IntVar(&initConfig.RenewDeadline, "leaseRenewDuration", 3, "Length of time a Kubernetes leader can attempt to renew its lease") kubeVipCmd.PersistentFlags().IntVar(&initConfig.RetryPeriod, "leaseRetry", 1, "Number of times the host will retry to hold a lease") - // Packet flags + // Equinix Metal flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableMetal, "metal", false, "This will use the Equinix Metal API (requires the token ENV) to update the EIP <-> VIP") kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalAPIKey, "metalKey", "", "The API token for authenticating with the Equinix Metal API") kubeVipCmd.PersistentFlags().StringVar(&initConfig.MetalProject, "metalProject", "", "The name of project already created within Equinix Metal") @@ -94,7 +98,6 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.ProviderConfig, "provider-config", "", "The path to a provider configuration") // BGP flags - kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPCIDR, "cidr", "32", "The CIDR range for the virtual IP address") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableBGP, "bgp", false, "This will enable BGP support within kube-vip") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.RouterID, "bgpRouterID", "", "The routerID for the bgp server") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)") @@ -116,6 +119,9 @@ func init() { // Service flags kubeVipService.Flags().StringVarP(&configMap, "configMap", "c", "plndr", "The configuration map defined within the cluster") + // Routing Table flags + kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableID, "tableID", 198, "The routing table used for all table entries") + // Behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services") @@ -205,11 +211,9 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(logLevel)) - go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ Addr: initConfig.PrometheusHTTPServer, }) - log.Infof("Starting kube-vip.io [%s]", Release.Version) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) @@ -230,12 +234,17 @@ var kubeVipManager = &cobra.Command{ if initConfig.EnableWireguard { mode = "Wireguard" } + + if initConfig.EnableRoutingTable { + mode = "Routing Table" + } + // Provide configuration to output/logging log.Infof("namespace [%s], Mode: [%s], Features(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, mode, initConfig.EnableControlPane, initConfig.EnableServices) // End if nothing is enabled if !initConfig.EnableServices && !initConfig.EnableControlPane { - log.Fatalln("no modes are enabled") + log.Fatalln("no features are enabled") } // If we're using wireguard then all traffic goes through the wg0 interface diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index b8819bc2..45f7212d 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -40,10 +40,11 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { address = c.Address } - network, err := vip.NewConfig(address, c.Interface, c.DDNS) + network, err := vip.NewConfig(address, c.Interface, c.VIPSubnet, c.DDNS, c.RoutingTableID) if err != nil { return nil, err } + return network, nil } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 148ebb5d..48cba93e 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -174,12 +174,17 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser if err != nil { log.Warnf("Attempted to clean existing VIP => %v", err) } - - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) + if c.EnableRoutingTable { + err = cluster.Network.AddRoute() + if err != nil { + log.Warnf("%v", err) + } + } else { + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } } - if c.EnableARP { //ctxArp, cancelArp = context.WithCancel(context.Background()) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 3c80da3a..37319dec 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -184,24 +184,34 @@ func ParseEnvironment(c *Config) error { c.EnableARP = b } - // BGP Server options - env = os.Getenv(bgpEnable) + // Wireguard Mode + env = os.Getenv(vipWireguard) if env != "" { b, err := strconv.ParseBool(env) if err != nil { return err } - c.EnableBGP = b + c.EnableWireguard = b + } + + // Routing Table Mode + env = os.Getenv(vipRoutingTable) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableRoutingTable = b } // BGP Server options - env = os.Getenv(vipWireguard) + env = os.Getenv(bgpEnable) if env != "" { b, err := strconv.ParseBool(env) if err != nil { return err } - c.EnableWireguard = b + c.EnableBGP = b } // BGP Router interface determines an interface that we can use to find an address for diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d003a18b..bc5770be 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -97,6 +97,9 @@ const ( //vipWireguard - defines if wireguard will be used for vips vipWireguard = "vip_wireguard" //nolint + //vipRoutingTable - defines if table mode will be used for vips + vipRoutingTable = "vip_routingtable" //nolint + //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 46556d88..4843982d 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -177,18 +177,29 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, packet...) } - // If BGP, but we're not using packet + // Detect and enable wireguard mode if c.EnableWireguard { - bgp := []corev1.EnvVar{ + wireguard := []corev1.EnvVar{ { Name: vipWireguard, Value: strconv.FormatBool(c.EnableWireguard), }, } - newEnvironment = append(newEnvironment, bgp...) + newEnvironment = append(newEnvironment, wireguard...) + } + + // Detect and enable routing table mode + if c.EnableRoutingTable { + routingtable := []corev1.EnvVar{ + { + Name: vipWireguard, + Value: strconv.FormatBool(c.EnableRoutingTable), + }, + } + newEnvironment = append(newEnvironment, routingtable...) } - // If BGP, but we're not using packet + // If BGP, but we're not using Equinix Metal if c.EnableBGP { bgp := []corev1.EnvVar{ { @@ -198,7 +209,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newEnvironment = append(newEnvironment, bgp...) } - // If BGP, but we're not using packet + // If BGP, but we're not using Equinix Metal if c.EnableBGP && !c.EnableMetal { bgpConfig := []corev1.EnvVar{ { diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 25ef6a7d..b6d2009e 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -25,19 +25,6 @@ func ParseBackendConfig(ep string) (*BackEnd, error) { return &BackEnd{Address: endpoint[0], Port: p}, nil } -//ParsePeerConfig - -func ParsePeerConfig(ep string) (*RaftPeer, error) { - endpoint := strings.Split(ep, ":") - if len(endpoint) != 3 { - return nil, fmt.Errorf("ensure a peer is in in the format id:address:port, e.g. server1:10.0.0.1:8080") - } - p, err := strconv.Atoi(endpoint[2]) - if err != nil { - return nil, err - } - return &RaftPeer{ID: endpoint[0], Address: endpoint[1], Port: p}, nil -} - //OpenConfig will attempt to read a file and parse it's contents into a configuration func OpenConfig(path string) (*Config, error) { if path == "" { @@ -73,61 +60,12 @@ func (c *Config) PrintConfig() { fmt.Print(string(b)) } -//ParseFlags will write the current configuration to a specified [path] -func (c *Config) ParseFlags(localPeer string, remotePeers, backends []string) error { - // Parse localPeer - p, err := ParsePeerConfig(localPeer) - if err != nil { - return err - } - c.LocalPeer = *p - - // Parse remotePeers - //Iterate backends - for i := range remotePeers { - p, err := ParsePeerConfig(remotePeers[i]) - if err != nil { - return err - - } - c.RemotePeers = append(c.RemotePeers, *p) - } - - //Iterate backends - for i := range backends { - b, err := ParseBackendConfig(backends[i]) - if err != nil { - return err - } - c.LoadBalancers[0].Backends = append(c.LoadBalancers[0].Backends, *b) - } - - return nil -} - //SampleConfig will create an example configuration and write it to the specified [path] func SampleConfig() { // Generate Sample configuration c := &Config{ - // Generate sample peers - RemotePeers: []RaftPeer{ - { - ID: "server2", - Address: "192.168.0.2", - Port: 10000, - }, - { - ID: "server3", - Address: "192.168.0.3", - Port: 10000, - }, - }, - LocalPeer: RaftPeer{ - ID: "server1", - Address: "192.168.0.1", - Port: 10000, - }, + // Virtual IP address VIP: "192.168.0.100", // Interface to bind to diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 00ae2ecb..e1c115b4 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -18,6 +18,9 @@ type Config struct { // EnableWireguard, will use wireguard to advertise the VIP address EnableWireguard bool `yaml:"enableWireguard"` + // EnableRoutingTable, will use the routing table to advertise the VIP address + EnableRoutingTable bool `yaml:"enableRoutingTable"` + // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPane bool `yaml:"enableControlPane"` @@ -33,18 +36,15 @@ type Config struct { // LeaderElection defines the settings around Kubernetes LeaderElection LeaderElection - // LocalPeer is the configuration of this host - LocalPeer RaftPeer `yaml:"localPeer"` - - // Peers are all of the peers within the RAFT cluster - RemotePeers []RaftPeer `yaml:"remotePeers"` - // AddPeersAsBackends, this will automatically add RAFT peers as backends to a loadbalancer AddPeersAsBackends bool `yaml:"addPeersAsBackends"` // VIP is the Virtual IP address exposed for the cluster (TODO: deprecate) VIP string `yaml:"vip"` + // VipSubnet is the Subnet that is applied to the VIP + VIPSubnet string `yaml:"vipSubnet"` + // VIPCIDR is cidr range for the VIP (primarily needed for BGP) VIPCIDR string `yaml:"vipCidr"` @@ -81,6 +81,9 @@ type Config struct { // Forwarding method for the IPVS Service LoadBalancerForwardingMethod string `yaml:"lbForwardingMethod"` + // Routing Table ID for when using routing table mode + RoutingTableID int `yaml:"routingTableID"` + // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer @@ -124,18 +127,6 @@ type LeaderElection struct { RetryPeriod int } -// RaftPeer details the configuration of all cluster peers -type RaftPeer struct { - // ID is the unique identifier a peer instance - ID string `yaml:"id"` - - // IP Address of a peer instance - Address string `yaml:"address"` - - // Listening port of this peer instance - Port int `yaml:"port"` -} - // LoadBalancer contains the configuration of a load balancing instance type LoadBalancer struct { // Name of a LoadBalancer diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index a7c18502..082489fa 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -56,12 +56,15 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) // Generate new Virtual IP configuration newVip := &kubevip.Config{ - VIP: instanceAddress, //TODO support more than one vip? - Interface: serviceInterface, - SingleNode: true, - EnableARP: config.EnableARP, - EnableBGP: config.EnableBGP, - VIPCIDR: config.VIPCIDR, + VIP: instanceAddress, //TODO support more than one vip? + Interface: serviceInterface, + SingleNode: true, + EnableARP: config.EnableARP, + EnableBGP: config.EnableBGP, + VIPCIDR: config.VIPCIDR, + VIPSubnet: config.VIPSubnet, + EnableRoutingTable: config.EnableRoutingTable, + RoutingTableID: config.RoutingTableID, } // Create new service diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index eda96efb..99bae91b 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -137,6 +137,11 @@ func (sm *Manager) Start() error { return sm.startWireguard() } + if sm.config.EnableRoutingTable { + log.Infoln("Starting Kube-vip Manager with the Routing Table engine") + return sm.startTableMode() + } + log.Errorln("prematurely exiting Load-balancer as no modes [ARP/BGP/Wireguard] are enabled") return nil } diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 4db0d305..2a591f9b 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -71,7 +71,7 @@ func (sm *Manager) startARP() error { } else { ns, err = returnNameSpace() if err != nil { - log.Errorf("Unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) + log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) ns = sm.config.Namespace } } diff --git a/pkg/manager/manager_table.go b/pkg/manager/manager_table.go new file mode 100644 index 00000000..6aedd605 --- /dev/null +++ b/pkg/manager/manager_table.go @@ -0,0 +1,110 @@ +package manager + +import ( + "context" + "os" + "time" + + 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" +) + +// Start will begin the Manager, which will start services and watch the configmap +func (sm *Manager) startTableMode() error { + var ns string + var err error + + id, err := os.Hostname() + if err != nil { + return err + } + + // use a Go context so we can tell the leaderelection code when we + // want to step down + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + log.Infof("all routing table entries will exist in table [%d]", sm.config.RoutingTableID) + + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-sm.signalChan + log.Info("Received termination, signaling shutdown") + + // Cancel the context, which will in turn cancel the leadership + cancel() + }() + + ns, err = returnNameSpace() + if err != nil { + log.Warnf("unable to auto-detect namespace, dropping to [%s]", 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") + 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) + // 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: plunderLock, + Namespace: ns, + }, + Client: sm.clientSet.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: id, + }, + } + + // start the leader election code loop + leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ + Lock: lock, + // IMPORTANT: you MUST ensure that any code you have that + // is protected by the lease must terminate **before** + // you call cancel. Otherwise, you could have a background + // loop still running and another process could + // get elected before your background loop finished, violating + // the stated goal of the lease. + ReleaseOnCancel: true, + LeaseDuration: 10 * time.Second, + RenewDeadline: 5 * time.Second, + RetryPeriod: 1 * time.Second, + Callbacks: leaderelection.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + err = sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + log.Error(err) + } + }, + OnStoppedLeading: func() { + // we can do cleanup here + log.Infof("leader lost: %s", id) + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + + log.Fatal("lost leadership, restarting kube-vip") + }, + OnNewLeader: func(identity string) { + // we're notified when new leader elected + if identity == id { + // I just got the lock + return + } + log.Infof("new leader elected: %s", identity) + }, + }, + }) + } + return nil +} diff --git a/pkg/manager/manager_wireguard.go b/pkg/manager/manager_wireguard.go index e362c9d8..197a1d31 100644 --- a/pkg/manager/manager_wireguard.go +++ b/pkg/manager/manager_wireguard.go @@ -55,7 +55,7 @@ func (sm *Manager) startWireguard() error { ns, err = returnNameSpace() if err != nil { - log.Errorf("Unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) + log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) ns = sm.config.Namespace } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 89eb0814..0c3f0d56 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -27,6 +27,10 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro return err } + for x := range sm.serviceInstances { + sm.serviceInstances[x].cluster.Stop() + } + log.Infof("Shutting down kube-Vip") return nil diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 3c99ace2..6d586236 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -15,7 +15,9 @@ const ( // Network is an interface that enable managing operations for a given IP type Network interface { AddIP() error + AddRoute() error DeleteIP() error + DeleteRoute() error IsSet() (bool, error) IP() string SetIP(ip string) error @@ -35,6 +37,8 @@ type network struct { dnsName string isDDNS bool + + routeTable int } func netlinkParse(addr string) (*netlink.Addr, error) { @@ -46,19 +50,29 @@ func netlinkParse(addr string) (*netlink.Addr, error) { } // NewConfig will attempt to provide an interface to the kernel network configuration -func NewConfig(address string, iface string, isDDNS bool) (Network, error) { +func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID int) (Network, error) { result := &network{} link, err := netlink.LinkByName(iface) if err != nil { return result, errors.Wrapf(err, "could not get link for interface '%s'", iface) } + result.link = link + result.routeTable = tableID if IsIP(address) { - result.address, err = netlinkParse(address) - if err != nil { - return result, errors.Wrapf(err, "could not parse address '%s'", address) + // Check if the subnet needs overriding + if subnet != "" { + result.address, err = netlink.ParseAddr(address + subnet) + if err != nil { + return result, errors.Wrapf(err, "could not parse address '%s'", address) + } + } else { + result.address, err = netlinkParse(address) + if err != nil { + return result, errors.Wrapf(err, "could not parse address '%s'", address) + } } // Ensure we don't have a global address on loopback if iface == "lo" { @@ -91,6 +105,34 @@ func NewConfig(address string, iface string, isDDNS bool) (Network, error) { return result, err } +// AddRoute - Add an IP address to a route table +func (configurator *network) AddRoute() error { + route := &netlink.Route{ + Scope: netlink.SCOPE_UNIVERSE, + Dst: configurator.address.IPNet, + LinkIndex: configurator.link.Attrs().Index, + Table: configurator.routeTable, + } + if err := netlink.RouteAdd(route); err != nil { + return err + } + return nil +} + +// AddRoute - Add an IP address to a route table +func (configurator *network) DeleteRoute() error { + route := &netlink.Route{ + Scope: netlink.SCOPE_UNIVERSE, + Dst: configurator.address.IPNet, + LinkIndex: configurator.link.Attrs().Index, + Table: configurator.routeTable, + } + if err := netlink.RouteDel(route); err != nil { + return err + } + return nil +} + // AddIP - Add an IP address to the interface func (configurator *network) AddIP() error { if err := netlink.AddrReplace(configurator.link, configurator.address); err != nil { From 9d15e0ac8b442d8a74f5acb576091233ce5f5adb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 30 Jun 2022 11:25:40 +0100 Subject: [PATCH 257/542] fixes to missing env --- pkg/kubevip/config_environment.go | 10 ++++++++++ pkg/kubevip/config_envvar.go | 7 +++++-- pkg/kubevip/config_generator.go | 13 +++++++++++-- testing/kubeadm/create.sh | 10 +++++----- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 37319dec..cc2c693b 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -138,6 +138,16 @@ func ParseEnvironment(c *Config) error { return err } c.EnableServices = b + + // Find Services leader Election + env = os.Getenv(svcElection) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableServicesElection = b + } } // Find vip address cidr range diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index bc5770be..d8de7f5b 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -103,12 +103,15 @@ const ( //cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" - //cpEnable starts kube-vip in the hybrid mode + //cpEnable enables the control plane feature cpEnable = "cp_enable" - //cpEnable starts kube-vip in the hybrid mode + //svcEnable enables the Kubernetes service feature svcEnable = "svc_enable" + //svcElection enables election per Kubernetes service + svcElection = "svc_election" + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 4843982d..e2ec828b 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -83,13 +83,22 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod // If we're doing the hybrid mode if c.EnableServices { - cp := []corev1.EnvVar{ + svc := []corev1.EnvVar{ { Name: svcEnable, Value: strconv.FormatBool(c.EnableServices), }, } - newEnvironment = append(newEnvironment, cp...) + newEnvironment = append(newEnvironment, svc...) + if c.EnableServicesElection { + svcElection := []corev1.EnvVar{ + { + Name: svcElection, + Value: strconv.FormatBool(c.EnableServicesElection), + }, + } + newEnvironment = append(newEnvironment, svcElection...) + } } // If Leader election is enabled then add the configuration to the manifest diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 728ab0c8..5d61650d 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -20,11 +20,11 @@ first_node() { logr "INFO" "Creating First node!" #ssh $NODE01 "sudo modprobe ip_vs_rr" #ssh $NODE01 "sudo modprobe nf_conntrack" - logr "INFO" "$(ssh $NODE01 "docker rmi plndr/kube-vip:$kube_vip_version" 2>&1)" + logr "INFO" "$(ssh $NODE01 "docker rmi ghcr.io/kube-vip/kube-vip:$kube_vip_version" 2>&1)" # echo "echo "ip_vs | tee -a /etc/modules" logr "INFO" "Creating Kube-vip.io Manifest" - ssh $NODE01 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + ssh $NODE01 "sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile logr "INFO" "Deploying first Kubernetes node $NODE01" FIRST_NODE=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $kubernetes_version --control-plane-endpoint $kube_vip_vip --upload-certs --pod-network-cidr=10.0.0.0/16") echo "$FIRST_NODE" >> $logfile @@ -48,11 +48,11 @@ additional_controlplane() { logr "INFO" "Adding $NODE02" ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile sleep 1 - ssh $NODE02 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + ssh $NODE02 "sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile logr "INFO" "Adding $NODE03" ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile sleep 1 - ssh $NODE03 "sudo docker run --network host --rm plndr/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + ssh $NODE03 "sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:$kube_vip_version manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile } ## Main() @@ -96,7 +96,7 @@ esac if [[ -z "$DEPS" ]]; then logr "INFO" "Installing specific version of Kubernetes Dependancies" - install_deps +# install_deps fi first_node From 93dfe4d3723f2b02e863116c4ee27e82a5c17b4d Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Fri, 1 Jul 2022 17:01:59 +0100 Subject: [PATCH 258/542] prometheus changes --- cmd/kube-vip.go | 15 ++++++++++----- pkg/kubevip/config_environment.go | 7 +++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 11 +++++++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 707d46ec..c61c1611 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -209,11 +209,6 @@ var kubeVipManager = &cobra.Command{ Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { - // Set the logging level for all subsequent functions - log.SetLevel(log.Level(logLevel)) - go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ - Addr: initConfig.PrometheusHTTPServer, - }) log.Infof("Starting kube-vip.io [%s]", Release.Version) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) @@ -221,6 +216,16 @@ var kubeVipManager = &cobra.Command{ log.Fatalln(err) } + // Set the logging level for all subsequent functions + log.SetLevel(log.Level(logLevel)) + + // start prometheus server + if initConfig.PrometheusHTTPServer != "" { + go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ + Addr: initConfig.PrometheusHTTPServer, + }) + } + // Determine the kube-vip mode var mode string if initConfig.EnableARP { diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index cc2c693b..805907c6 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -355,5 +355,12 @@ func ParseEnvironment(c *Config) error { if env != "" { c.LoadBalancerForwardingMethod = env } + + // Find Prometheus configuration + env = os.Getenv(prometheusServer) + if env != "" { + c.PrometheusHTTPServer = env + } + return nil } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d8de7f5b..d8936847 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -121,6 +121,9 @@ const ( //lbForwardingMethod defines the forwarding method of load-balancer lbForwardingMethod = "lb_fwdmethod" + //prometheusServer defines the address prometheus listens on + prometheusServer = "prometheus_server" + //vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index e2ec828b..d78fd16c 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -313,6 +313,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }) } + if c.PrometheusHTTPServer != "" { + prometheus := []corev1.EnvVar{ + + { + Name: prometheusServer, + Value: c.PrometheusHTTPServer, + }, + } + newEnvironment = append(newEnvironment, prometheus...) + } + newManifest := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", From e6048c3eab00ea03d9c85afb768014353bbf3355 Mon Sep 17 00:00:00 2001 From: zhanglei Date: Thu, 14 Jul 2022 19:37:48 +0800 Subject: [PATCH 259/542] Fixes close nil channel panic Signed-off-by: zhanglei --- pkg/cluster/cluster.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 45f7212d..00b786a6 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -51,7 +51,9 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { // Stop - Will stop the Cluster and release VIP if needed func (cluster *Cluster) Stop() { // Close the stop chanel, which will shut down the VIP (if needed) - close(cluster.stop) + if cluster.stop != nil { + close(cluster.stop) + } // Wait until the completed channel is closed, signallign all shutdown tasks completed <-cluster.completed From ef78dcc5e53c1584a9ac14dd23b8b638a6f6ed5b Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 15 Jul 2022 08:53:50 +0100 Subject: [PATCH 260/542] Create FUNDING.yml --- .github/FUNDING.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..2e34c565 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# Enable GitHub funding + +github: # [thebsdbox] + From a70b965b52418699c7abed889bb8b4909139f32a Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 15 Jul 2022 22:34:04 +0100 Subject: [PATCH 261/542] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2e34c565..b2ec3752 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # Enable GitHub funding -github: # [thebsdbox] +github: [thebsdbox] From 31786074a88d6e041c166317102cfc9c508d0372 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 21 Jul 2022 14:30:54 +0100 Subject: [PATCH 262/542] Adds a route if leader --- pkg/cluster/service.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 48cba93e..a6cc2794 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -154,6 +154,14 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co } }(ctxArp) } + + if c.EnableRoutingTable { + err = cluster.Network.AddRoute() + if err != nil { + log.Warnf("%v", err) + } + } + return nil } From 1ef35923057160d9862d5c71e27e7e3238bedff3 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 22 Jul 2022 09:27:24 +0100 Subject: [PATCH 263/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b7b08e46..d6da9866 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.4.4 +VERSION := v0.5.0 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 708f4b3ebf30e3d3a4cb780223b27e2388262532 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Sun, 7 Aug 2022 12:24:32 +0100 Subject: [PATCH 264/542] Update FUNDING.yml --- .github/FUNDING.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index b2ec3752..972401f6 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,4 @@ # Enable GitHub funding -github: [thebsdbox] +github: [kube-vip] From 14100f0aece4ef0c0f80ecdca95ae5e719121933 Mon Sep 17 00:00:00 2001 From: valtzu Date: Mon, 8 Aug 2022 00:05:13 +0300 Subject: [PATCH 265/542] Allow fixed virtual MAC for VIPs via DHCP Closes #354 Signed-off-by: valtzu --- pkg/manager/instance.go | 2 +- pkg/service/services_dhcp.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 082489fa..c3b84e61 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -168,7 +168,7 @@ func (i *Instance) startDHCP() (chan string, error) { } var initRebootFlag bool - if i.dhcpInterfaceHwaddr != "" { + if i.dhcpInterfaceIP != "" { initRebootFlag = true } diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index 997ac69f..3766c485 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -65,7 +65,7 @@ func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Confi } var initRebootFlag bool - if newService.dhcpInterfaceHwaddr != "" { + if newService.dhcpInterfaceIP != "" { initRebootFlag = true } From c50465c09c64ad3146c307c9d4f55dec19ebbcf2 Mon Sep 17 00:00:00 2001 From: Abhinav Pandey Date: Thu, 4 Aug 2022 16:32:34 -0700 Subject: [PATCH 266/542] Enable kube-vip to only respond to svc with kube-vip's lb class Signed-off-by: Abhinav Pandey --- cmd/kube-vip.go | 1 + pkg/kubevip/config_environment.go | 10 ++++++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 9 +++++++++ pkg/kubevip/config_types.go | 3 +++ pkg/manager/watch_services.go | 4 ++++ 6 files changed, 30 insertions(+) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index c61c1611..58b26fe7 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -128,6 +128,7 @@ func init() { // Extended behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServicesElection, "servicesElection", false, "Enable leader election per kubernetes service") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassOnly, "lbClassOnly", false, "Enable load balancing only for services with LoadBalancerClass \"kube-vip.io/kube-vip-class\"") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 805907c6..7de77676 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -148,6 +148,16 @@ func ParseEnvironment(c *Config) error { } c.EnableServicesElection = b } + + // Find load-balancer class only + env = os.Getenv(lbClassOnly) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.LoadBalancerClassOnly = b + } } // Find vip address cidr range diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d8936847..e53668ed 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -112,6 +112,9 @@ const ( //svcElection enables election per Kubernetes service svcElection = "svc_election" + //lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only + lbClassOnly = "lb_class_only" + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index d78fd16c..b0e58ad6 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -99,6 +99,15 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newEnvironment = append(newEnvironment, svcElection...) } + if c.LoadBalancerClassOnly { + lbClassOnlyVar := []corev1.EnvVar{ + { + Name: lbClassOnly, + Value: strconv.FormatBool(c.LoadBalancerClassOnly), + }, + } + newEnvironment = append(newEnvironment, lbClassOnlyVar...) + } } // If Leader election is enabled then add the configuration to the manifest diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index e1c115b4..8c644e4b 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -30,6 +30,9 @@ type Config struct { // EnableServicesElection, will enable leaderElection per service EnableServicesElection bool `yaml:"enableServicesElection"` + // LoadBalancerClassOnly, will enable load balancing only for services with LoadBalancerClass set to "kube-vip.io/kube-vip-class" + LoadBalancerClassOnly bool `yaml:"lbClassOnly"` + // Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations Annotations string diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index bbe1467d..c2608d36 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -96,6 +96,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Infof("service [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass) break } + } 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("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) + break } // Check if we ignore this service From 494283d511645f12d2bc7870a679f79a075916b2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 26 Aug 2022 09:31:34 +0100 Subject: [PATCH 267/542] Add Anchore SBOM creation --- .github/workflows/anchore-syft.yml | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/anchore-syft.yml diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml new file mode 100644 index 00000000..86d3f3ab --- /dev/null +++ b/.github/workflows/anchore-syft.yml @@ -0,0 +1,38 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, builds an image, performs a container image +# scan with Anchore's Syft tool, and uploads the results to the GitHub Dependency +# submission API. + +# For more information on the Anchore sbom-action usage +# and parameters, see https://github.com/anchore/sbom-action. For more +# information about the Anchore SBOM tool, Syft, see +# https://github.com/anchore/syft +name: Anchore Syft SBOM scan + +on: + push: + branches: [ "main" ] + +permissions: + contents: write + +jobs: + Anchore-Build-Scan: + permissions: + contents: write # required to upload to the Dependency submission API + runs-on: ubuntu-latest + steps: + - name: Checkout the code + uses: actions/checkout@v3 + - name: Build the Docker image + run: docker build . --file Dockerfile --tag localbuild/testimage:latest + - name: Scan the image and upload dependency results + uses: anchore/sbom-action@bb716408e75840bbb01e839347cd213767269d4a + with: + image: "localbuild/testimage:latest" + artifact-name: image.spdx.json + dependency-snapshot: true From a29cf4ea8010a1c64abd117c0baa3d15a80b8215 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 26 Aug 2022 09:36:29 +0100 Subject: [PATCH 268/542] Update anchore-syft.yml Fixes buildkit dependency --- .github/workflows/anchore-syft.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 86d3f3ab..23f873eb 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -28,6 +28,8 @@ jobs: steps: - name: Checkout the code uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 - name: Build the Docker image run: docker build . --file Dockerfile --tag localbuild/testimage:latest - name: Scan the image and upload dependency results From 6b12d18ab25afa181d139c4929525b152b843370 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 26 Aug 2022 09:39:04 +0100 Subject: [PATCH 269/542] Update anchore-syft.yml --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 23f873eb..3a2d38b2 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -31,7 +31,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Build the Docker image - run: docker build . --file Dockerfile --tag localbuild/testimage:latest + run: docker buildx build . --file Dockerfile --tag localbuild/testimage:latest - name: Scan the image and upload dependency results uses: anchore/sbom-action@bb716408e75840bbb01e839347cd213767269d4a with: From 85cb26d3054cb24d823d1f2a706dfca32acf62c1 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 26 Aug 2022 12:52:07 +0100 Subject: [PATCH 270/542] Update anchore-syft.yml --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 3a2d38b2..eb47e1df 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -31,7 +31,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Build the Docker image - run: docker buildx build . --file Dockerfile --tag localbuild/testimage:latest + run: docker buildx build . --file Dockerfile --load --tag localbuild/testimage:latest - name: Scan the image and upload dependency results uses: anchore/sbom-action@bb716408e75840bbb01e839347cd213767269d4a with: From 7e97ef0eef21f4e7247d7f4fce286e13b35842e0 Mon Sep 17 00:00:00 2001 From: Chris Privitere <23177737+cprivitere@users.noreply.github.com> Date: Mon, 29 Aug 2022 15:29:42 -0500 Subject: [PATCH 271/542] go fmt Signed-off-by: Chris Privitere <23177737+cprivitere@users.noreply.github.com> --- cmd/kube-vip-manifests.go | 2 +- pkg/bgp/peers.go | 2 +- pkg/equinixmetal/utils.go | 2 +- pkg/kubevip/config_manager.go | 10 ++-- pkg/service/prom.go | 2 +- pkg/vip/dhcp.go | 91 +++++++++++++++++++---------------- 6 files changed, 59 insertions(+), 50 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 093a3a02..8eab6cec 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -13,7 +13,7 @@ import ( // - Pod spec manifest, mainly used for a static pod (kubeadm) // - Daemonset manifest, mainly used to run kube-vip as a deamonset within Kubernetes (k3s/rke) -//var inCluster bool +// var inCluster bool var taint bool func init() { diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 400536b0..f58c6258 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -12,7 +12,7 @@ import ( api "github.com/osrg/gobgp/v3/api" ) -// AddPeer will add peers to the BGP configuration +// AddPeer will add peers to the BGP configuration func (b *Server) AddPeer(peer Peer) (err error) { port := 179 diff --git a/pkg/equinixmetal/utils.go b/pkg/equinixmetal/utils.go index 9c982aff..95d2734e 100644 --- a/pkg/equinixmetal/utils.go +++ b/pkg/equinixmetal/utils.go @@ -38,7 +38,7 @@ func findSelf(c *packngo.Client, projectID string) *packngo.Device { return nil } -//GetPacketConfig will lookup the configuration from a file path +// GetPacketConfig will lookup the configuration from a file path func GetPacketConfig(providerConfig string) (string, string, error) { var config struct { AuthToken string `json:"apiKey"` diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index b6d2009e..128024f2 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -12,7 +12,7 @@ import ( "github.com/vishvananda/netlink" ) -//ParseBackendConfig - +// ParseBackendConfig - func ParseBackendConfig(ep string) (*BackEnd, error) { endpoint := strings.Split(ep, ":") if len(endpoint) != 2 { @@ -25,7 +25,7 @@ func ParseBackendConfig(ep string) (*BackEnd, error) { return &BackEnd{Address: endpoint[0], Port: p}, nil } -//OpenConfig will attempt to read a file and parse it's contents into a configuration +// OpenConfig will attempt to read a file and parse it's contents into a configuration func OpenConfig(path string) (*Config, error) { if path == "" { return nil, fmt.Errorf("path cannot be blank") @@ -53,14 +53,14 @@ func OpenConfig(path string) (*Config, error) { return nil, fmt.Errorf("error reading [%s]", path) } -//PrintConfig - will print out an instance of the kubevip config +// PrintConfig - will print out an instance of the kubevip config func (c *Config) PrintConfig() { b, _ := yaml.Marshal(c) fmt.Print(string(b)) } -//SampleConfig will create an example configuration and write it to the specified [path] +// SampleConfig will create an example configuration and write it to the specified [path] func SampleConfig() { // Generate Sample configuration @@ -99,7 +99,7 @@ func SampleConfig() { fmt.Print(string(b)) } -//WriteConfig will write the current configuration to a specified [path] +// WriteConfig will write the current configuration to a specified [path] func (c *Config) WriteConfig(path string) error { f, err := os.Create(path) if err != nil { diff --git a/pkg/service/prom.go b/pkg/service/prom.go index 2b316691..6e41287a 100644 --- a/pkg/service/prom.go +++ b/pkg/service/prom.go @@ -2,7 +2,7 @@ package service import "github.com/prometheus/client_golang/prometheus" -//PrometheusCollector - required for statistics // TODO - improve monitoring +// PrometheusCollector - required for statistics // TODO - improve monitoring func (sm *Manager) PrometheusCollector() []prometheus.Collector { return []prometheus.Collector{sm.countServiceWatchEvent} } diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index 25d47066..f0d6c085 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -54,50 +54,59 @@ func (c *DHCPClient) Stop() { } // Start state-transition process of dhcp client -// -------- ------- +// +// -------- ------- +// // | | +-------------------------->| |<-------------------+ // | INIT- | | +-------------------->| INIT | | // | REBOOT |DHCPNAK/ +---------->| |<---+ | // | |Restart| | ------- | | -// -------- | DHCPNAK/ | | | -// | Discard offer | -/Send DHCPDISCOVER | +// +// -------- | DHCPNAK/ | | | +// | Discard offer | -/Send DHCPDISCOVER | +// // -/Send DHCPREQUEST | | | -// | | | DHCPACK v | | -// ----------- | (not accept.)/ ----------- | | +// +// | | | DHCPACK v | | +// ----------- | (not accept.)/ ----------- | | +// // | | | Send DHCPDECLINE | | | // | REBOOTING | | | | SELECTING |<----+ | // | | | / | | |DHCPOFFER/ | -// ----------- | / ----------- | |Collect | -// | | / | | | replies | +// +// ----------- | / ----------- | |Collect | +// | | / | | | replies | +// // DHCPACK/ | / +----------------+ +-------+ | // Record lease, set| | v Select offer/ | // timers T1, T2 ------------ send DHCPREQUEST | | -// | +----->| | DHCPNAK, Lease expired/ | -// | | | REQUESTING | Halt network | -// DHCPOFFER/ | | | | -// Discard ------------ | | -// | | | | ----------- | -// | +--------+ DHCPACK/ | | | -// | Record lease, set -----| REBINDING | | -// | timers T1, T2 / | | | -// | | DHCPACK/ ----------- | -// | v Record lease, set ^ | -// +----------------> ------- /timers T1,T2 | | -// +----->| |<---+ | | -// | | BOUND |<---+ | | -// DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/ -// DHCPNAK/Discard ------- | Broadcast Halt network -// | | | | DHCPREQUEST | -// +-------+ | DHCPACK/ | | -// T1 expires/ Record lease, set | | -// Send DHCPREQUEST timers T1, T2 | | -// to leasing server | | | -// | ---------- | | -// | | |------------+ | -// +->| RENEWING | | -// | |----------------------------+ -// ---------- -// Figure: State-transition diagram for DHCP clients +// +// | +----->| | DHCPNAK, Lease expired/ | +// | | | REQUESTING | Halt network | +// DHCPOFFER/ | | | | +// Discard ------------ | | +// | | | | ----------- | +// | +--------+ DHCPACK/ | | | +// | Record lease, set -----| REBINDING | | +// | timers T1, T2 / | | | +// | | DHCPACK/ ----------- | +// | v Record lease, set ^ | +// +----------------> ------- /timers T1,T2 | | +// +----->| |<---+ | | +// | | BOUND |<---+ | | +// DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/ +// DHCPNAK/Discard ------- | Broadcast Halt network +// | | | | DHCPREQUEST | +// +-------+ | DHCPACK/ | | +// T1 expires/ Record lease, set | | +// Send DHCPREQUEST timers T1, T2 | | +// to leasing server | | | +// | ---------- | | +// | | |------------+ | +// +->| RENEWING | | +// | |----------------------------+ +// ---------- +// Figure: State-transition diagram for DHCP clients func (c *DHCPClient) Start() { backoff := backoff.Backoff{ Factor: 2, @@ -205,14 +214,14 @@ func (c *DHCPClient) release() error { return unicast.Release(c.lease) } -// -------------------------------------------------------- -// | |INIT-REBOOT | RENEWING |REBINDING | -// -------------------------------------------------------- -// |broad/unicast |broadcast | unicast |broadcast | -// |server-ip |MUST NOT | MUST NOT |MUST NOT | -// |requested-ip |MUST | MUST NOT |MUST NOT | -// |ciaddr |zero | IP address |IP address| -// -------------------------------------------------------- +// -------------------------------------------------------- +// | |INIT-REBOOT | RENEWING |REBINDING | +// -------------------------------------------------------- +// |broad/unicast |broadcast | unicast |broadcast | +// |server-ip |MUST NOT | MUST NOT |MUST NOT | +// |requested-ip |MUST | MUST NOT |MUST NOT | +// |ciaddr |zero | IP address |IP address| +// -------------------------------------------------------- func (c *DHCPClient) initReboot() (*nclient4.Lease, error) { broadcast, err := nclient4.New(c.iface.Name) if err != nil { From 8eaafee0f5a569a39d83ffc72a8a24bec341cafe Mon Sep 17 00:00:00 2001 From: Chris Privitere <23177737+cprivitere@users.noreply.github.com> Date: Mon, 29 Aug 2022 15:30:10 -0500 Subject: [PATCH 272/542] Add ReadHeaderTimeout Resolves golanglint-ci complaint Signed-off-by: Chris Privitere <23177737+cprivitere@users.noreply.github.com> --- cmd/kube-vip.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 58b26fe7..3abf0723 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -351,8 +351,9 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC mux.Handle("/metrics", promhttp.Handler()) srv := &http.Server{ - Addr: config.Addr, - Handler: mux, + Addr: config.Addr, + Handler: mux, + ReadHeaderTimeout: 2 * time.Second, } go func() { From 8a0eb9a6615465284954c9ee60b326ff1b90374e Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 30 Aug 2022 14:26:29 +0100 Subject: [PATCH 273/542] Update anchore-syft.yml --- .github/workflows/anchore-syft.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index eb47e1df..0eef1236 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -38,3 +38,9 @@ jobs: image: "localbuild/testimage:latest" artifact-name: image.spdx.json dependency-snapshot: true + license-check: + runs-on: ubuntu-latest + name: License Check + steps: + - uses: actions/checkout@v3 + - uses: yusufpapurcu/go-license-checker@v0.5 From bb4c815c5c218c8096e14b63e246c4a929cffcaa Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 30 Aug 2022 14:28:10 +0100 Subject: [PATCH 274/542] Update anchore-syft.yml --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 0eef1236..a6758d32 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -43,4 +43,4 @@ jobs: name: License Check steps: - uses: actions/checkout@v3 - - uses: yusufpapurcu/go-license-checker@v0.5 + - uses: yusufpapurcu/go-license-checker@v0.9 From ba20ae172562c1d7c81e2d7e045d8c1d06751502 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 6 Sep 2022 15:18:48 +0100 Subject: [PATCH 275/542] This adds the initial code for egress (SNAT). --- go.mod | 2 + go.sum | 5 + main.go | 67 +++++++++++++ pkg/egress/egress.go | 175 ++++++++++++++++++++++++++++++++++ pkg/manager/service_egress.go | 90 +++++++++++++++++ pkg/manager/watch_services.go | 20 +++- pkg/vip/egress.go | 130 +++++++++++++++++++++++++ 7 files changed, 488 insertions(+), 1 deletion(-) create mode 100644 pkg/egress/egress.go create mode 100644 pkg/manager/service_egress.go create mode 100644 pkg/vip/egress.go diff --git a/go.mod b/go.mod index 3e8d517a..cc8d0006 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-2022042 require ( github.com/cloudflare/ipvs v0.8.0 github.com/davecgh/go-spew v1.1.1 + github.com/florianl/go-conntrack v0.3.0 github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.2 github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd @@ -38,6 +39,7 @@ require ( github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/coreos/go-iptables v0.6.0 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect diff --git a/go.sum b/go.sum index 2a4c1148..d4fd5242 100644 --- a/go.sum +++ b/go.sum @@ -108,6 +108,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -146,6 +148,8 @@ github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:Pjfxu github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/florianl/go-conntrack v0.3.0 h1:DUY84Mce+/lE9dJi2EWvGYacQtX2X96J9aVWV99l8UE= +github.com/florianl/go-conntrack v0.3.0/go.mod h1:Q+Um4J/nWUXSbnyzQRMOP4eweSeEQ2G8sfCO5gMz6Pw= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= @@ -803,6 +807,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go index 9e20cb03..9137ea6a 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,73 @@ var Version string var Build string func main() { + + // i, err := vip.CreateIptablesClient() + // if err != nil { + // panic(err) + // } + // if os.Getenv("CREATE") != "" { + + // b, err := i.CheckMangleChain(vip.MangleChainName) + // if err != nil { + // panic(err) + // } + // if b == false { + // err = i.CreateMangleChain(vip.MangleChainName) + // if err != nil { + // panic(err) + // } + // } + // // Add entries to our mangle chaing + // err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.0.0.0/16") + // if err != nil { + // panic(err) + // } + // err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.96.0.0/12") + // if err != nil { + // panic(err) + // } + // err = i.AppendReturnRulesForMarking(vip.MangleChainName, "10.0.77.36/32") + // if err != nil { + // panic(err) + // } + // err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName) + // if err != nil { + // panic(err) + // } + // err = i.InsertSourceNat("192.168.0.221", "10.0.77.36") + // if err != nil { + // panic(err) + // } + + // err = i.DumpChain(vip.MangleChainName) + // vip.ExampleNfct_Dump() + // if err == nil { + // return + // } + // } + // if os.Getenv("DELETE") != "" { + // err = i.DeleteManglePrerouting(vip.MangleChainName) + // if err != nil { + // panic(err) + // } + // err = i.DeleteMangleChain(vip.MangleChainName) + // if err != nil { + // panic(err) + // } + // err = i.DeleteSourceNat("10.0.77.36", "192.168.0.221") + // if err != nil { + // panic(err) + // } + // //err = i.DumpChain(vip.MangleChainName) + // vip.ExampleNfct_Dump() + // if err == nil { + // return + // } + // if err != nil { + // panic(err) + // } + // } cmd.Release.Version = Version cmd.Release.Build = Build cmd.Execute() diff --git a/pkg/egress/egress.go b/pkg/egress/egress.go new file mode 100644 index 00000000..95c52c3d --- /dev/null +++ b/pkg/egress/egress.go @@ -0,0 +1,175 @@ +package egress + +//https://github.com/Trojan295/kube-router/commit/d48fd0a275249eb44e272d7f936ac91610c987cd#diff-3b65e4098d69eede2c4abfedc10116dda8fa05b9e308c18c1cb62b1a3fc8c119 + +import ( + "bufio" + "bytes" + "fmt" + "net" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "github.com/coreos/go-iptables/iptables" + log "github.com/sirupsen/logrus" +) + +const ( + preroutingMarkChain = "CHINCHILLA-PREROUTING-MARK" + postroutingSnatChain = "CHINCHILLA-POSTROUTING-SNAT" + + egressIPAnnotation = "egressSNAT.IPAddress" + egressFixedPortsAnnotation = "egressSNAT.FixedPorts" + + routingTableFile = "/opt/rt_tables" +) + +func iptablesChainExists(table string, chain string, it *iptables.IPTables) (bool, error) { + chains, err := it.ListChains(table) + if err != nil { + return false, err + } + + for _, c := range chains { + if c == chain { + return true, nil + } + } + return false, nil +} + +func iptablesEnsureChain(table string, chain string, it *iptables.IPTables) error { + if exists, err := iptablesChainExists(table, chain, it); err != nil { + return nil + } else if !exists { + return it.NewChain(table, chain) + } + return nil +} + +func iptablesEnsureRuleAtPosition(table, chain string, position int, it *iptables.IPTables, rule ...string) error { + if exists, err := it.Exists(table, chain, rule...); err != nil { + return err + } else if exists { + if err2 := it.Delete(table, chain, rule...); err2 != nil { + return err2 + } + } + + return it.Insert(table, chain, position, rule...) +} + +type routeTable struct { + ID int + Name string + Subnet net.IPNet +} + +func FindRouteTableForIP(ip net.IP, rts []routeTable) *routeTable { + for _, rt := range rts { + if rt.Subnet.Contains(ip) { + return &rt + } + } + return nil +} + +func EnsureRouteRule(rt *routeTable) error { + fwmark := fmt.Sprintf("%x/0xff", rt.ID) + + out, err := exec.Command("ip", "rule", "show", "fwmark", fwmark, "table", rt.Name).Output() + if err != nil { + return err + } + + if string(out) != "" { + return nil + } + + _, err = exec.Command("ip", "rule", "add", "fwmark", fwmark, "table", rt.Name).Output() + if err != nil { + return err + } + + return nil +} + +func GetRouteTables() ([]routeTable, error) { + tables := make([]routeTable, 0) + + fp, err := os.Open(routingTableFile) + if err != nil { + return tables, err + } + defer fp.Close() + + r := bufio.NewScanner(fp) + for r.Scan() { + line := strings.Trim(r.Text(), " ") + if strings.HasPrefix(line, "#") { + continue + } + + cols := strings.Fields(line) + name := cols[1] + ID, err := strconv.Atoi(cols[0]) + if err != nil { + log.Error("invalid route table entry in /etc/iproute2/rt_tables") + continue + } + + rt := routeTable{ + ID: ID, + Name: name, + } + + if rt.ID == 0 { + continue + } + + cidr, err := getCIDRForRouteTable(&rt) + if err != nil || cidr == nil { + continue + } + + rt.Subnet = *cidr + + tables = append(tables, rt) + } + + return tables, nil +} + +func getCIDRForRouteTable(rt *routeTable) (*net.IPNet, error) { + tableID := fmt.Sprintf("%d", rt.ID) + + out, err := exec.Command("ip", "rule", "show", "table", tableID).Output() + if err != nil { + return nil, err + } + + r := bufio.NewScanner(bytes.NewBuffer(out)) + + var cidr *net.IPNet = nil + + pattern := fmt.Sprintf(`\d+:.+from (.+) lookup.+`) + re := regexp.MustCompile(pattern) + + for r.Scan() { + line := r.Text() + result := re.FindStringSubmatch(line) + + if len(result) > 0 { + _, cidr, _ = net.ParseCIDR(result[1]) + if cidr != nil { + break + } + } + } + + return cidr, nil +} + diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go new file mode 100644 index 00000000..3fde353b --- /dev/null +++ b/pkg/manager/service_egress.go @@ -0,0 +1,90 @@ +package manager + +import ( + "context" + "fmt" + "strings" + + "github.com/kube-vip/kube-vip/pkg/vip" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (sm *Manager) configureEgress(vipIP, podIP string) error { + serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() + if err != nil { + serviceCIDR = "10.96.0.0/12" + podCIDR = "10.0.0.0/16" + } + i, err := vip.CreateIptablesClient() + if err != nil { + return fmt.Errorf("error Creating iptables client [%s]", err) + } + // Check if the kube-vip mangle chain exists, if not create it + exists, err := i.CheckMangleChain(vip.MangleChainName) + if err != nil { + return fmt.Errorf("error checking for existence of mangle chain [%s], error [%s]", vip.MangleChainName, err) + } + if !exists { + err = i.CreateMangleChain(vip.MangleChainName) + if err != nil { + return fmt.Errorf("error creating mangle chain [%s], error [%s]", vip.MangleChainName, err) + } + } + err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, podCIDR) + if err != nil { + panic(err) + } + err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, serviceCIDR) + if err != nil { + panic(err) + } + err = i.AppendReturnRulesForMarking(vip.MangleChainName, podIP+"/32") + if err != nil { + panic(err) + } + + err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName) + if err != nil { + panic(err) + } + err = i.InsertSourceNat(vipIP, podIP) + if err != nil { + panic(err) + } + + _ = i.DumpChain(vip.MangleChainName) + err = vip.DeleteExistingSessions(podIP) + if err != nil { + return err + } + + return nil +} + +func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) { + pod, err := sm.clientSet.CoreV1().Pods("kube-system").Get(context.TODO(), "kube-controller-manager", v1.GetOptions{}) + if err != nil { + return "", "", err + } + for flags := range pod.Spec.Containers[0].Command { + if strings.Contains(pod.Spec.Containers[0].Command[flags], "--cluster-cidr=") { + podCIDR = strings.ReplaceAll(pod.Spec.Containers[0].Command[flags], "--cluster-cidr=", "") + } + if strings.Contains(pod.Spec.Containers[0].Command[flags], "--service-cluster-ip-range=") { + serviceCIDR = strings.ReplaceAll(pod.Spec.Containers[0].Command[flags], "--service-cluster-ip-range=", "") + } + } + if podCIDR == "" || serviceCIDR == "" { + err = fmt.Errorf("unable to fully determine cluster CIDR configurations") + } + + return +} + +func TeardownEgress(podIP, serviceIP string) error { + i, err := vip.CreateIptablesClient() + if err != nil { + return fmt.Errorf("error Creating iptables client [%s]", err) + } + return i.DeleteSourceNat(podIP, serviceIP) +} diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index c2608d36..6c0a89d7 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -44,6 +44,9 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context ch := rw.ResultChan() //defer rw.Stop() + // Used for tracking an active endpoint / pod + var podIP string + for event := range ch { sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) @@ -70,7 +73,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { ep, err := sm.clientSet.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) if err != nil { - return fmt.Errorf("unable to parse service endpoints [%v]", err) + log.Errorf("unable to parse service endpoints [%v]", err) } exists := false for subset := range ep.Subsets { @@ -79,6 +82,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if ep.Subsets[subset].Addresses[address].NodeName != nil { if id == *ep.Subsets[subset].Addresses[address].NodeName { exists = true + podIP = ep.Subsets[subset].Addresses[address].IP } } } @@ -87,6 +91,14 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Warnf("loadBalancer has External Traffic Policy: Local, no local pods found") break } + // Check if we want to rewrite egress + if svc.Annotations["kube-vip.io/egress"] == "true" && exists { + // We will need to modify the iptables rules + err = sm.configureEgress(svc.Spec.LoadBalancerIP, podIP) + if err != nil { + log.Errorf("Error configuring egress for loadbalancer [%s]", err) + } + } } // Check the loadBalancer class @@ -143,6 +155,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } + // We will need to tear down the egress + if svc.Annotations["kube-vip.io/egress"] == "true" { + log.Infof("service [%s] has an egress re-write enabled", svc.Name) + TeardownEgress(podIP, svc.Spec.LoadBalancerIP) + } + err = sm.deleteService(string(svc.UID)) if err != nil { log.Error(err) diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go new file mode 100644 index 00000000..d2d1fc8f --- /dev/null +++ b/pkg/vip/egress.go @@ -0,0 +1,130 @@ +package vip + +import ( + "fmt" + + iptables "github.com/coreos/go-iptables/iptables" + log "github.com/sirupsen/logrus" + + ct "github.com/florianl/go-conntrack" +) + +//Notes: https://github.com/cloudnativelabs/kube-router/issues/434 + +// This file contains all of the functions related to changing SNAT for a +// pod so that it appears to be coming from a VIP. + +// 1. Create a new chain in the mangle table +// 2. Ignore (or RETURN) packets going to a service or other pod address +// 3. Mark packets coming from a pod +// 4. Add a rule in the mangle chain PREROUTING to jump to the new chain created above +// 5. Mark packets going through this host (not originating) (might not be needed) +// 6. Perform source nating on marked packets + +// Create new iptables client +// Test to find out what exists before hand + +const MangleChainName = "KUBE-VIP-EGRESS" +const iptableCommentSuffiv = "KUBE-VIP-" + +// DEBUG +const podSubnet = "10.0.0.0/26" +const serviceSubnet = "10.96.0.0/12" + +// Create new table + +func (e *Egress) DumpChain(name string) error { + log.Infof("Dumping chain [%s]", name) + c, err := e.ipTablesClient.List("mangle", name) + if err != nil { + return err + } + for x := range c { + log.Infof("Rule -> %s", c[x]) + } + return nil +} + +type Egress struct { + ipTablesClient *iptables.IPTables +} + +func CreateIptablesClient() (*Egress, error) { + e := new(Egress) + var err error + e.ipTablesClient, err = iptables.New() + return e, err +} + +func (e *Egress) CheckMangleChain(name string) (bool, error) { + + log.Infof("[Egress] Cheching for Chain [%s]", name) + return e.ipTablesClient.ChainExists("mangle", name) + +} + +func (e *Egress) DeleteMangleChain(name string) error { + return e.ipTablesClient.ClearAndDeleteChain("mangle", name) +} + +func (e *Egress) DeleteManglePrerouting(name string) error { + return e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name) +} + +func (e *Egress) DeleteSourceNat(podIP, vip string) error { + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) +} + +func (e *Egress) CreateMangleChain(name string) error { + + log.Infof("[Egress] Creating Chain [%s]", 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) + return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN") +} + +func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error { + log.Infof("[Egress] Marking packets on network [%s]", subnet) + return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") +} + +func (e *Egress) InsertMangeTableIntoPrerouting(name string) error { + log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", name) + return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name) +} + +func (e *Egress) InsertSourceNat(vip, podIP string) error { + log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", "name") + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) +} + +func DeleteExistingSessions(podIP string) error { + nfct, err := ct.Open(&ct.Config{}) + if err != nil { + fmt.Println("could not create nfct:", err) + return nil + } + defer nfct.Close() + sessions, err := nfct.Dump(ct.Conntrack, ct.IPv4) + if err != nil { + fmt.Println("could not dump sessions:", err) + return nil + } + + for _, session := range sessions { + if session.Origin.Dst.String() == podIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { + fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) + + err = nfct.Delete(ct.Conntrack, ct.IPv4, session) + if err != nil { + fmt.Println("could not delete sessions:", err) + } + + } + } + return nil +} From db1ed82510bfb88a3083d69d5ababfebfbf176c9 Mon Sep 17 00:00:00 2001 From: Alexandre Vilain Date: Wed, 7 Sep 2022 21:02:24 +0200 Subject: [PATCH 276/542] fix --table flag should add vip_routingtable env var not vip_wireguard Signed-off-by: Alexandre Vilain --- pkg/kubevip/config_generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index b0e58ad6..97df0ac1 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -210,7 +210,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod if c.EnableRoutingTable { routingtable := []corev1.EnvVar{ { - Name: vipWireguard, + Name: vipRoutingTable, Value: strconv.FormatBool(c.EnableRoutingTable), }, } From 98f5c73919c97a445d609d5416f23b7d02c257a4 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Tue, 13 Sep 2022 09:09:20 +0100 Subject: [PATCH 277/542] Fixes to iptables and endpoint watcher --- pkg/egress/egress.go | 175 -------------------- pkg/manager/services.go | 3 +- pkg/manager/servicesLeader.go | 17 +- pkg/manager/watch_services.go | 294 ++++++++++++++++++++++++++-------- pkg/vip/egress.go | 28 +++- 5 files changed, 262 insertions(+), 255 deletions(-) delete mode 100644 pkg/egress/egress.go diff --git a/pkg/egress/egress.go b/pkg/egress/egress.go deleted file mode 100644 index 95c52c3d..00000000 --- a/pkg/egress/egress.go +++ /dev/null @@ -1,175 +0,0 @@ -package egress - -//https://github.com/Trojan295/kube-router/commit/d48fd0a275249eb44e272d7f936ac91610c987cd#diff-3b65e4098d69eede2c4abfedc10116dda8fa05b9e308c18c1cb62b1a3fc8c119 - -import ( - "bufio" - "bytes" - "fmt" - "net" - "os" - "os/exec" - "regexp" - "strconv" - "strings" - - "github.com/coreos/go-iptables/iptables" - log "github.com/sirupsen/logrus" -) - -const ( - preroutingMarkChain = "CHINCHILLA-PREROUTING-MARK" - postroutingSnatChain = "CHINCHILLA-POSTROUTING-SNAT" - - egressIPAnnotation = "egressSNAT.IPAddress" - egressFixedPortsAnnotation = "egressSNAT.FixedPorts" - - routingTableFile = "/opt/rt_tables" -) - -func iptablesChainExists(table string, chain string, it *iptables.IPTables) (bool, error) { - chains, err := it.ListChains(table) - if err != nil { - return false, err - } - - for _, c := range chains { - if c == chain { - return true, nil - } - } - return false, nil -} - -func iptablesEnsureChain(table string, chain string, it *iptables.IPTables) error { - if exists, err := iptablesChainExists(table, chain, it); err != nil { - return nil - } else if !exists { - return it.NewChain(table, chain) - } - return nil -} - -func iptablesEnsureRuleAtPosition(table, chain string, position int, it *iptables.IPTables, rule ...string) error { - if exists, err := it.Exists(table, chain, rule...); err != nil { - return err - } else if exists { - if err2 := it.Delete(table, chain, rule...); err2 != nil { - return err2 - } - } - - return it.Insert(table, chain, position, rule...) -} - -type routeTable struct { - ID int - Name string - Subnet net.IPNet -} - -func FindRouteTableForIP(ip net.IP, rts []routeTable) *routeTable { - for _, rt := range rts { - if rt.Subnet.Contains(ip) { - return &rt - } - } - return nil -} - -func EnsureRouteRule(rt *routeTable) error { - fwmark := fmt.Sprintf("%x/0xff", rt.ID) - - out, err := exec.Command("ip", "rule", "show", "fwmark", fwmark, "table", rt.Name).Output() - if err != nil { - return err - } - - if string(out) != "" { - return nil - } - - _, err = exec.Command("ip", "rule", "add", "fwmark", fwmark, "table", rt.Name).Output() - if err != nil { - return err - } - - return nil -} - -func GetRouteTables() ([]routeTable, error) { - tables := make([]routeTable, 0) - - fp, err := os.Open(routingTableFile) - if err != nil { - return tables, err - } - defer fp.Close() - - r := bufio.NewScanner(fp) - for r.Scan() { - line := strings.Trim(r.Text(), " ") - if strings.HasPrefix(line, "#") { - continue - } - - cols := strings.Fields(line) - name := cols[1] - ID, err := strconv.Atoi(cols[0]) - if err != nil { - log.Error("invalid route table entry in /etc/iproute2/rt_tables") - continue - } - - rt := routeTable{ - ID: ID, - Name: name, - } - - if rt.ID == 0 { - continue - } - - cidr, err := getCIDRForRouteTable(&rt) - if err != nil || cidr == nil { - continue - } - - rt.Subnet = *cidr - - tables = append(tables, rt) - } - - return tables, nil -} - -func getCIDRForRouteTable(rt *routeTable) (*net.IPNet, error) { - tableID := fmt.Sprintf("%d", rt.ID) - - out, err := exec.Command("ip", "rule", "show", "table", tableID).Output() - if err != nil { - return nil, err - } - - r := bufio.NewScanner(bytes.NewBuffer(out)) - - var cidr *net.IPNet = nil - - pattern := fmt.Sprintf(`\d+:.+from (.+) lookup.+`) - re := regexp.MustCompile(pattern) - - for r.Scan() { - line := r.Text() - result := re.FindStringSubmatch(line) - - if len(result) > 0 { - _, cidr, _ = net.ParseCIDR(result[1]) - if cidr != nil { - break - } - } - } - - return cidr, nil -} - diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9e98882b..78873d5c 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -91,7 +91,6 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy // This instance wasn't found, we need to add it to the manager if !foundInstance && newServiceAddress != "" { - log.Infof("add the service [%s/%s] with external address [%s]", service.Namespace, service.Name, newServiceAddress) if err := sm.addService(service); err != nil { return err } @@ -106,7 +105,7 @@ func (sm *Manager) addService(service *v1.Service) error { return err } - log.Infof("new VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) + log.Infof("adding VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 0c3f0d56..3ccda761 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -14,15 +14,10 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" ) -// activeService keeps track of services that already have a leaderElection in place -var activeService map[string]bool - // The startServicesWatchForLeaderElection function will start a services watcher, the func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) error { - activeService = make(map[string]bool) - - err := sm.servicesWatcher(ctx, sm.startServicesLeaderElection) + err := sm.servicesWatcher(ctx, sm.StartServicesLeaderElection) if err != nil { return err } @@ -37,11 +32,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 { - // No leader election is necessary - if activeService[string(service.UID)] { - return nil - } +func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error { id, err := os.Hostname() if err != nil { @@ -80,8 +71,8 @@ func (sm *Manager) startServicesLeaderElection(ctx context.Context, service *v1. OnStartedLeading: func(ctx context.Context) { // we run this in background as it's blocking go func() { - log.Infof("adding the service [%s/%s] with external address [%s]", service.Namespace, service.Name, service.Spec.LoadBalancerIP) - if err := sm.addService(service); err != nil { + //sm.syncServices(ctx, service, wg) + if err := sm.syncServices(ctx, service, wg); err != nil { log.Errorln(err) } }() diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 6c0a89d7..2c4f35ba 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -12,16 +12,27 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" ) -// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly +// activeServiceLoadBalancer keeps track of services that already have a leaderElection in place +var activeServiceLoadBalancer map[string]context.Context + +// activeService keeps track of services that already have a leaderElection in place +var activeService map[string]bool + +// This function handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { // Watch function var wg sync.WaitGroup + // Set up the activeServiceLoadBalancer + activeServiceLoadBalancer = make(map[string]context.Context) + activeService = make(map[string]bool) + id, err := os.Hostname() if err != nil { return err @@ -69,38 +80,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - // We need to see if the pod is local to this kube-vip pod - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - ep, err := sm.clientSet.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - if err != nil { - log.Errorf("unable to parse service endpoints [%v]", err) - } - exists := false - for subset := range ep.Subsets { - for address := range ep.Subsets[subset].Addresses { - // Check the node is populated - if ep.Subsets[subset].Addresses[address].NodeName != nil { - if id == *ep.Subsets[subset].Addresses[address].NodeName { - exists = true - podIP = ep.Subsets[subset].Addresses[address].IP - } - } - } - } - if !exists { - log.Warnf("loadBalancer has External Traffic Policy: Local, no local pods found") - break - } - // Check if we want to rewrite egress - if svc.Annotations["kube-vip.io/egress"] == "true" && exists { - // We will need to modify the iptables rules - err = sm.configureEgress(svc.Spec.LoadBalancerIP, podIP) - if err != nil { - log.Errorf("Error configuring egress for loadbalancer [%s]", err) - } - } - } - // Check the loadBalancer class if svc.Spec.LoadBalancerClass != nil { // if this isn't nil then it has been configured, check if it the kube-vip loadBalancer class @@ -120,53 +99,110 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } + // // We need to see if the pod is local to this kube-vip pod + // if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // ep, err := sm.clientSet.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) + // if err != nil { + // log.Errorf("unable to parse service endpoints [%v]", err) + // } + // exists := false + // for subset := range ep.Subsets { + // for address := range ep.Subsets[subset].Addresses { + // // Check the node is populated + // if ep.Subsets[subset].Addresses[address].NodeName != nil { + // if id == *ep.Subsets[subset].Addresses[address].NodeName { + // exists = true + // podIP = ep.Subsets[subset].Addresses[address].IP + // } + // } + // } + // } + // if !exists { + // log.Warnf("loadBalancer [%s] has External Traffic Policy: Local, no local pods found", svc.Name) + // break + // } + // // Check if we want to rewrite egress + // if svc.Annotations["kube-vip.io/egress"] == "true" && exists { + // // We will need to modify the iptables rules + // err = sm.configureEgress(svc.Spec.LoadBalancerIP, podIP) + // if err != nil { + // log.Errorf("Error configuring egress for loadbalancer [%s]", err) + // } + // } + // } + log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) - wg.Add(1) - // Background the services election - if sm.config.EnableServicesElection { - go func() { - err = serviceFunc(ctx, svc, &wg) + + // Scenarios: + // 1. + + if !activeService[string(svc.UID)] { + wg.Add(1) + activeServiceLoadBalancer[string(svc.UID)] = context.TODO() + // Background the services election + if sm.config.EnableServicesElection { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Start an endpoint watcher + // background the endpoint watcher + go func() { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Add Endpoint watcher + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Errorf("%v", err) + } + wg.Wait() + } + }() + } else { + go func() { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Wait() + }() + } + } else { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) if err != nil { log.Error(err) } wg.Wait() - }() - } else { - err = serviceFunc(ctx, svc, &wg) - if err != nil { - log.Error(err) } - wg.Wait() } case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { return fmt.Errorf("unable to parse Kubernetes services from API watcher") } + if activeService[string(svc.UID)] { + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } - // We only care about LoadBalancer services - if svc.Spec.Type != v1.ServiceTypeLoadBalancer { - break - } + // We can ignore this service + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } - // We can ignore this service - if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) - break - } + // We will need to tear down the egress + if svc.Annotations["kube-vip.io/egress"] == "true" { + log.Infof("service [%s] has an egress re-write enabled", svc.Name) + TeardownEgress(podIP, svc.Spec.LoadBalancerIP) + } - // We will need to tear down the egress - if svc.Annotations["kube-vip.io/egress"] == "true" { - log.Infof("service [%s] has an egress re-write enabled", svc.Name) - TeardownEgress(podIP, svc.Spec.LoadBalancerIP) - } + err = sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) + } - err = sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } - log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) + activeServiceLoadBalancer[string(svc.UID)].Done() + log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) + } case watch.Bookmark: // Un-used case watch.Error: @@ -188,3 +224,135 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } + +func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + watchContect := context.TODO() + + opts := metav1.ListOptions{ + FieldSelector: fields.OneTermEqualSelector("metadata.name", service.Name).String(), + } + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Endpoints(service.Namespace).Watch(watchContect, opts) + }, + }) + if err != nil { + return fmt.Errorf("error creating endpoint watcher: %s", err.Error()) + } + + ch := rw.ResultChan() + //defer rw.Stop() + var localEndpoint string + var endpointExists bool + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + var endPointStillExists bool + ep, ok := event.Object.(*v1.Endpoints) + if !ok { + return fmt.Errorf("unable to parse Kubernetes services from API watcher") + } + for subset := range ep.Subsets { + for address := range ep.Subsets[subset].Addresses { + + // Check the node is populated + if ep.Subsets[subset].Addresses[address].NodeName != nil { + if id == *ep.Subsets[subset].Addresses[address].NodeName { + + log.Info("local endpoint discovered") + localEndpoint = ep.Subsets[subset].Addresses[address].IP + endpointExists = true + endPointStillExists = true + //podIP = ep.Subsets[subset].Addresses[address].IP + go func() { + err = sm.StartServicesLeaderElection(ctx, service, wg) + if err != nil { + log.Error(err) + } + wg.Wait() + }() + + if service.Annotations["kube-vip.io/egress"] == "true" { + log.Info("stuff happening") + + // We will need to modify the iptables rules + err = sm.configureEgress(service.Spec.LoadBalancerIP, ep.Subsets[subset].Addresses[address].IP) + if err != nil { + log.Errorf("Error configuring egress for loadbalancer [%s]", err) + } + } + } + } + } + } + // Does the endpoint still exist + if endpointExists && !endPointStillExists { + + } + case watch.Deleted: + watchContect.Done() + return nil + } + } + + if !exists { + ctx.Done() + } + + return nil +} + +func (sm updateServiceEndpointAnnotation(service *v1.Service) error { + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(i.ServiceNamespace).Get(context.TODO(), i.ServiceName, metav1.GetOptions{}) + if err != nil { + return err + } + + id, err := os.Hostname() + if err != nil { + return err + } + + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + + // If we're using ARP then we can only broadcast the VIP from one place, add an annotation to the service + if sm.config.EnableARP { + // Add the current host + currentServiceCopy.Annotations[vipHost] = id + } + if i.dhcpInterfaceHwaddr != "" || i.dhcpInterfaceIP != "" { + currentServiceCopy.Annotations[hwAddrKey] = i.dhcpInterfaceHwaddr + currentServiceCopy.Annotations[requestedIP] = i.dhcpInterfaceIP + } + + updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", i.ServiceName, err) + return err + } + + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} + _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) + return err + } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + return retryErr + } + return nil + return nil +} diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index d2d1fc8f..5c714409 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -84,21 +84,45 @@ func (e *Egress) CreateMangleChain(name string) error { } func (e *Egress) AppendReturnRulesForDestinationSubnet(name, subnet string) error { log.Infof("[Egress] Adding jump for subnet [%s] to RETURN to previous chain/rules", subnet) - return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN") + exists, _ := e.ipTablesClient.Exists("mangle", name, "-d", subnet, "-j", "RETURN") + if !exists { + return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN") + } + return nil } func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error { log.Infof("[Egress] Marking packets on network [%s]", subnet) - return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") + exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") + if !exists { + return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") + } + return nil } func (e *Egress) InsertMangeTableIntoPrerouting(name string) error { log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", name) + if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name); err != nil { + return err + } else if exists { + if err2 := e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name); err2 != nil { + return err2 + } + } + return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name) } func (e *Egress) InsertSourceNat(vip, podIP string) error { log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", "name") + if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip); err != nil { + return err + } else if exists { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip); err2 != nil { + return err2 + } + } + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) } From 023ddbafd187f29c526e15d7e8e3a1b33716b04b Mon Sep 17 00:00:00 2001 From: daper Date: Tue, 13 Sep 2022 16:06:57 +0200 Subject: [PATCH 278/542] Add random MAC address generation for DHCP Signed-off-by: David Peralta --- pkg/manager/instance.go | 7 +++++++ pkg/vip/util.go | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index c3b84e61..0b98f66e 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -139,8 +139,14 @@ func (i *Instance) startDHCP() (chan string, error) { hwaddr, err := net.ParseMAC(i.dhcpInterfaceHwaddr) if i.dhcpInterfaceHwaddr != "" && err != nil { return nil, err + } else if hwaddr == nil { + hwaddr, err = net.ParseMAC(vip.GenerateMac()) + if err != nil { + return nil, err + } } + log.Infof("New interface [%s] mac is %s", interfaceName, hwaddr) mac := &netlink.Macvlan{ LinkAttrs: netlink.LinkAttrs{ Name: interfaceName, @@ -159,6 +165,7 @@ func (i *Instance) startDHCP() (chan string, error) { if err != nil { return nil, fmt.Errorf("could not bring up interface [%s] : %v", interfaceName, err) } + iface, err = net.InterfaceByName(interfaceName) if err != nil { return nil, fmt.Errorf("error finding new DHCP interface by name [%v]", err) diff --git a/pkg/vip/util.go b/pkg/vip/util.go index 48a2050d..8608c5f1 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -2,6 +2,7 @@ package vip import ( "context" + "crypto/rand" "fmt" "net" "strings" @@ -107,3 +108,21 @@ func MonitorDefaultInterface(ctx context.Context, defaultIF *net.Interface) erro } } } + +func GenerateMac() (mac string) { + buf := make([]byte, 3) + _, err := rand.Read(buf) + if err != nil { + return + } + + /** + * The first 3 bytes need to match a real manufacturer + * you can refer to the following lists for examples: + * - https://gist.github.com/aallan/b4bb86db86079509e6159810ae9bd3e4 + * - 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) + return mac +} From 6620440c9527a51f7b3a451f76bf95522975e11b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Thu, 15 Sep 2022 13:41:42 +0100 Subject: [PATCH 279/542] Final first push at Egress --- pkg/manager/instance.go | 18 ++- pkg/manager/service_egress.go | 14 ++- pkg/manager/services.go | 23 ++-- pkg/manager/servicesLeader.go | 4 +- pkg/manager/watch_endpoints.go | 197 +++++++++++++++++++++++++++++++++ pkg/manager/watch_services.go | 148 ++----------------------- pkg/vip/egress.go | 13 ++- 7 files changed, 255 insertions(+), 162 deletions(-) create mode 100644 pkg/manager/watch_endpoints.go diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index c3b84e61..8dc5ae8e 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -38,8 +38,7 @@ type Instance struct { UID string Type string - ServiceName string - ServiceNamespace string + serviceSnapshot *v1.Service } func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) { @@ -69,10 +68,9 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) // Create new service instance := &Instance{ - UID: instanceUID, - Vip: instanceAddress, - ServiceName: service.Name, - ServiceNamespace: service.Namespace, + UID: instanceUID, + Vip: instanceAddress, + serviceSnapshot: service, } if len(service.Spec.Ports) > 0 { instance.Type = string(service.Spec.Ports[0].Protocol) @@ -85,7 +83,7 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) // Generate Load Balancer config newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", instance.ServiceName), + Name: fmt.Sprintf("%s-load-balancer", service.Name), Port: int(instance.Port), Type: instance.Type, BindToVip: true, @@ -105,7 +103,7 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) select { case <-time.After(dhcpTimeout): return nil, fmt.Errorf("timeout to request the IP from DHCP server for service %s/%s", - instance.ServiceNamespace, instance.ServiceName) + instance.serviceSnapshot.Namespace, instance.serviceSnapshot.Name) case ip := <-ipChan: instance.vipConfig.VIP = ip instance.dhcpInterfaceIP = ip @@ -114,7 +112,7 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) c, err := cluster.InitCluster(instance.vipConfig, false) if err != nil { - log.Errorf("Failed to add Service %s/%s", instance.ServiceNamespace, instance.ServiceName) + log.Errorf("Failed to add Service %s/%s", service.Namespace, service.Name) return nil, err } instance.cluster = c @@ -177,7 +175,7 @@ func (i *Instance) startDHCP() (chan string, error) { client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP, func(lease *nclient4.Lease) { ipChan <- lease.ACK.YourIPAddr.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", i.vipConfig.VIP, i.ServiceNamespace, i.ServiceName) + log.Infof("DHCP VIP [%s] for [%s/%s] ", i.vipConfig.VIP, i.serviceSnapshot.Namespace, i.serviceSnapshot.Name) }) go client.Start() diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 3fde353b..e411c5ea 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -52,8 +52,8 @@ func (sm *Manager) configureEgress(vipIP, podIP string) error { panic(err) } - _ = i.DumpChain(vip.MangleChainName) - err = vip.DeleteExistingSessions(podIP) + //_ = i.DumpChain(vip.MangleChainName) + err = i.DeleteExistingSessions(vipIP, podIP) if err != nil { return err } @@ -86,5 +86,13 @@ func TeardownEgress(podIP, serviceIP string) error { if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } - return i.DeleteSourceNat(podIP, serviceIP) + err = i.DeleteSourceNat(podIP, serviceIP) + if err != nil { + return fmt.Errorf("error changing iptables rules for egress [%s]", err) + } + err = i.DeleteExistingSessions(serviceIP, podIP) + if err != nil { + return fmt.Errorf("error changing iptables rules for egress [%s]", err) + } + return nil } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 78873d5c..691ed700 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -105,7 +105,7 @@ func (sm *Manager) addService(service *v1.Service) error { return err } - log.Infof("adding VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceNamespace, newService.ServiceName) + log.Infof("adding VIP [%s] for [%s/%s] ", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) @@ -120,7 +120,16 @@ func (sm *Manager) addService(service *v1.Service) error { } return err } - + if service.Annotations["kube-vip.io/egress"] == "true" { + if service.Annotations["kube-vip.io/active-endpoint"] != "" { + // We will need to modify the iptables rules + err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations["kube-vip.io/active-endpoint"]) + if err != nil { + log.Errorf("Error configuring egress for loadbalancer [%s]", err) + } + } + sm.updateServiceEndpointAnnotation(service.Annotations["kube-vip.io/active-endpoint"], service) + } log.Debugf("[COMPLETE] Service Sync") return nil @@ -130,8 +139,8 @@ func (sm *Manager) upnpMap(s *Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() if sm.upnp != nil { - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) - if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { + log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.serviceSnapshot.Name) + if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { log.Infof("Service should be accessible externally on port [%d]", s.Port) } else { sm.upnp.Reclaim() @@ -144,7 +153,7 @@ func (sm *Manager) updateStatus(i *Instance) error { retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { // Retrieve the latest version of Deployment before attempting update // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(i.ServiceNamespace).Get(context.TODO(), i.ServiceName, metav1.GetOptions{}) + currentService, err := sm.clientSet.CoreV1().Services(i.serviceSnapshot.Namespace).Get(context.TODO(), i.serviceSnapshot.Name, metav1.GetOptions{}) if err != nil { return err } @@ -171,14 +180,14 @@ func (sm *Manager) updateStatus(i *Instance) error { updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", i.ServiceName, err) + log.Errorf("Error updating Service Spec [%s] : %v", i.serviceSnapshot.Name, err) return err } updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) if err != nil { - log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) + log.Errorf("Error updating Service %s/%s Status: %v", i.serviceSnapshot.Namespace, i.serviceSnapshot.Name, err) return err } return nil diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 3ccda761..f60be0e1 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -53,7 +53,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. Identity: id, }, } - activeService[string(service.UID)] = true + //activeService[string(service.UID)] = true // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -84,7 +84,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. log.Errorln(err) } // Mark this service is inactive - activeService[string(service.UID)] = false + //activeService[string(service.UID)] = false }, OnNewLeader: func(identity string) { // we're notified when new leader elected diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go new file mode 100644 index 00000000..81075d6e --- /dev/null +++ b/pkg/manager/watch_endpoints.go @@ -0,0 +1,197 @@ +package manager + +import ( + "context" + "fmt" + "sync" + + 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" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" + watchtools "k8s.io/client-go/tools/watch" + "k8s.io/client-go/util/retry" +) + +func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { + log.Infof("Watching endpoints for service [%s]", service.Name) + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + var cancel context.CancelFunc + var endpointContext context.Context + endpointContext, cancel = context.WithCancel(context.Background()) + + defer cancel() + + opts := metav1.ListOptions{ + FieldSelector: fields.OneTermEqualSelector("metadata.name", service.Name).String(), + } + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.CoreV1().Endpoints(service.Namespace).Watch(ctx, opts) + }, + }) + if err != nil { + cancel() + return fmt.Errorf("error creating endpoint watcher: %s", err.Error()) + } + + ch := rw.ResultChan() + //defer rw.Stop() + var lastKnownGoodEndpoint string + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + ep, ok := event.Object.(*v1.Endpoints) + if !ok { + cancel() + return fmt.Errorf("unable to parse Kubernetes services from API watcher") + } + var localendpoints []string + for subset := range ep.Subsets { + for address := range ep.Subsets[subset].Addresses { + + // Check the node is populated + if ep.Subsets[subset].Addresses[address].NodeName != nil { + if id == *ep.Subsets[subset].Addresses[address].NodeName { + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + // if localEndpoint == ep.Subsets[subset].Addresses[address].IP { + // endPointStillExists = true + // break + // } + // } else { + // localEndpoint = ep.Subsets[subset].Addresses[address].IP + // log.Infof("local endpoint [%s] discovered") + // //err = sm.updateServiceEndpointAnnotation(ep.Subsets[subset].Addresses[address].IP, service) + // // if err != nil { + // // //log.Error(err) + // // watchContect.Done() + // // return err + // // } + // endpointExists = true + // endPointStillExists = true + // //podIP = ep.Subsets[subset].Addresses[address].IP + // go func() { + // err = sm.StartServicesLeaderElection(ctx, service, wg) + // if err != nil { + // log.Error(err) + // } + // wg.Wait() + // }() + + // if service.Annotations["kube-vip.io/egress"] == "true" { + // log.Info("stuff happening") + + // // We will need to modify the iptables rules + // err = sm.configureEgress(service.Spec.LoadBalancerIP, ep.Subsets[subset].Addresses[address].IP) + // if err != nil { + // log.Errorf("Error configuring egress for loadbalancer [%s]", err) + // } + // } + + } + } + } + } + log.Infof("[%d], endpoints, last known good [%s]", len(localendpoints), lastKnownGoodEndpoint) + // Check how many local endpoints exist (should ideally be 1) + stillExists := false + if len(localendpoints) != 0 { + if lastKnownGoodEndpoint == "" { + lastKnownGoodEndpoint = localendpoints[0] + // Create new context + endpointContext, cancel = context.WithCancel(context.Background()) + wg.Add(1) + if service.Annotations["kube-vip.io/egress"] == "true" { + service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint + } + go func() { + err = sm.StartServicesLeaderElection(endpointContext, service, wg) + if err != nil { + log.Error(err) + } + wg.Wait() + }() + + } else { + // check out previous endpoint exists + for x := range localendpoints { + if localendpoints[x] == lastKnownGoodEndpoint { + stillExists = true + } + } + if stillExists { + break + } else { + cancel() + //rw.Stop() + } + } + } else { + if lastKnownGoodEndpoint != "" { + lastKnownGoodEndpoint = "" + cancel() + //rw.Stop() + //return nil + } + } + + case watch.Deleted: + cancel() + rw.Stop() + case watch.Error: + errObject := apierrors.FromObject(event.Object) + statusErr, _ := errObject.(*apierrors.StatusError) + log.Errorf("%v", statusErr) + } + } + log.Infof("Stopping watching endpoints for [%s]", service.Name) + return nil +} + +func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1.Service) error { + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + + // id, err := os.Hostname() + // if err != nil { + // return err + // } + + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + + currentServiceCopy.Annotations["kube-vip.io/active-endpoint"] = endpoint + + _, err = sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", currentServiceCopy.Name, err) + return err + } + + // updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} + // _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) + // if err != nil { + // log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) + // return err + // } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + return retryErr + } + return nil +} diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 2c4f35ba..6dcf7fc0 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -12,7 +12,6 @@ import ( v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" @@ -56,8 +55,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context //defer rw.Stop() // Used for tracking an active endpoint / pod - var podIP string - for event := range ch { sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) @@ -170,6 +167,8 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } wg.Wait() } + activeService[string(svc.UID)] = true + } case watch.Deleted: svc, ok := event.Object.(*v1.Service) @@ -190,8 +189,14 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // We will need to tear down the egress if svc.Annotations["kube-vip.io/egress"] == "true" { - log.Infof("service [%s] has an egress re-write enabled", svc.Name) - TeardownEgress(podIP, svc.Spec.LoadBalancerIP) + if svc.Annotations["kube-vip.io/active-endpoint"] != "" { + + log.Infof("service [%s] has an egress re-write enabled", svc.Name) + err = TeardownEgress(svc.Annotations["kube-vip.io/active-endpoint"], svc.Spec.LoadBalancerIP) + if err != nil { + log.Errorf("%v", err) + } + } } err = sm.deleteService(string(svc.UID)) @@ -200,6 +205,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } activeServiceLoadBalancer[string(svc.UID)].Done() + activeService[string(svc.UID)] = false log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) } @@ -224,135 +230,3 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } - -func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - watchContect := context.TODO() - - opts := metav1.ListOptions{ - FieldSelector: fields.OneTermEqualSelector("metadata.name", service.Name).String(), - } - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Endpoints(service.Namespace).Watch(watchContect, opts) - }, - }) - if err != nil { - return fmt.Errorf("error creating endpoint watcher: %s", err.Error()) - } - - ch := rw.ResultChan() - //defer rw.Stop() - var localEndpoint string - var endpointExists bool - for event := range ch { - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - var endPointStillExists bool - ep, ok := event.Object.(*v1.Endpoints) - if !ok { - return fmt.Errorf("unable to parse Kubernetes services from API watcher") - } - for subset := range ep.Subsets { - for address := range ep.Subsets[subset].Addresses { - - // Check the node is populated - if ep.Subsets[subset].Addresses[address].NodeName != nil { - if id == *ep.Subsets[subset].Addresses[address].NodeName { - - log.Info("local endpoint discovered") - localEndpoint = ep.Subsets[subset].Addresses[address].IP - endpointExists = true - endPointStillExists = true - //podIP = ep.Subsets[subset].Addresses[address].IP - go func() { - err = sm.StartServicesLeaderElection(ctx, service, wg) - if err != nil { - log.Error(err) - } - wg.Wait() - }() - - if service.Annotations["kube-vip.io/egress"] == "true" { - log.Info("stuff happening") - - // We will need to modify the iptables rules - err = sm.configureEgress(service.Spec.LoadBalancerIP, ep.Subsets[subset].Addresses[address].IP) - if err != nil { - log.Errorf("Error configuring egress for loadbalancer [%s]", err) - } - } - } - } - } - } - // Does the endpoint still exist - if endpointExists && !endPointStillExists { - - } - case watch.Deleted: - watchContect.Done() - return nil - } - } - - if !exists { - ctx.Done() - } - - return nil -} - -func (sm updateServiceEndpointAnnotation(service *v1.Service) error { - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(i.ServiceNamespace).Get(context.TODO(), i.ServiceName, metav1.GetOptions{}) - if err != nil { - return err - } - - id, err := os.Hostname() - if err != nil { - return err - } - - currentServiceCopy := currentService.DeepCopy() - if currentServiceCopy.Annotations == nil { - currentServiceCopy.Annotations = make(map[string]string) - } - - // If we're using ARP then we can only broadcast the VIP from one place, add an annotation to the service - if sm.config.EnableARP { - // Add the current host - currentServiceCopy.Annotations[vipHost] = id - } - if i.dhcpInterfaceHwaddr != "" || i.dhcpInterfaceIP != "" { - currentServiceCopy.Annotations[hwAddrKey] = i.dhcpInterfaceHwaddr - currentServiceCopy.Annotations[requestedIP] = i.dhcpInterfaceIP - } - - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", i.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - log.Errorf("Failed to set Services: %v", retryErr) - return retryErr - } - return nil - return nil -} diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 5c714409..31050f6b 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -72,6 +72,11 @@ func (e *Egress) DeleteManglePrerouting(name string) error { } func (e *Egress) DeleteSourceNat(podIP, vip string) error { + exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) + + if !exists { + return fmt.Errorf("Unable to find source Nat rule for [%s]", podIP) + } return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) } @@ -126,7 +131,8 @@ func (e *Egress) InsertSourceNat(vip, podIP string) error { return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) } -func DeleteExistingSessions(podIP string) error { +func (e *Egress) DeleteExistingSessions(vip, podIP string) error { + nfct, err := ct.Open(&ct.Config{}) if err != nil { fmt.Println("could not create nfct:", err) @@ -140,8 +146,9 @@ func DeleteExistingSessions(podIP string) error { } for _, session := range sessions { - if session.Origin.Dst.String() == podIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { - fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) + //fmt.Printf("Looking for [%s] found [%s]\n", podIP, session.Origin.Dst.String()) + if session.Origin.Src.String() == podIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { + //fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) err = nfct.Delete(ct.Conntrack, ct.IPv4, session) if err != nil { From 36f42300c4e8024e9f819a73212ec1c23d1b522b Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 28 Sep 2022 11:44:02 +0100 Subject: [PATCH 280/542] Adds stability and warnings to egress --- Dockerfile_iptables | 19 ++++++++ Makefile | 5 ++ main.go | 66 -------------------------- pkg/manager/manager.go | 4 ++ pkg/manager/service_egress.go | 28 +++++++++++ pkg/manager/services.go | 31 +++++++++++- pkg/manager/servicesLeader.go | 13 +++-- pkg/manager/watch_endpoints.go | 36 +------------- pkg/manager/watch_services.go | 86 ++++++++++------------------------ 9 files changed, 121 insertions(+), 167 deletions(-) create mode 100644 Dockerfile_iptables diff --git a/Dockerfile_iptables b/Dockerfile_iptables new file mode 100644 index 00000000..1d56af99 --- /dev/null +++ b/Dockerfile_iptables @@ -0,0 +1,19 @@ +# syntax=docker/dockerfile:experimental + +FROM golang:1.18.0-alpine3.15 as dev +RUN apk add --no-cache git make +RUN adduser -D appuser +COPY . /src/ +WORKDIR /src + +ENV GO111MODULE=on +RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ + --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=linux make build + +FROM alpine:3.16.2 +# Add Certificates into the image, for anything that does API calls +RUN apk add --no-cache iptables +# Add kube-vip binary +COPY --from=dev /src/kube-vip / +ENTRYPOINT ["/kube-vip"] \ No newline at end of file diff --git a/Makefile b/Makefile index d6da9866..4d3d0ea0 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,11 @@ dockerx86Dev: @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):dev . @echo New single x86 Architecture Docker image created +dockerx86Iptables: + @-rm ./kube-vip + @docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --push -t $(REPOSITORY)/$(TARGET):dev . + @echo New single x86 Architecture Docker image created + dockerx86: @-rm ./kube-vip @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . diff --git a/main.go b/main.go index 9137ea6a..2d66f9cd 100644 --- a/main.go +++ b/main.go @@ -12,72 +12,6 @@ var Build string func main() { - // i, err := vip.CreateIptablesClient() - // if err != nil { - // panic(err) - // } - // if os.Getenv("CREATE") != "" { - - // b, err := i.CheckMangleChain(vip.MangleChainName) - // if err != nil { - // panic(err) - // } - // if b == false { - // err = i.CreateMangleChain(vip.MangleChainName) - // if err != nil { - // panic(err) - // } - // } - // // Add entries to our mangle chaing - // err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.0.0.0/16") - // if err != nil { - // panic(err) - // } - // err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, "10.96.0.0/12") - // if err != nil { - // panic(err) - // } - // err = i.AppendReturnRulesForMarking(vip.MangleChainName, "10.0.77.36/32") - // if err != nil { - // panic(err) - // } - // err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName) - // if err != nil { - // panic(err) - // } - // err = i.InsertSourceNat("192.168.0.221", "10.0.77.36") - // if err != nil { - // panic(err) - // } - - // err = i.DumpChain(vip.MangleChainName) - // vip.ExampleNfct_Dump() - // if err == nil { - // return - // } - // } - // if os.Getenv("DELETE") != "" { - // err = i.DeleteManglePrerouting(vip.MangleChainName) - // if err != nil { - // panic(err) - // } - // err = i.DeleteMangleChain(vip.MangleChainName) - // if err != nil { - // panic(err) - // } - // err = i.DeleteSourceNat("10.0.77.36", "192.168.0.221") - // if err != nil { - // panic(err) - // } - // //err = i.DumpChain(vip.MangleChainName) - // vip.ExampleNfct_Dump() - // if err == nil { - // return - // } - // if err != nil { - // panic(err) - // } - // } cmd.Release.Version = Version cmd.Release.Build = Build cmd.Execute() diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 99bae91b..af420393 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -7,6 +7,7 @@ import ( "os/signal" "path/filepath" "strings" + "sync" "syscall" "github.com/kube-vip/kube-vip/pkg/k8s" @@ -45,6 +46,9 @@ type Manager struct { // This is a prometheus counter used to count the number of events received // from the service watcher countServiceWatchEvent *prometheus.CounterVec + + // This mutex is to protect calls from various goroutines + mutex sync.Mutex } // New will create a new managing object diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index e411c5ea..7e69c0f8 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -1,14 +1,42 @@ package manager import ( + "bufio" "context" "fmt" + "os" "strings" "github.com/kube-vip/kube-vip/pkg/vip" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func (sm *Manager) iptablesCheck() error { + file, err := os.Open("/proc/modules") + if err != nil { + return err + } + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + var nat, filter, mangle bool + for scanner.Scan() { + line := strings.Fields(scanner.Text()) + switch line[0] { + case "iptable_filter": + filter = true + case "iptable_nat": + nat = true + case "iptable_mangle": + mangle = true + } + } + + if !filter || !nat || !mangle { + return fmt.Errorf("missing iptables modules -> nat [%t] -> filter [%t] mangle -> [%t]", nat, filter, mangle) + } + return nil +} + func (sm *Manager) configureEgress(vipIP, podIP string) error { serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() if err != nil { diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 691ed700..c98e6b28 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -21,9 +21,14 @@ const ( ) func (sm *Manager) deleteService(uid string) error { + //pretect multiple calls + sm.mutex.Lock() + defer sm.mutex.Unlock() + var updatedInstances []*Instance found := false for x := range sm.serviceInstances { + log.Debugf("Looking for [%s], found [%s]", uid, sm.serviceInstances[x].UID) // Add the running services to the new array if sm.serviceInstances[x].UID != uid { updatedInstances = append(updatedInstances, sm.serviceInstances[x]) @@ -48,11 +53,25 @@ func (sm *Manager) deleteService(uid string) error { err := sm.bgpServer.DelHost(cidrVip) return err } + + // We will need to tear down the egress + if sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/egress"] == "true" { + if sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"] != "" { + + log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) + err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP) + if err != nil { + log.Errorf("%v", err) + } + } + } } } // If we've been through all services and not found the correct one then error if !found { - return fmt.Errorf("unable to find/stop service [%s]", uid) + // TODO: - fix UX + //return fmt.Errorf("unable to find/stop service [%s]", uid) + return nil } // Update the service array @@ -123,12 +142,20 @@ func (sm *Manager) addService(service *v1.Service) error { if service.Annotations["kube-vip.io/egress"] == "true" { if service.Annotations["kube-vip.io/active-endpoint"] != "" { // We will need to modify the iptables rules + err = sm.iptablesCheck() + if err != nil { + log.Errorf("Error configuring egress for loadbalancer [%s]", err) + } err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations["kube-vip.io/active-endpoint"]) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) + } else { + err = sm.updateServiceEndpointAnnotation(service.Annotations["kube-vip.io/active-endpoint"], service) + if err != nil { + log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) + } } } - sm.updateServiceEndpointAnnotation(service.Annotations["kube-vip.io/active-endpoint"], service) } log.Debugf("[COMPLETE] Service Sync") diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index f60be0e1..734347f2 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -69,6 +69,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. RetryPeriod: 5 * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { + // we run this in background as it's blocking go func() { //sm.syncServices(ctx, service, wg) @@ -76,15 +77,19 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. log.Errorln(err) } }() + activeService[string(service.UID)] = true + }, OnStoppedLeading: func() { // we can do cleanup here - log.Infof("leader lost: %s", id) - if err := sm.deleteService(string(service.UID)); err != nil { - log.Errorln(err) + log.Infof("services leader lost: %s", id) + if activeService[string(service.UID)] { + if err := sm.deleteService(string(service.UID)); err != nil { + log.Errorln(err) + } } // Mark this service is inactive - //activeService[string(service.UID)] = false + activeService[string(service.UID)] = false }, OnNewLeader: func(identity string) { // we're notified when new leader elected diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 81075d6e..76c19778 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -59,40 +59,6 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser if ep.Subsets[subset].Addresses[address].NodeName != nil { if id == *ep.Subsets[subset].Addresses[address].NodeName { localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - // if localEndpoint == ep.Subsets[subset].Addresses[address].IP { - // endPointStillExists = true - // break - // } - // } else { - // localEndpoint = ep.Subsets[subset].Addresses[address].IP - // log.Infof("local endpoint [%s] discovered") - // //err = sm.updateServiceEndpointAnnotation(ep.Subsets[subset].Addresses[address].IP, service) - // // if err != nil { - // // //log.Error(err) - // // watchContect.Done() - // // return err - // // } - // endpointExists = true - // endPointStillExists = true - // //podIP = ep.Subsets[subset].Addresses[address].IP - // go func() { - // err = sm.StartServicesLeaderElection(ctx, service, wg) - // if err != nil { - // log.Error(err) - // } - // wg.Wait() - // }() - - // if service.Annotations["kube-vip.io/egress"] == "true" { - // log.Info("stuff happening") - - // // We will need to modify the iptables rules - // err = sm.configureEgress(service.Spec.LoadBalancerIP, ep.Subsets[subset].Addresses[address].IP) - // if err != nil { - // log.Errorf("Error configuring egress for loadbalancer [%s]", err) - // } - // } - } } } @@ -104,7 +70,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser if lastKnownGoodEndpoint == "" { lastKnownGoodEndpoint = localendpoints[0] // Create new context - endpointContext, cancel = context.WithCancel(context.Background()) + endpointContext, cancel = context.WithCancel(context.Background()) //nolint wg.Add(1) if service.Annotations["kube-vip.io/egress"] == "true" { service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 6dcf7fc0..d40e9579 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -23,6 +23,9 @@ var activeServiceLoadBalancer map[string]context.Context // activeService keeps track of services that already have a leaderElection in place var activeService map[string]bool +// watchedService keeps track of services that are already being watched +var watchedService map[string]bool + // This function handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { // Watch function @@ -31,6 +34,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Set up the activeServiceLoadBalancer activeServiceLoadBalancer = make(map[string]context.Context) activeService = make(map[string]bool) + watchedService = make(map[string]bool) id, err := os.Hostname() if err != nil { @@ -96,38 +100,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - // // We need to see if the pod is local to this kube-vip pod - // if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // ep, err := sm.clientSet.CoreV1().Endpoints(svc.Namespace).Get(ctx, svc.Name, metav1.GetOptions{}) - // if err != nil { - // log.Errorf("unable to parse service endpoints [%v]", err) - // } - // exists := false - // for subset := range ep.Subsets { - // for address := range ep.Subsets[subset].Addresses { - // // Check the node is populated - // if ep.Subsets[subset].Addresses[address].NodeName != nil { - // if id == *ep.Subsets[subset].Addresses[address].NodeName { - // exists = true - // podIP = ep.Subsets[subset].Addresses[address].IP - // } - // } - // } - // } - // if !exists { - // log.Warnf("loadBalancer [%s] has External Traffic Policy: Local, no local pods found", svc.Name) - // break - // } - // // Check if we want to rewrite egress - // if svc.Annotations["kube-vip.io/egress"] == "true" && exists { - // // We will need to modify the iptables rules - // err = sm.configureEgress(svc.Spec.LoadBalancerIP, podIP) - // if err != nil { - // log.Errorf("Error configuring egress for loadbalancer [%s]", err) - // } - // } - // } - log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) // Scenarios: @@ -139,18 +111,23 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Background the services election if sm.config.EnableServicesElection { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Start an endpoint watcher - // background the endpoint watcher - go func() { - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Add Endpoint watcher - err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) - if err != nil { - log.Errorf("%v", err) + // Start an endpoint watcher if we're not watching it alredy + if !watchedService[string(svc.UID)] { + watchedService[string(svc.UID)] = true + + // background the endpoint watcher + go func() { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Add Endpoint watcher + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Errorf("%v", err) + } + watchedService[string(svc.UID)] = false + wg.Wait() } - wg.Wait() - } - }() + }() + } } else { go func() { err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) @@ -167,7 +144,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } wg.Wait() } - activeService[string(svc.UID)] = true } case watch.Deleted: @@ -186,26 +162,16 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) break } - - // We will need to tear down the egress - if svc.Annotations["kube-vip.io/egress"] == "true" { - if svc.Annotations["kube-vip.io/active-endpoint"] != "" { - - log.Infof("service [%s] has an egress re-write enabled", svc.Name) - err = TeardownEgress(svc.Annotations["kube-vip.io/active-endpoint"], svc.Spec.LoadBalancerIP) - if err != nil { - log.Errorf("%v", err) - } + // If this is a watched service then and additional leaderElection will handle stopping + if !watchedService[string(svc.UID)] { + err := sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) } } - - err = sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } - activeServiceLoadBalancer[string(svc.UID)].Done() activeService[string(svc.UID)] = false + watchedService[string(svc.UID)] = false log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) } From e6ae07f404f487ad9f9e549d72a03b884084846e Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 28 Sep 2022 11:54:38 +0100 Subject: [PATCH 281/542] Create mainiptables.yaml --- .github/workflows/mainiptables.yaml | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/mainiptables.yaml diff --git a/.github/workflows/mainiptables.yaml b/.github/workflows/mainiptables.yaml new file mode 100644 index 00000000..9a8c7795 --- /dev/null +++ b/.github/workflows/mainiptables.yaml @@ -0,0 +1,36 @@ +name: Build and publish main image regularly + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Github Packages + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push main branch + id: docker_build + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile_iptables + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x + push: ${{ github.event_name != 'pull_request' }} + tags: >- + plndr/kube-vip-iptables:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }} + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} From 00cd131e2e5a26c63a85fff5aac03406055538c1 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 28 Sep 2022 11:55:16 +0100 Subject: [PATCH 282/542] Update mainiptables.yaml --- .github/workflows/mainiptables.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mainiptables.yaml b/.github/workflows/mainiptables.yaml index 9a8c7795..01477fe5 100644 --- a/.github/workflows/mainiptables.yaml +++ b/.github/workflows/mainiptables.yaml @@ -1,4 +1,4 @@ -name: Build and publish main image regularly +name: Build and publish main iptables based image regularly jobs: docker: From 88af581958b24bb6ccbbdf015d7cb6cc81456cec Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 28 Sep 2022 11:56:39 +0100 Subject: [PATCH 283/542] Update mainiptables.yaml --- .github/workflows/mainiptables.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/mainiptables.yaml b/.github/workflows/mainiptables.yaml index 01477fe5..4898eaaf 100644 --- a/.github/workflows/mainiptables.yaml +++ b/.github/workflows/mainiptables.yaml @@ -1,5 +1,9 @@ name: Build and publish main iptables based image regularly +on: + schedule: + - cron: '25 0 * * *' + jobs: docker: runs-on: ubuntu-latest From c41df19a3614de54fb970223c7c598b3ab2fe6f8 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 28 Sep 2022 12:01:22 +0100 Subject: [PATCH 284/542] Update mainiptables.yaml --- .github/workflows/mainiptables.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mainiptables.yaml b/.github/workflows/mainiptables.yaml index 4898eaaf..240f130b 100644 --- a/.github/workflows/mainiptables.yaml +++ b/.github/workflows/mainiptables.yaml @@ -3,6 +3,7 @@ name: Build and publish main iptables based image regularly on: schedule: - cron: '25 0 * * *' + workflow_dispatch: jobs: docker: From 651038ada2f8fefb601f8999763ca3afb21da421 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 10 Oct 2022 13:48:54 +0100 Subject: [PATCH 285/542] Adds ports and namespaces --- cmd/kube-vip.go | 2 +- pkg/cluster/cluster.go | 3 - pkg/kubevip/config_environment.go | 6 ++ pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_generator.go | 20 ++++++- pkg/kubevip/config_types.go | 3 + pkg/manager/manager_arp.go | 1 + pkg/manager/service_egress.go | 96 ++++++++++++++++++++++++------- pkg/manager/services.go | 4 +- pkg/manager/servicesLeader.go | 2 +- pkg/manager/watch_endpoints.go | 8 +-- pkg/manager/watch_services.go | 9 ++- pkg/vip/egress.go | 34 ++++++++--- 13 files changed, 149 insertions(+), 42 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 3abf0723..88eff7e6 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -110,7 +110,7 @@ func init() { kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.BGPPeers, "bgppeers", []string{}, "Comma separated BGP Peer, format: address:as:password:multihop") kubeVipCmd.PersistentFlags().StringVar(&initConfig.Annotations, "annotations", "", "Set Node annotations prefix for parsing") - // Control plane specific flags + // Namespace for kube-vip kubeVipCmd.PersistentFlags().StringVarP(&initConfig.Namespace, "namespace", "n", "kube-system", "The namespace for the configmap defined within the cluster") // Manage logging diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 00b786a6..90198821 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -3,7 +3,6 @@ package cluster import ( "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" - log "github.com/sirupsen/logrus" ) // Cluster - The Cluster object manages the state of the cluster for a particular node @@ -57,6 +56,4 @@ func (cluster *Cluster) Stop() { // Wait until the completed channel is closed, signallign all shutdown tasks completed <-cluster.completed - - log.Info("Stopped") } diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 7de77676..69219881 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -158,6 +158,12 @@ func ParseEnvironment(c *Config) error { } c.LoadBalancerClassOnly = b } + + // Find the namespace that the control pane should use (for leaderElection lock) + env = os.Getenv(svcNamespace) + if env != "" { + c.ServiceNamespace = env + } } // Find vip address cidr range diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index e53668ed..7b661e9a 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -109,6 +109,9 @@ const ( //svcEnable enables the Kubernetes service feature svcEnable = "svc_enable" + //svcNamespace defines the namespace the service pods will run in + svcNamespace = "svc_namespace" + //svcElection enables election per Kubernetes service svcElection = "svc_election" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 97df0ac1..28c39e73 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -14,6 +14,14 @@ import ( func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" + // Determine where the pods should be living (for multi-tenancy) + var namespace string + if c.ServiceNamespace != "" { + namespace = c.ServiceNamespace + } else { + namespace = metav1.NamespaceSystem + } + // build environment variables newEnvironment := []corev1.EnvVar{ { @@ -340,7 +348,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, ObjectMeta: metav1.ObjectMeta{ Name: "kube-vip", - Namespace: "kube-system", + Namespace: namespace, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ @@ -428,6 +436,14 @@ func GeneratePodManifestFromConfig(c *Config, imageVersion string, inCluster boo // GenerateDaemonsetManifestFromConfig will take a kube-vip config and generate a manifest func GenerateDaemonsetManifestFromConfig(c *Config, imageVersion string, inCluster, taint bool) string { + // Determine where the pod should be deployed + var namespace string + if c.ServiceNamespace != "" { + namespace = c.ServiceNamespace + } else { + namespace = metav1.NamespaceSystem + } + podSpec := generatePodSpec(c, imageVersion, inCluster).Spec newManifest := &appv1.DaemonSet{ TypeMeta: metav1.TypeMeta{ @@ -436,7 +452,7 @@ func GenerateDaemonsetManifestFromConfig(c *Config, imageVersion string, inClust }, ObjectMeta: metav1.ObjectMeta{ Name: "kube-vip-ds", - Namespace: "kube-system", + Namespace: namespace, Labels: map[string]string{ "app.kubernetes.io/name": "kube-vip-ds", "app.kubernetes.io/version": imageVersion, diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 8c644e4b..31ba4ef7 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -60,6 +60,9 @@ type Config struct { // Namespace will define which namespace the control plane pods will run in Namespace string `yaml:"namespace"` + // Namespace will define which namespace the control plane pods will run in + ServiceNamespace string `yaml:"serviceNamespace"` + // use DDNS to allocate IP when Address is set to a DNS Name DDNS bool `yaml:"ddns"` diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 2a591f9b..33b560be 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -69,6 +69,7 @@ func (sm *Manager) startARP() error { ns = sm.config.Namespace } else { + ns, err = returnNameSpace() if err != nil { log.Warnf("unable to auto-detect namespace, dropping to [%s]", sm.config.Namespace) diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 7e69c0f8..f1fa7528 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -11,6 +11,10 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// DEBUG +const podCIDR = "10.0.0.0/26" +const serviceCIDR = "10.96.0.0/12" + func (sm *Manager) iptablesCheck() error { file, err := os.Open("/proc/modules") if err != nil { @@ -37,12 +41,12 @@ func (sm *Manager) iptablesCheck() error { return nil } -func (sm *Manager) configureEgress(vipIP, podIP string) error { - serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() - if err != nil { - serviceCIDR = "10.96.0.0/12" - podCIDR = "10.0.0.0/16" - } +func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts string) error { + // serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() + // if err != nil { + // serviceCIDR = "10.96.0.0/12" + // podCIDR = "10.0.0.0/16" + // } i, err := vip.CreateIptablesClient() if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) @@ -60,28 +64,54 @@ func (sm *Manager) configureEgress(vipIP, podIP string) error { } err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, podCIDR) if err != nil { - panic(err) + return fmt.Errorf("error adding rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, serviceCIDR) if err != nil { - panic(err) + return fmt.Errorf("error adding rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } err = i.AppendReturnRulesForMarking(vip.MangleChainName, podIP+"/32") if err != nil { - panic(err) + return fmt.Errorf("error adding marking rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } err = i.InsertMangeTableIntoPrerouting(vip.MangleChainName) if err != nil { - panic(err) - } - err = i.InsertSourceNat(vipIP, podIP) - if err != nil { - panic(err) + return fmt.Errorf("error adding prerouting mangle chain [%s], error [%s]", vip.MangleChainName, err) } + if destinationPorts != "" { + + fixedPorts := strings.Split(destinationPorts, ",") + + for _, fixedPort := range fixedPorts { + var proto, port string + + data := strings.Split(fixedPort, ":") + if len(data) == 0 { + continue + } else if len(data) == 1 { + proto = "tcp" + port = data[0] + } else { + proto = data[0] + port = data[1] + } + + err = i.InsertSourceNatForDestinationPort(vipIP, podIP, port, proto) + if err != nil { + return fmt.Errorf("error adding snat rules to nat chain [%s], error [%s]", vip.MangleChainName, err) + } + + } + } else { + err = i.InsertSourceNat(vipIP, podIP) + if err != nil { + return fmt.Errorf("error adding snat rules to nat chain [%s], error [%s]", vip.MangleChainName, err) + } + } //_ = i.DumpChain(vip.MangleChainName) - err = i.DeleteExistingSessions(vipIP, podIP) + err = i.DeleteExistingSessions(podIP) if err != nil { return err } @@ -109,16 +139,42 @@ func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) return } -func TeardownEgress(podIP, serviceIP string) error { +func TeardownEgress(podIP, vipIP, destinationPorts string) error { i, err := vip.CreateIptablesClient() if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } - err = i.DeleteSourceNat(podIP, serviceIP) - if err != nil { - return fmt.Errorf("error changing iptables rules for egress [%s]", err) + if destinationPorts != "" { + + fixedPorts := strings.Split(destinationPorts, ",") + + for _, fixedPort := range fixedPorts { + var proto, port string + + data := strings.Split(fixedPort, ":") + if len(data) == 0 { + continue + } else if len(data) == 1 { + proto = "tcp" + port = data[0] + } else { + proto = data[0] + port = data[1] + } + + err = i.DeleteSourceNatForDestinationPort(podIP, vipIP, port, proto) + if err != nil { + return fmt.Errorf("error changing iptables rules for egress [%s]", err) + } + + } + } else { + err = i.DeleteSourceNat(podIP, vipIP) + if err != nil { + return fmt.Errorf("error changing iptables rules for egress [%s]", err) + } } - err = i.DeleteExistingSessions(serviceIP, podIP) + err = i.DeleteExistingSessions(podIP) if err != nil { return fmt.Errorf("error changing iptables rules for egress [%s]", err) } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index c98e6b28..3063643e 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -59,7 +59,7 @@ func (sm *Manager) deleteService(uid string) error { if sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"] != "" { log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP) + err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/egress-destination-ports"]) if err != nil { log.Errorf("%v", err) } @@ -146,7 +146,7 @@ func (sm *Manager) addService(service *v1.Service) error { if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations["kube-vip.io/active-endpoint"]) + err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations["kube-vip.io/active-endpoint"], service.Annotations["kube-vip.io/egress-destination-ports"], service.Annotations["kube-vip.io/egress-source-ports"]) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 734347f2..47982171 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -40,7 +40,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. } serviceLease := fmt.Sprintf("kubevip-%s", service.Name) - log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", service.Namespace, serviceLease, id) + log.Infof("beginning leadership for service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, 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{ diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 76c19778..57c135eb 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -17,7 +17,7 @@ import ( ) func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { - log.Infof("Watching endpoints for service [%s]", service.Name) + log.Infof("watching endpoints for service [%s]", service.Name) // Use a restartable watcher, as this should help in the event of etcd or timeout issues var cancel context.CancelFunc var endpointContext context.Context @@ -63,7 +63,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } } - log.Infof("[%d], endpoints, last known good [%s]", len(localendpoints), lastKnownGoodEndpoint) + log.Debugf("[%d], endpoints, last known good [%s]", len(localendpoints), lastKnownGoodEndpoint) // Check how many local endpoints exist (should ideally be 1) stillExists := false if len(localendpoints) != 0 { @@ -115,8 +115,8 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser log.Errorf("%v", statusErr) } } - log.Infof("Stopping watching endpoints for [%s]", service.Name) - return nil + log.Infof("stopping watching endpoints for [%s]", service.Name) + return nil //nolint } func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1.Service) error { diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index d40e9579..f472471f 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -40,11 +40,18 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { return err } + if sm.config.ServiceNamespace == "" { + // v1.NamespaceAll is actually "", but we'll stay with the const incase things change upstream + sm.config.ServiceNamespace = v1.NamespaceAll + log.Infof("starting services watcher for all namespaces") + } else { + log.Infof("starting services watcher for services in namespace [%s]", sm.config.ServiceNamespace) + } // Use a restartable watcher, as this should help in the event of etcd or timeout issues rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) + return sm.clientSet.CoreV1().Services(sm.config.ServiceNamespace).Watch(ctx, metav1.ListOptions{}) }, }) if err != nil { diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 31050f6b..e65f700a 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -25,11 +25,6 @@ import ( // Test to find out what exists before hand const MangleChainName = "KUBE-VIP-EGRESS" -const iptableCommentSuffiv = "KUBE-VIP-" - -// DEBUG -const podSubnet = "10.0.0.0/26" -const serviceSubnet = "10.96.0.0/12" // Create new table @@ -75,11 +70,21 @@ func (e *Egress) DeleteSourceNat(podIP, vip string) error { exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) if !exists { - return fmt.Errorf("Unable to find source Nat rule for [%s]", podIP) + return fmt.Errorf("unable to find source Nat rule for [%s]", podIP) } return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) } +func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto string) error { + + exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port) + + if !exists { + return fmt.Errorf("unable to find source Nat rule for [%s], with destination port [%s]", podIP, port) + } + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port) +} + func (e *Egress) CreateMangleChain(name string) error { log.Infof("[Egress] Creating Chain [%s]", name) @@ -119,7 +124,7 @@ func (e *Egress) InsertMangeTableIntoPrerouting(name string) error { } func (e *Egress) InsertSourceNat(vip, podIP string) error { - log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", "name") + log.Infof("[Egress] Adding source nat from [%s] => [%s]", podIP, vip) if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip); err != nil { return err } else if exists { @@ -131,7 +136,20 @@ func (e *Egress) InsertSourceNat(vip, podIP string) error { return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) } -func (e *Egress) DeleteExistingSessions(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) + if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port); err != nil { + return err + } else if exists { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port); err2 != nil { + return err2 + } + } + + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port) +} + +func (e *Egress) DeleteExistingSessions(podIP string) error { nfct, err := ct.Open(&ct.Config{}) if err != nil { From daa7d852ab7485e5c3876bfd20f3126a6858363f Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 10 Oct 2022 14:12:36 +0100 Subject: [PATCH 286/542] linting fixes --- pkg/manager/watch_endpoints.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 57c135eb..a1160b04 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -70,7 +70,8 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser if lastKnownGoodEndpoint == "" { lastKnownGoodEndpoint = localendpoints[0] // Create new context - endpointContext, cancel = context.WithCancel(context.Background()) //nolint + endpointContext, cancel = context.WithCancel(context.Background()) //nolint:govet + defer cancel() //nolint wg.Add(1) if service.Annotations["kube-vip.io/egress"] == "true" { service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint @@ -116,7 +117,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } log.Infof("stopping watching endpoints for [%s]", service.Name) - return nil //nolint + return nil //nolint:govet } func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1.Service) error { From 5c859f42f5b3b30222c2c5cfc08b35669b0db2a5 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 10 Oct 2022 16:25:16 +0100 Subject: [PATCH 287/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4d3d0ea0..96d0fb6c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.0 +VERSION := v0.5.5 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 56362fb47e479881a66f93af6ae958cf2d22d1e7 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 10 Oct 2022 20:27:10 +0100 Subject: [PATCH 288/542] Update release.yaml --- .github/workflows/release.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1498333a..c7cd086d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,6 +4,8 @@ on: push: tags: - '*' + workflow_dispatch: + jobs: docker: runs-on: ubuntu-latest @@ -37,5 +39,18 @@ jobs: plndr/kube-vip:latest, ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip:latest + - name: Build and push main branch + id: docker_build_iptables + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile_iptables + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x + push: ${{ github.event_name != 'pull_request' }} + tags: >- + plndr/kube-vip:${{ github.ref_name }}, + plndr/kube-vip:latest, + ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip:latest - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} From 256f866d43ee8a9306269dac5b17d4206c000e21 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 11 Oct 2022 09:44:23 +0100 Subject: [PATCH 289/542] Update release.yaml --- .github/workflows/release.yaml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c7cd086d..8d46bfbc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,10 +1,9 @@ -name: Publish Releases to Docker Hub +name: Publish Releases to Docker Hub and GitHub Container Registry on: push: tags: - '*' - workflow_dispatch: jobs: docker: @@ -39,18 +38,5 @@ jobs: plndr/kube-vip:latest, ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip:latest - - name: Build and push main branch - id: docker_build_iptables - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile_iptables - platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x - push: ${{ github.event_name != 'pull_request' }} - tags: >- - plndr/kube-vip:${{ github.ref_name }}, - plndr/kube-vip:latest, - ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, - ghcr.io/kube-vip/kube-vip:latest - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} From 28b58dc0131be1a227730152b6d893c77c064a6c Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 11 Oct 2022 09:45:07 +0100 Subject: [PATCH 290/542] Create release_iptables.yaml --- .github/workflows/release_iptables.yaml | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/release_iptables.yaml diff --git a/.github/workflows/release_iptables.yaml b/.github/workflows/release_iptables.yaml new file mode 100644 index 00000000..e30b97db --- /dev/null +++ b/.github/workflows/release_iptables.yaml @@ -0,0 +1,44 @@ +name: Publish Egress (iptables) Releases to Docker Hub and Container Registry + +on: + push: + tags: + - '*' + workflow_dispatch: + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Github Packages + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push main branch + id: docker_build_iptables + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile_iptables + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x + push: ${{ github.event_name != 'pull_request' }} + tags: >- + plndr/kube-vip:${{ github.ref_name }}, + plndr/kube-vip:latest, + ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip:latest + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} From bc260ce03a359517280cac753b749193935e10d2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 11 Oct 2022 13:13:31 +0100 Subject: [PATCH 291/542] Update release.yaml --- .github/workflows/release.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8d46bfbc..320edf5b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -38,5 +38,18 @@ jobs: plndr/kube-vip:latest, ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip:latest + - name: Build iptables version and push main branch + id: docker_build_iptables + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile_iptables + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x + push: ${{ github.event_name != 'pull_request' }} + tags: >- + plndr/kube-vip-iptables:${{ github.ref_name }}, + plndr/kube-vip-iptables:latest, + ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip-iptables:latest - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} From c9a4d584b460bd3c76e964378fe4fda5804b05f7 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 11 Oct 2022 13:13:45 +0100 Subject: [PATCH 292/542] Delete release_iptables.yaml --- .github/workflows/release_iptables.yaml | 44 ------------------------- 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/release_iptables.yaml diff --git a/.github/workflows/release_iptables.yaml b/.github/workflows/release_iptables.yaml deleted file mode 100644 index e30b97db..00000000 --- a/.github/workflows/release_iptables.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: Publish Egress (iptables) Releases to Docker Hub and Container Registry - -on: - push: - tags: - - '*' - workflow_dispatch: - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Login to Github Packages - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push main branch - id: docker_build_iptables - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile_iptables - platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x - push: ${{ github.event_name != 'pull_request' }} - tags: >- - plndr/kube-vip:${{ github.ref_name }}, - plndr/kube-vip:latest, - ghcr.io/kube-vip/kube-vip:${{ github.ref_name }}, - ghcr.io/kube-vip/kube-vip:latest - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} From ea7ab1e4d600f09eda361d58e49cb7621afcf178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Tue, 11 Oct 2022 20:05:26 +0200 Subject: [PATCH 293/542] Update to go 1.19 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 2 +- CONTRIBUTING.md | 2 +- Dockerfile | 2 +- Dockerfile_iptables | 4 ++-- demo/Dockerfile | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2db4d50c..286aba9d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: '1.18' + go-version: '1.19' - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.2 - name: checks diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08d4c7e0..de6d2b63 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,7 +154,7 @@ the `$GOPATH`. To develop locally, you can follow these steps: - 1. [Install Go 1.18](https://golang.org/doc/install) + 1. [Install Go 1.19](https://golang.org/doc/install) 2. Checkout your feature branch and `cd` into it. 3. To build all Go files and install them under `bin`, run `make bin` 4. To run all Go unit tests, run `make test-unit` diff --git a/Dockerfile b/Dockerfile index 70119912..e2567d6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.18.0-alpine3.15 as dev +FROM golang:1.19.2-alpine3.16 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 1d56af99..01e236b7 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.18.0-alpine3.15 as dev +FROM golang:1.19.2-alpine3.16 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ @@ -16,4 +16,4 @@ FROM alpine:3.16.2 RUN apk add --no-cache iptables # Add kube-vip binary COPY --from=dev /src/kube-vip / -ENTRYPOINT ["/kube-vip"] \ No newline at end of file +ENTRYPOINT ["/kube-vip"] diff --git a/demo/Dockerfile b/demo/Dockerfile index a11a5074..96e85ad6 100644 --- a/demo/Dockerfile +++ b/demo/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.13-alpine as dev +FROM golang:1.19-alpine as dev RUN apk add --no-cache git ca-certificates RUN adduser -D appuser COPY main.go /src/ @@ -13,4 +13,4 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ FROM scratch COPY --from=dev /src/demo / -CMD ["/demo"] \ No newline at end of file +CMD ["/demo"] From 6004892920eb79f7f00cdbbc67b2e53d00b00b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Tue, 11 Oct 2022 20:02:08 +0200 Subject: [PATCH 294/542] go.mod: Update dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- go.mod | 73 ++++----- go.sum | 459 +++++++++++---------------------------------------------- 2 files changed, 123 insertions(+), 409 deletions(-) diff --git a/go.mod b/go.mod index cc8d0006..7eb364ee 100644 --- a/go.mod +++ b/go.mod @@ -13,29 +13,31 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 - github.com/mdlayher/ndp v0.10.0 + github.com/mdlayher/ndp v1.0.0 github.com/onsi/ginkgo v1.14.2 - github.com/onsi/gomega v1.10.1 - github.com/osrg/gobgp/v3 v3.1.0 - github.com/packethost/packngo v0.22.0 + github.com/onsi/gomega v1.21.1 + github.com/osrg/gobgp/v3 v3.7.0 + github.com/packethost/packngo v0.28.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.12.1 - github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.4.0 - github.com/stretchr/testify v1.7.1 + github.com/prometheus/client_golang v1.13.0 + github.com/sirupsen/logrus v1.9.0 + github.com/spf13/cobra v1.6.0 + github.com/stretchr/testify v1.8.0 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b - k8s.io/api v0.23.5 - k8s.io/apimachinery v0.23.5 - k8s.io/client-go v0.23.5 - k8s.io/klog/v2 v2.60.1 - sigs.k8s.io/kind v0.12.0 + golang.org/x/net v0.0.0-20221004154528-8021a29435af + golang.org/x/sys v0.0.0-20221010170243-090e33056c14 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 + k8s.io/api v0.25.2 + k8s.io/apimachinery v0.25.2 + k8s.io/client-go v0.25.2 + k8s.io/klog/v2 v2.70.1 + sigs.k8s.io/kind v0.16.0 ) require ( github.com/BurntSushi/toml v1.0.0 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect @@ -43,21 +45,27 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect github.com/magiconair/properties v1.8.5 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc // indirect @@ -69,12 +77,13 @@ require ( github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -83,27 +92,25 @@ require ( github.com/subosito/gotenv v1.2.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/grpc v1.45.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect - sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index d4fd5242..effd3fb4 100644 --- a/go.sum +++ b/go.sum @@ -13,19 +13,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -34,8 +21,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -46,22 +31,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -71,20 +48,11 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -93,27 +61,20 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/ipvs v0.8.0 h1:2cl7WMwQI6pklBcwrzdusAqHuPThu/VBdAFNl5r/D5w= github.com/cloudflare/ipvs v0.8.0/go.mod h1:rL2uv7wRPwNsyRig+6EJybJVLVIuw7+L6dc8DPyn+84= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -127,37 +88,26 @@ github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/florianl/go-conntrack v0.3.0 h1:DUY84Mce+/lE9dJi2EWvGYacQtX2X96J9aVWV99l8UE= github.com/florianl/go-conntrack v0.3.0/go.mod h1:Q+Um4J/nWUXSbnyzQRMOP4eweSeEQ2G8sfCO5gMz6Pw= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -166,21 +116,25 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -189,7 +143,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -197,8 +150,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -214,13 +165,12 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -229,20 +179,17 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -250,79 +197,32 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 h1:StGYqyAyFXHsJAZgFD4xLzfCrLOaHd86ZhX/5pZY/4I= github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3/go.mod h1:DwyLjKGwSxRt84j0FEB58tAFgjuEDEu20dyJG2canEI= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -338,7 +238,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXp github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -361,26 +260,16 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -394,8 +283,8 @@ github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lk github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= -github.com/mdlayher/ndp v0.10.0 h1:Zdwol2bq1EHY8xSnejIYkq6LEj7dLjLymJX0o/2tjGw= -github.com/mdlayher/ndp v0.10.0/go.mod h1:Uv6IWvgvqirNUu2N3ZXJEB86xu6foyUsG0NrClSSfek= +github.com/mdlayher/ndp v1.0.0 h1:rcFaJVj04Rj47ZlV/t3iZcuKzlpwBuBsD3gR9AHDzcI= +github.com/mdlayher/ndp v1.0.0/go.mod h1:+3vkk6YnlL8ZTRTjmQanCNQFqDKOpP2zNyHl2HqyoZs= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -417,23 +306,9 @@ github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/ github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -441,35 +316,30 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/osrg/gobgp/v3 v3.1.0 h1:mnAPYsx4V0xPpbDJL0r1qmU6FvoXg7R7ZHfb4kJSaSU= -github.com/osrg/gobgp/v3 v3.1.0/go.mod h1:PX9HMux6z+A4/X01NNvOad1k/xEJXuvsfHRVLHcFaVI= -github.com/packethost/packngo v0.22.0 h1:7syZ1jDN5rbdkkrh9A5rA/ijXe0AHNovNqlUUf0L+uM= -github.com/packethost/packngo v0.22.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/onsi/gomega v1.21.1 h1:OB/euWYIExnPBohllTicTHmGTrMaqJ67nIu80j0/uEM= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/osrg/gobgp/v3 v3.7.0 h1:h+Liq90TsxNKTB/443V8b1o/pwOm94yIsm+gP0RHwOo= +github.com/osrg/gobgp/v3 v3.7.0/go.mod h1:fKQPuk7+4qMiDT5viZTXT/aSEn8yYDkEs5p3NjmU2bw= +github.com/packethost/packngo v0.28.0 h1:3KSmYGgVzVxgH/oYCA+45L1OnPIKU/kWu6uEduB/7qY= +github.com/packethost/packngo v0.28.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -477,81 +347,71 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -565,38 +425,20 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= -gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -621,8 +463,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -631,16 +471,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -655,7 +489,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -674,44 +507,27 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= -golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -722,16 +538,14 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= +golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -746,20 +560,15 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -776,53 +585,33 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -830,7 +619,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= @@ -838,8 +626,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -854,10 +642,8 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -877,7 +663,6 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -885,27 +670,15 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0= golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b h1:9JncmKXcUwE918my+H6xmjBdhK2jM/UTUNXxhRG1BAk= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 h1:ARxNdT6I+00ZyY5yRT/ZECkQti4iGrMZX9dvG/ao/LY= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -922,23 +695,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -977,37 +733,7 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1022,24 +748,11 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1052,8 +765,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1064,7 +778,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -1080,8 +793,8 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1089,33 +802,27 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA= -k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= -k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= -k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8= -k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= +k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= +k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= +k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= +k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo= +k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= +k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= +k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/kind v0.12.0 h1:LFynXwQkH1MrWI8pM1FQty0oUwEKjU5EkMaVZaPld8E= -sigs.k8s.io/kind v0.12.0/go.mod h1:EcgDSBVxz8Bvm19fx8xkioFrf9dC30fMJdOTXBSGNoM= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.16.0 h1:GFXyyxtPnHFKqXr3ZG8/X0+0K9sl69lejStlPn2WQyM= +sigs.k8s.io/kind v0.16.0/go.mod h1:cKTqagdRyUQmihhBOd+7p43DpOPRn9rHsUC08K1Jbsk= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 7321a06dae4d86e8583dae6820e06a9a31464594 Mon Sep 17 00:00:00 2001 From: Abhay Krishna Arunachalam Date: Tue, 18 Oct 2022 22:09:14 -0700 Subject: [PATCH 295/542] Fix typo in EnableControlPlane config option Signed-off-by: Abhay Krishna Arunachalam --- cmd/kube-vip-manifests.go | 4 ++-- cmd/kube-vip.go | 6 +++--- pkg/kubevip/config_environment.go | 6 +++--- pkg/kubevip/config_generator.go | 4 ++-- pkg/kubevip/config_types.go | 6 +++--- pkg/manager/manager.go | 4 ++-- pkg/manager/manager_arp.go | 6 +++--- pkg/manager/manager_bgp.go | 7 +++---- 8 files changed, 21 insertions(+), 22 deletions(-) diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 8eab6cec..703d6f51 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -46,7 +46,7 @@ var kubeManifestPod = &cobra.Command{ } // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { + if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } @@ -71,7 +71,7 @@ var kubeManifestDaemon = &cobra.Command{ // TODO - check for certain things VIP/interfaces // The control plane has a requirement for a VIP being specified - if initConfig.EnableControlPane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { + if initConfig.EnableControlPlane && (initConfig.VIP == "" && initConfig.Address == "" && !initConfig.DDNS) { _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 88eff7e6..f3a2a578 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -123,7 +123,7 @@ func init() { kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableID, "tableID", 198, "The routing table used for all table entries") // Behaviour flags - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPane, "controlplane", false, "Enable HA for control plane") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPlane, "controlplane", false, "Enable HA for control plane") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services") // Extended behaviour flags @@ -246,10 +246,10 @@ 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.EnableControlPane, initConfig.EnableServices) + log.Infof("namespace [%s], Mode: [%s], Features(s): Control Plane:[%t], Services:[%t]", initConfig.Namespace, mode, initConfig.EnableControlPlane, initConfig.EnableServices) // End if nothing is enabled - if !initConfig.EnableServices && !initConfig.EnableControlPane { + if !initConfig.EnableServices && !initConfig.EnableControlPlane { log.Fatalln("no features are enabled") } diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 69219881..7efbfa8c 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -114,7 +114,7 @@ func ParseEnvironment(c *Config) error { c.DDNS = b } - // Find the namespace that the control pane should use (for leaderElection lock) + // Find the namespace that the control plane should use (for leaderElection lock) env = os.Getenv(cpNamespace) if env != "" { c.Namespace = env @@ -127,7 +127,7 @@ func ParseEnvironment(c *Config) error { if err != nil { return err } - c.EnableControlPane = b + c.EnableControlPlane = b } // Find Services toggle @@ -159,7 +159,7 @@ func ParseEnvironment(c *Config) error { c.LoadBalancerClassOnly = b } - // Find the namespace that the control pane should use (for leaderElection lock) + // Find the namespace that the control plane should use (for leaderElection lock) env = os.Getenv(svcNamespace) if env != "" { c.ServiceNamespace = env diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 28c39e73..5f735eb6 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -71,11 +71,11 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } // If we're doing the hybrid mode - if c.EnableControlPane { + if c.EnableControlPlane { cp := []corev1.EnvVar{ { Name: cpEnable, - Value: strconv.FormatBool(c.EnableControlPane), + Value: strconv.FormatBool(c.EnableControlPlane), }, { Name: cpNamespace, diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 31ba4ef7..b80d7490 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -21,10 +21,10 @@ type Config struct { // EnableRoutingTable, will use the routing table to advertise the VIP address EnableRoutingTable bool `yaml:"enableRoutingTable"` - // EnableControlPane, will enable the control plane functionality (used for hybrid behaviour) - EnableControlPane bool `yaml:"enableControlPane"` + // EnableControlPlane, will enable the control plane functionality (used for hybrid behaviour) + EnableControlPlane bool `yaml:"enableControlPlane"` - // EnableControlPane, will enable the services functionality (used for hybrid behaviour) + // EnableServices, will enable the services functionality (used for hybrid behaviour) EnableServices bool `yaml:"enableServices"` // EnableServicesElection, will enable leaderElection per service diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index af420393..2f705045 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -62,8 +62,8 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { switch { case fileExists(adminConfigPath): - if config.EnableControlPane { - // If this is a control pane host it will likely have started as a static pod or won't have the + if config.EnableControlPlane { + // If this is a control plane host it will likely have started as a static pod or won't have the // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. clientset, err = k8s.NewClientset(adminConfigPath, false, fmt.Sprintf("kubernetes:%v", config.Port)) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 33b560be..4edba64b 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -31,14 +31,14 @@ func (sm *Manager) startARP() error { go func() { <-sm.signalChan log.Info("Received termination, signaling shutdown") - if sm.config.EnableControlPane { + if sm.config.EnableControlPlane { cpCluster.Stop() } // Cancel the context, which will in turn cancel the leadership cancel() }() - if sm.config.EnableControlPane { + if sm.config.EnableControlPlane { cpCluster, err = cluster.InitCluster(sm.config, false) if err != nil { return err @@ -52,7 +52,7 @@ func (sm *Manager) startARP() error { go func() { err := cpCluster.StartCluster(sm.config, clusterManager, nil) if err != nil { - log.Errorf("Control Pane Error [%v]", err) + log.Errorf("Control Plane Error [%v]", err) // Trigger the shutdown of this manager instance sm.signalChan <- syscall.SIGINT diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 2cc72802..ad1c5c7a 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -69,7 +69,7 @@ func (sm *Manager) startBGP() error { go func() { <-sm.signalChan log.Info("Received termination, signaling shutdown") - if sm.config.EnableControlPane { + if sm.config.EnableControlPlane { if cpCluster != nil { cpCluster.Stop() } @@ -78,8 +78,7 @@ func (sm *Manager) startBGP() error { cancel() }() - if sm.config.EnableControlPane { - + if sm.config.EnableControlPlane { cpCluster, err = cluster.InitCluster(sm.config, false) if err != nil { return err @@ -93,7 +92,7 @@ func (sm *Manager) startBGP() error { go func() { err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer, packetClient) if err != nil { - log.Errorf("Control Pane Error [%v]", err) + log.Errorf("Control Plane Error [%v]", err) // Trigger the shutdown of this manager instance sm.signalChan <- syscall.SIGINT } From 6c52800bd40123e70728387d25b9a7c40cf01405 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 31 Oct 2022 12:54:53 +0000 Subject: [PATCH 296/542] Adds some additional checking scripts --- testing/kubeadm/create.sh | 2 +- testing/kubeadm/create_ctr.sh | 116 ++++++++++++++++++++++++++++++++++ testing/nodes | 15 +++-- 3 files changed, 127 insertions(+), 6 deletions(-) create mode 100755 testing/kubeadm/create_ctr.sh diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index 5d61650d..d1f31c30 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -96,7 +96,7 @@ esac if [[ -z "$DEPS" ]]; then logr "INFO" "Installing specific version of Kubernetes Dependancies" -# install_deps + install_deps fi first_node diff --git a/testing/kubeadm/create_ctr.sh b/testing/kubeadm/create_ctr.sh new file mode 100755 index 00000000..3ebf3b29 --- /dev/null +++ b/testing/kubeadm/create_ctr.sh @@ -0,0 +1,116 @@ +#!/bin/bash +set -e + +# Read node configuration +source ./testing/nodes + +# Read logging function +source ./testing/logging.bash + +install_deps() { + echo "Installing Kubernetes dependencies for Kubernetes $kubernetes_version on all nodes" + ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" +} + +first_node() { + logr "INFO" "Creating First node!" + #ssh $NODE01 "sudo modprobe ip_vs_rr" + #ssh $NODE01 "sudo modprobe nf_conntrack" + logr "INFO" "$(ssh $NODE01 "ctr images rm ghcr.io/kube-vip/kube-vip:$kube_vip_version" 2>&1)" + + # echo "echo "ip_vs | tee -a /etc/modules" + logr "INFO" "Creating Kube-vip.io Manifest" + + ssh $NODE01 "sudo ctr image pull ghcr.io/kube-vip/kube-vip:$kube_vip_version" + ssh $NODE01 "sudo mkdir -p /etc/kubernetes/manifests/; sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$kube_vip_version vip /kube-vip manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\" | sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + logr "INFO" "Deploying first Kubernetes node $NODE01" + FIRST_NODE=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $kubernetes_version --control-plane-endpoint $kube_vip_vip --upload-certs --pod-network-cidr=10.0.0.0/16") + echo "$FIRST_NODE" >> $logfile + CONTROLPLANE_CMD=$(echo "$FIRST_NODE" | grep -m1 certificate-key) + #CONTROLPLANE_CMD=$(ssh $NODE01 "sudo kubeadm init --kubernetes-version $kubernetes_version --control-plane-endpoint $kube_vip_vip --upload-certs --pod-network-cidr=10.0.0.0/16 | grep -m1 certificate-key") + ssh $NODE01 "sudo rm -rf ~/.kube/" + ssh $NODE01 "mkdir -p .kube" + ssh $NODE01 "sudo cp -i /etc/kubernetes/admin.conf .kube/config" + ssh $NODE01 "sudo chown dan:dan .kube/config" + logr "INFO" "Enabling strict ARP on kube-proxy" + ssh $NODE01 "kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system" + ssh $NODE01 "kubectl describe configmap -n kube-system kube-proxy | grep strictARP" + logr "INFO" "Deploying Calico to the Kubernetes Cluster" + ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" >> $logfile + logr "INFO" "Retrieving Join command" + JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") +} + + +additional_controlplane() { + logr "INFO" "Adding $NODE02" + ssh $NODE02 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile + sleep 1 + ssh $NODE02 "sudo ctr image pull ghcr.io/kube-vip/kube-vip:$kube_vip_version; sudo mkdir -p /etc/kubernetes/manifests/; sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$kube_vip_version vip /kube-vip manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile + logr "INFO" "Adding $NODE03" + ssh $NODE03 "sudo $JOIN_CMD $CONTROLPLANE_CMD" >> $logfile + sleep 1 + ssh $NODE03 "sudo ctr image pull ghcr.io/kube-vip/kube-vip:$kube_vip_version; sudo mkdir -p /etc/kubernetes/manifests/; sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$kube_vip_version vip /kube-vip manifest pod --interface ens160 --vip $kube_vip_vip --arp --leaderElection --enableLoadBalancer $kube_vip_mode | sed \"s/image:.*/image: plndr\/kube-vip:$kube_vip_version/\"| sudo tee /etc/kubernetes/manifests/vip.yaml" >> $logfile +} + +## Main() + +# Ensure we have an entirely new logfile +reset_logfile + +logr "INFO" "Starting kube-vip.io testing with Kubeadm" +logr "DEFAULT" "Creating Logfile $logfile" + +if [[ -z $1 && -z $2 && -z $3 && -z $4 ]]; then + echo "Usage:" + echo " Param 1: Kubernetes Version" + echo " Param 2: Kube-Vip Version" + echo " Param 3: Kube-Vip mode [\"controlplane\"/\"services\"/\"hybrid\"]" + echo " Param 4: Vip address" + echo "" + echo "" ./create.sh 1.18.5 0.4.0 hybrid 192.168.0.40 + exit 1 +fi + +# Sane variable renaming +kubernetes_version=$1 +kube_vip_version=$2 +kube_vip_vip=$4 + +case "$3" in +"controlplane") logr "INFO" "Creating in control plane only mode" + kube_vip_mode="--controlplane" + ;; +"services") logr "INFO" "Creating in services-only mode" + kube_vip_mode="--services" + ;; +"hybrid") logr "INFO" "Creating in hybrid mode" + kube_vip_mode="--controlplane --services" + ;; +*) echo "Unknown kube-vip mode [$3]" + exit -1 + ;; +esac + +if [[ -z "$DEPS" ]]; then + logr "INFO" "Installing specific version of Kubernetes Dependancies" + install_deps +fi + +first_node +additional_controlplane +logr "INFO" "Adding $NODE04" +ssh $NODE04 "sudo $JOIN_CMD" >> $logfile +logr "INFO" "Adding $NODE05" +ssh $NODE05 "sudo $JOIN_CMD" >> $logfile +logr "DEFAULT" "Nodes should be deployed at this point, waiting 5 secs and querying the deployment" +echo +sleep 5 +ssh $NODE01 "kubectl get nodes" | tee >> $logfile +ssh $NODE01 "kubectl get pods -A" | tee >> $logfile +echo +logr "INFO" "Kubernetes: $kubernetes_version, Kube-vip $kube_vip_version, Advertising VIP: $kube_vip_vip" diff --git a/testing/nodes b/testing/nodes index f624c23c..4d23b100 100644 --- a/testing/nodes +++ b/testing/nodes @@ -1,6 +1,11 @@ # Home lab (for testing) -NODE01=k8s01.fnnrn.me -NODE02=k8s02.fnnrn.me -NODE03=k8s03.fnnrn.me -NODE04=k8s04.fnnrn.me -NODE05=k8s05.fnnrn.me \ No newline at end of file +#NODE01=k8s01.fnnrn.me +#NODE02=k8s02.fnnrn.me +#NODE03=k8s03.fnnrn.me +#NODE04=k8s04.fnnrn.me +#NODE05=k8s05.fnnrn.me +NODE01=192.168.0.31 +NODE02=192.168.0.32 +NODE03=192.168.0.33 +NODE04=192.168.0.34 +NODE05=192.168.0.35 From 8687d28eb4381a60b0eab7f36e103ccc2d62aacb Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 31 Oct 2022 13:22:17 +0000 Subject: [PATCH 297/542] Fixes to logging Signed-off-by: thebsdbox --- cmd/kube-vip.go | 2 +- pkg/kubevip/config_environment.go | 3 +-- pkg/kubevip/config_types.go | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index f3a2a578..d344bb59 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -218,7 +218,7 @@ var kubeVipManager = &cobra.Command{ } // Set the logging level for all subsequent functions - log.SetLevel(log.Level(logLevel)) + log.SetLevel(log.Level(initConfig.Logging)) // start prometheus server if initConfig.PrometheusHTTPServer != "" { diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 7efbfa8c..2f99aebe 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -6,7 +6,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/detector" - log "github.com/sirupsen/logrus" ) // ParseEnvironment - will popultate the configuration from environment variables @@ -19,7 +18,7 @@ func ParseEnvironment(c *Config) error { if err != nil { panic("Unable to parse environment variable [vip_loglevel], should be int") } - log.SetLevel(log.Level(logLevel)) + c.Logging = int(logLevel) } // Find interface diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index b80d7490..3f6805f0 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -9,6 +9,9 @@ import ( // Config defines all of the settings for the Kube-Vip Pod type Config struct { + // Logging, settings + Logging int `yaml:"logging"` + // EnableARP, will use ARP to advertise the VIP address EnableARP bool `yaml:"enableARP"` From a4b11e68540812f0dacf85ca4435990ce54e5f49 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 31 Oct 2022 15:52:29 +0000 Subject: [PATCH 298/542] Fixes all leaderElection code to use config Signed-off-by: thebsdbox --- pkg/kubevip/config_environment.go | 5 +++++ pkg/manager/manager_arp.go | 6 +++--- pkg/manager/manager_table.go | 6 +++--- pkg/manager/manager_wireguard.go | 6 +++--- pkg/manager/servicesLeader.go | 6 +++--- pkg/service/manager_arp.go | 6 +++--- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 2f99aebe..210e465c 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -13,6 +13,11 @@ func ParseEnvironment(c *Config) error { // Ensure that logging is set through the environment variables env := os.Getenv(vipLogLevel) + // Set default value + if env == "" { + env = "4" + } + if env != "" { logLevel, err := strconv.ParseUint(env, 10, 32) if err != nil { diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 4edba64b..6cb9abf8 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -131,9 +131,9 @@ func (sm *Manager) startARP() error { // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, + LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { err = sm.servicesWatcher(ctx, sm.syncServices) diff --git a/pkg/manager/manager_table.go b/pkg/manager/manager_table.go index 6aedd605..eb16b11f 100644 --- a/pkg/manager/manager_table.go +++ b/pkg/manager/manager_table.go @@ -76,9 +76,9 @@ func (sm *Manager) startTableMode() error { // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, + LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { err = sm.servicesWatcher(ctx, sm.syncServices) diff --git a/pkg/manager/manager_wireguard.go b/pkg/manager/manager_wireguard.go index 197a1d31..a17c2c97 100644 --- a/pkg/manager/manager_wireguard.go +++ b/pkg/manager/manager_wireguard.go @@ -108,9 +108,9 @@ func (sm *Manager) startWireguard() error { // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, + LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { err = sm.servicesWatcher(ctx, sm.syncServices) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 47982171..6c32990e 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -64,9 +64,9 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 60 * time.Second, - RenewDeadline: 15 * time.Second, - RetryPeriod: 5 * time.Second, + LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index 3705cc21..9e342c2f 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -108,9 +108,9 @@ func (sm *Manager) startARP() error { // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: 10 * time.Second, - RenewDeadline: 5 * time.Second, - RetryPeriod: 1 * time.Second, + LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { if err := sm.servicesWatcher(ctx); err != nil { From f173c5f97942193d26a1b18a750f3b7c8d165384 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Mon, 31 Oct 2022 16:07:35 +0000 Subject: [PATCH 299/542] Adds the capability to exclude egress traffic Signed-off-by: thebsdbox --- pkg/kubevip/config_environment.go | 11 +++++++++++ pkg/kubevip/config_envvar.go | 6 ++++++ pkg/kubevip/config_types.go | 10 +++++++++- pkg/manager/service_egress.go | 25 +++++++++++++++++++++---- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 210e465c..dfc717ae 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -382,5 +382,16 @@ func ParseEnvironment(c *Config) error { c.PrometheusHTTPServer = env } + // Set Egress configuration(s) + env = os.Getenv(egressPodCidr) + if env != "" { + c.EgressPodCidr = env + } + + env = os.Getenv(egressServiceCidr) + if env != "" { + c.EgressServiceCidr = env + } + return nil } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 7b661e9a..3c66255b 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -30,6 +30,12 @@ const ( //vipCidr - defines the cidr that the vip will use vipCidr = "vip_cidr" + //egressPodCidr - defines the cidr that egress will ignore + egressPodCidr = "egress_podcidr" + + //egressServiceCidr - defines the cidr that egress will ignore + egressServiceCidr = "egress_servicecidr" + ///////////////////////////////////// // TO DO: // Determine how to tidy this mess up diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 3f6805f0..58b2e9ee 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -98,7 +98,7 @@ type Config struct { BGPPeerConfig bgp.Peer BGPPeers []string - // EnablePacket, will use the metal API to update the EIP <-> VIP (if BGP is enabled then BGP will be used) + // EnableMetal, will use the metal API to update the EIP <-> VIP (if BGP is enabled then BGP will be used) EnableMetal bool `yaml:"enableMetal"` // MetalAPIKey, is the API token used to authenticate to the API @@ -118,6 +118,14 @@ type Config struct { // The hostport used to expose Prometheus metrics over an HTTP server PrometheusHTTPServer string `yaml:"prometheusHTTPServer,omitempty"` + + // Egress configuration + + // EgressPodCidr, this contains the pod cidr range to ignore Egress + EgressPodCidr string + + // EgressServiceCidr, this contains the service cidr range to ignore + EgressServiceCidr string } // LeaderElection defines all of the settings for Kubernetes LeaderElection diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index f1fa7528..8e4bf7c6 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -12,8 +12,10 @@ import ( ) // DEBUG -const podCIDR = "10.0.0.0/26" -const serviceCIDR = "10.96.0.0/12" +const ( + defaultPodCIDR = "10.0.0.0/16" + defaultServiceCIDR = "10.96.0.0/12" +) func (sm *Manager) iptablesCheck() error { file, err := os.Open("/proc/modules") @@ -47,6 +49,21 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts s // serviceCIDR = "10.96.0.0/12" // podCIDR = "10.0.0.0/16" // } + + var podCidr, serviceCidr string + + if sm.config.EgressPodCidr != "" { + podCidr = sm.config.EgressPodCidr + } else { + podCidr = defaultPodCIDR + } + + if sm.config.EgressServiceCidr != "" { + serviceCidr = sm.config.EgressServiceCidr + } else { + serviceCidr = defaultServiceCIDR + } + i, err := vip.CreateIptablesClient() if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) @@ -62,11 +79,11 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts s return fmt.Errorf("error creating mangle chain [%s], error [%s]", vip.MangleChainName, err) } } - err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, podCIDR) + err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, podCidr) if err != nil { return fmt.Errorf("error adding rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } - err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, serviceCIDR) + err = i.AppendReturnRulesForDestinationSubnet(vip.MangleChainName, serviceCidr) if err != nil { return fmt.Errorf("error adding rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } From ccaef3d7502f43929047cad98f422e741719d8e0 Mon Sep 17 00:00:00 2001 From: thebsdbox Date: Wed, 2 Nov 2022 16:18:17 +0000 Subject: [PATCH 300/542] This fixes an issue with the cache being wiped Signed-off-by: thebsdbox --- pkg/manager/servicesLeader.go | 9 ++++----- pkg/manager/watch_services.go | 36 +++++++++++++++++------------------ 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 6c32990e..b005fc98 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -53,7 +53,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. Identity: id, }, } - //activeService[string(service.UID)] = true + // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -69,20 +69,19 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { - + // Mark this service as active (as we've started leading) + activeService[string(service.UID)] = true // we run this in background as it's blocking go func() { - //sm.syncServices(ctx, service, wg) if err := sm.syncServices(ctx, service, wg); err != nil { log.Errorln(err) } }() - activeService[string(service.UID)] = true }, OnStoppedLeading: func() { // we can do cleanup here - log.Infof("services leader lost: %s", id) + log.Infof("service [%s] leader lost: %s", service.Name, id) if activeService[string(service.UID)] { if err := sm.deleteService(string(service.UID)); err != nil { log.Errorln(err) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index f472471f..30515280 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -26,16 +26,18 @@ var activeService map[string]bool // watchedService keeps track of services that are already being watched var watchedService map[string]bool +func init() { + // Set up the caches for monitoring existing active or watched services + activeServiceLoadBalancer = make(map[string]context.Context) + activeService = make(map[string]bool) + watchedService = make(map[string]bool) +} + // This function handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context.Context, *v1.Service, *sync.WaitGroup) error) error { // Watch function var wg sync.WaitGroup - // Set up the activeServiceLoadBalancer - activeServiceLoadBalancer = make(map[string]context.Context) - activeService = make(map[string]bool) - watchedService = make(map[string]bool) - id, err := os.Hostname() if err != nil { return err @@ -107,33 +109,32 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + //log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) // Scenarios: // 1. - if !activeService[string(svc.UID)] { wg.Add(1) activeServiceLoadBalancer[string(svc.UID)] = context.TODO() // Background the services election if sm.config.EnableServicesElection { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Start an endpoint watcher if we're not watching it alredy + // Start an endpoint watcher if we're not watching it already if !watchedService[string(svc.UID)] { - watchedService[string(svc.UID)] = true - + log.Warnf("[RACE] now watching [%s]", svc.Name) // background the endpoint watcher go func() { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Add Endpoint watcher err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) if err != nil { - log.Errorf("%v", err) + log.Error(err) } - watchedService[string(svc.UID)] = false wg.Wait() } }() + // We're now watching this service + watchedService[string(svc.UID)] = true } } else { go func() { @@ -158,6 +159,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if !ok { return fmt.Errorf("unable to parse Kubernetes services from API watcher") } + if activeService[string(svc.UID)] { // We only care about LoadBalancer services if svc.Spec.Type != v1.ServiceTypeLoadBalancer { @@ -169,12 +171,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) break } - // If this is a watched service then and additional leaderElection will handle stopping - if !watchedService[string(svc.UID)] { - err := sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } + // If this is an active service then and additional leaderElection will handle stopping + err := sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) } activeServiceLoadBalancer[string(svc.UID)].Done() activeService[string(svc.UID)] = false From af1a1e51c8e1c741966788f2b082287368110fc7 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 7 Nov 2022 15:25:34 +0000 Subject: [PATCH 301/542] Adds tags to rules so that we can garbage collect. --- pkg/manager/service_egress.go | 18 ++++- pkg/manager/watch_services.go | 1 - pkg/vip/egress.go | 145 +++++++++++++++++++++++----------- pkg/vip/egress_test.go | 36 +++++++++ 4 files changed, 152 insertions(+), 48 deletions(-) create mode 100644 pkg/vip/egress_test.go diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 8e4bf7c6..99af4e45 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/kube-vip/kube-vip/pkg/vip" + log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -68,6 +69,14 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts s if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } + if os.Getenv("EGRESS_CLEAN") != "" { + log.Info("[egress] Cleaning any dangling kube-vip egress rules") + cleanErr := i.CleanIPtables() + if cleanErr != nil { + log.Errorf("Error cleaning rules [%v]", cleanErr) + } + } + // Check if the kube-vip mangle chain exists, if not create it exists, err := i.CheckMangleChain(vip.MangleChainName) if err != nil { @@ -161,8 +170,15 @@ func TeardownEgress(podIP, vipIP, destinationPorts string) error { if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } - if destinationPorts != "" { + // Remove the marking of egress packets + err = i.DeleteMangleMarking(podIP, vip.MangleChainName) + if err != nil { + return fmt.Errorf("error changing iptables rules for egress [%s]", err) + } + + // Clear up SNAT rules + if destinationPorts != "" { fixedPorts := strings.Split(destinationPorts, ",") for _, fixedPort := range fixedPorts { diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 30515280..7ee80dae 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -121,7 +121,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Start an endpoint watcher if we're not watching it already if !watchedService[string(svc.UID)] { - log.Warnf("[RACE] now watching [%s]", svc.Name) // background the endpoint watcher go func() { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index e65f700a..c840085f 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -2,6 +2,7 @@ package vip import ( "fmt" + "strings" iptables "github.com/coreos/go-iptables/iptables" log "github.com/sirupsen/logrus" @@ -25,20 +26,7 @@ import ( // Test to find out what exists before hand const MangleChainName = "KUBE-VIP-EGRESS" - -// Create new table - -func (e *Egress) DumpChain(name string) error { - log.Infof("Dumping chain [%s]", name) - c, err := e.ipTablesClient.List("mangle", name) - if err != nil { - return err - } - for x := range c { - log.Infof("Rule -> %s", c[x]) - } - return nil -} +const Comment = "a3ViZS12aXAK=kube-vip" type Egress struct { ipTablesClient *iptables.IPTables @@ -52,10 +40,8 @@ func CreateIptablesClient() (*Egress, error) { } func (e *Egress) CheckMangleChain(name string) (bool, error) { - - log.Infof("[Egress] Cheching for Chain [%s]", name) + log.Infof("[egress] Cheching for Chain [%s]", name) return e.ipTablesClient.ChainExists("mangle", name) - } func (e *Egress) DeleteMangleChain(name string) error { @@ -66,114 +52,181 @@ func (e *Egress) DeleteManglePrerouting(name string) error { return e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name) } +func (e *Egress) DeleteMangleMarking(podIP, name string) error { + exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) + + if !exists { + return fmt.Errorf("unable to find source Mangle rule for [%s]", podIP) + } + return e.ipTablesClient.Delete("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) +} + func (e *Egress) DeleteSourceNat(podIP, vip string) error { - exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) + exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) if !exists { return fmt.Errorf("unable to find source Nat rule for [%s]", podIP) } - return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) } func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto string) error { - exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", 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", Comment) if !exists { return fmt.Errorf("unable to find source Nat rule for [%s], with destination port [%s]", podIP, port) } - return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port) + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment) } func (e *Egress) CreateMangleChain(name string) error { - log.Infof("[Egress] Creating Chain [%s]", name) + log.Infof("[egress] Creating Chain [%s]", 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) - exists, _ := e.ipTablesClient.Exists("mangle", name, "-d", subnet, "-j", "RETURN") + log.Infof("[egress] Adding jump for subnet [%s] to RETURN to previous chain/rules", subnet) + exists, _ := e.ipTablesClient.Exists("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", Comment) if !exists { - return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN") + return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", Comment) } return nil } func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error { - log.Infof("[Egress] Marking packets on network [%s]", subnet) - exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") + log.Infof("[egress] Marking packets on network [%s]", subnet) + exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) if !exists { - return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64") + return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) } return nil } func (e *Egress) InsertMangeTableIntoPrerouting(name string) error { - log.Infof("[Egress] Adding jump from mangle prerouting to [%s]", name) - if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name); err != nil { + log.Infof("[egress] Adding jump from mangle prerouting to [%s]", name) + if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", Comment); err != nil { return err } else if exists { - if err2 := e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name); err2 != nil { + if err2 := e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", Comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name) + return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name, "-m", "comment", "--comment", Comment) } func (e *Egress) InsertSourceNat(vip, podIP string) error { - log.Infof("[Egress] Adding source nat from [%s] => [%s]", podIP, vip) - if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip); err != nil { + log.Infof("[egress] Adding source nat from [%s] => [%s]", podIP, 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", Comment); err != nil { return err } else if exists { - if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip); err2 != nil { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip) + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) } 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) - if exists, err := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port); err != nil { + log.Infof("[egress] Adding source nat from [%s] => [%s], with destination port [%s]", podIP, vip, port) + if exists, err := 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", Comment); err != nil { return err } else if exists { - if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port); err2 != nil { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port) + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment) } func (e *Egress) DeleteExistingSessions(podIP string) error { nfct, err := ct.Open(&ct.Config{}) if err != nil { - fmt.Println("could not create nfct:", err) - return nil + log.Errorf("could not create nfct: %v", err) + return err } defer nfct.Close() sessions, err := nfct.Dump(ct.Conntrack, ct.IPv4) if err != nil { - fmt.Println("could not dump sessions:", err) - return nil + log.Errorf("could not dump sessions: %v", err) + return err } for _, session := range sessions { //fmt.Printf("Looking for [%s] found [%s]\n", podIP, session.Origin.Dst.String()) if session.Origin.Src.String() == podIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { //fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) - err = nfct.Delete(ct.Conntrack, ct.IPv4, session) if err != nil { - fmt.Println("could not delete sessions:", err) + log.Errorf("could not delete sessions: %v", err) } + } + } + return nil +} + +// Debug functions +func (e *Egress) DumpChain(name string) error { + log.Infof("Dumping chain [%s]", name) + c, err := e.ipTablesClient.List("mangle", name) + if err != nil { + return err + } + for x := range c { + log.Infof("Rule -> %s", c[x]) + } + return nil +} + +func (e *Egress) CleanIPtables() error { + natRules, err := e.ipTablesClient.List("nat", "POSTROUTING") + if err != nil { + return err + } + foundNatRules := findRules(natRules) + log.Warnf("[egress] Cleaning [%d] dangling postrouting nat rules", 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) + } + } + + mangleRules, err := e.ipTablesClient.List("mangle", MangleChainName) + if err != nil { + return err + } + foundNatRules = findRules(mangleRules) + log.Warnf("[egress] Cleaning [%d] dangling prerouting mangle rules", 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) } } return nil } + +func findRules(rules []string) [][]string { + var foundRules [][]string + + for i := range rules { + r := strings.Split(rules[i], " ") + for x := range r { + if r[x] == "\""+Comment+"\"" { + // Remove the quotes around the comment + r[x] = strings.Trim(r[x], "\"") + foundRules = append(foundRules, r) + } + } + } + + return foundRules +} diff --git a/pkg/vip/egress_test.go b/pkg/vip/egress_test.go new file mode 100644 index 00000000..ce90f88a --- /dev/null +++ b/pkg/vip/egress_test.go @@ -0,0 +1,36 @@ +package vip + +import ( + "fmt" + "reflect" + "testing" +) + +func Test_findRules(t *testing.T) { + type args struct { + rules []string + } + tests := []struct { + name string + args args + want [][]string + }{ + + { + "test", + args{[]string{ + "-A PREROUTING -m comment --comment \"cali:6gwbT8clXdHdC1b1\" -j cali-PREROUTING", + fmt.Sprintf("-A KUBE-VIP-EGRESS -s 172.17.88.190/32 -m comment --comment \"%s\" -j MARK --set-xmark 0x40/0x40", Comment), + fmt.Sprintf("-A POSTROUTING -m comment --comment \"%s\" -j RETURN", Comment), + }}, + [][]string{{"-A", "KUBE-VIP-EGRESS", "-s", "172.17.88.190/32", "-m", "comment", "--comment", Comment, "-j", "MARK", "--set-xmark", "0x40/0x40"}, {"-A", "POSTROUTING", "-m", "comment", "--comment", Comment, "-j", "RETURN"}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := findRules(tt.args.rules); !reflect.DeepEqual(got, tt.want) { + t.Errorf("findRules() = \n%v, want \n%v", got, tt.want) + } + }) + } +} From 5e38c81290c963bab8761a45ea264aeccd43055f Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 7 Nov 2022 17:43:55 +0000 Subject: [PATCH 302/542] Adds capability to specify a subnet for the VIP Signed-off-by: Dan Finneran --- pkg/kubevip/config_environment.go | 6 ++++++ pkg/kubevip/config_envvar.go | 5 ++++- pkg/kubevip/config_generator.go | 11 +++++++++++ pkg/manager/services.go | 7 ++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index dfc717ae..32c7670f 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -176,6 +176,12 @@ func ParseEnvironment(c *Config) error { c.VIPCIDR = env } + // Find vip address subnet + env = os.Getenv(vipSubnet) + if env != "" { + c.VIPSubnet = env + } + // Find Single Node env = os.Getenv(vipSingleNode) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 3c66255b..d1ea15f1 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -27,9 +27,12 @@ const ( //vipServicesInterface - defines the interface that the service vips should bind too vipServicesInterface = "vip_servicesinterface" - //vipCidr - defines the cidr that the vip will use + //vipCidr - defines the cidr that the vip will use (for BGP) vipCidr = "vip_cidr" + //vipSubnet - defines the subnet that the vip will use + vipSubnet = "vip_subnet" + //egressPodCidr - defines the cidr that egress will ignore egressPodCidr = "egress_podcidr" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 5f735eb6..82c9aa53 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -67,7 +67,18 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }, } newEnvironment = append(newEnvironment, cidr...) + } + // If a subnet is required for the VIP + if c.VIPSubnet != "" { + // build environment variables + cidr := []corev1.EnvVar{ + { + Name: vipSubnet, + Value: c.VIPSubnet, + }, + } + newEnvironment = append(newEnvironment, cidr...) } // If we're doing the hybrid mode diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 3063643e..668df4b1 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -6,6 +6,7 @@ import ( "os" "strings" "sync" + "time" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" @@ -86,6 +87,7 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy defer wg.Done() log.Debugf("[STARTING] Service Sync") + // Iterate through the synchronising services foundInstance := false newServiceAddress := service.Spec.LoadBalancerIP @@ -119,6 +121,8 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy } func (sm *Manager) addService(service *v1.Service) error { + startTime := time.Now() + newService, err := NewInstance(service, sm.config) if err != nil { return err @@ -157,7 +161,8 @@ func (sm *Manager) addService(service *v1.Service) error { } } } - log.Debugf("[COMPLETE] Service Sync") + finishTime := time.Since(startTime) + log.Infof("[service] synchronised in %dms", finishTime.Milliseconds()) return nil } From ccaf8119da60a3fe6e98194922b679ba5bd4f89c Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 7 Nov 2022 18:40:48 +0000 Subject: [PATCH 303/542] Fixes to where iptables are gc Signed-off-by: Dan Finneran --- pkg/manager/manager_arp.go | 15 +++++++++++++++ pkg/manager/service_egress.go | 8 -------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 6cb9abf8..59067f26 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -2,6 +2,7 @@ package manager import ( "context" + "fmt" "os" "strconv" "syscall" @@ -14,6 +15,7 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/vip" ) // Start will begin the Manager, which will start services and watch the configmap @@ -97,6 +99,19 @@ func (sm *Manager) startARP() error { } } + // This will tidy any dangling kube-vip iptables rules + i, err := vip.CreateIptablesClient() + if err != nil { + return fmt.Errorf("error Creating iptables client [%s]", err) + } + if os.Getenv("EGRESS_CLEAN") != "" { + log.Info("[egress] Cleaning any dangling kube-vip egress rules") + cleanErr := i.CleanIPtables() + if cleanErr != nil { + log.Errorf("Error cleaning rules [%v]", cleanErr) + } + } + // 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 { diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 99af4e45..63a7d162 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/kube-vip/kube-vip/pkg/vip" - log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -69,13 +68,6 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts s if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } - if os.Getenv("EGRESS_CLEAN") != "" { - log.Info("[egress] Cleaning any dangling kube-vip egress rules") - cleanErr := i.CleanIPtables() - if cleanErr != nil { - log.Errorf("Error cleaning rules [%v]", cleanErr) - } - } // Check if the kube-vip mangle chain exists, if not create it exists, err := i.CheckMangleChain(vip.MangleChainName) From e599a333306bd60ed5d1076a770ef7846977e1de Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 9 Nov 2022 16:49:33 +0000 Subject: [PATCH 304/542] logging and fixed an issue with multiple elections Signed-off-by: Dan Finneran --- pkg/cluster/clusterLeaderElection.go | 6 +++--- pkg/cluster/service.go | 12 +++++++----- pkg/kubevip/config_environment.go | 15 ++++++++++++++- pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_types.go | 3 +++ pkg/manager/instance.go | 1 + pkg/manager/services.go | 6 +++--- pkg/manager/servicesLeader.go | 8 ++++---- pkg/manager/watch_endpoints.go | 4 ++-- pkg/vip/arp.go | 3 --- pkg/vip/egress.go | 2 +- 11 files changed, 41 insertions(+), 22 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index ffb85ea5..d5a1ab6e 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -268,7 +268,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro case watch.Added, watch.Modified: node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } //Find the node IP address (this isn't foolproof) for x := range node.Status.Addresses { @@ -276,14 +276,14 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro 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.Errorf("add IPVS backend [%v]", err) } } } case watch.Deleted: node, ok := event.Object.(*v1.Node) if !ok { - return fmt.Errorf("Unable to parse Kubernetes Node from Annotation watcher") + return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } //Find the node IP address (this isn't foolproof) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index a6cc2794..a95a38b4 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -167,9 +167,6 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co // StartLoadBalancerService will start a VIP instance and leave it for kube-proxy to handle func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Server) { - // Start a kube-vip loadbalancer service - log.Infof("Starting advertising address [%s] with kube-vip", c.VIP) - // use a Go context so we can tell the arp loop code when we // want to step down //nolint @@ -209,6 +206,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser if ndp != nil { defer ndp.Close() } + log.Debugf("Broadcasting ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) for { select { @@ -242,9 +240,14 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } } } - time.Sleep(3 * time.Second) + if c.ArpBroadcastRate < 500 { + log.Errorf("arp broadcast rate is [%d], this shouldn't be lower that 300ms (defaulting to 3000)", c.ArpBroadcastRate) + c.ArpBroadcastRate = 3000 + } + time.Sleep(time.Duration(c.ArpBroadcastRate) * time.Millisecond) } }(ctxArp) + log.Debugf("ending ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) } if c.EnableBGP { @@ -277,5 +280,4 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } } }() - log.Infoln("Started Load Balancer and Virtual IP") } diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 32c7670f..0e0b150c 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -210,7 +210,7 @@ func ParseEnvironment(c *Config) error { c.StartAsLeader = b } - // Find ARP + // Find if ARP is enabled env = os.Getenv(vipArp) if env != "" { b, err := strconv.ParseBool(env) @@ -220,6 +220,19 @@ func ParseEnvironment(c *Config) error { c.EnableARP = b } + // Find if ARP is enabled + env = os.Getenv(vipArpRate) + if env != "" { + i64, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.ArpBroadcastRate = i64 + } else { + // default to three seconds + c.ArpBroadcastRate = 3000 + } + // Wireguard Mode env = os.Getenv(vipWireguard) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index d1ea15f1..3d775315 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -6,6 +6,9 @@ const ( //vipArp - defines if the arp broadcast should be enabled vipArp = "vip_arp" + //vip_arpRate - defines the rate of gARP broadcasts + vipArpRate = "vip_arpRate" + //vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaderElection = "vip_leaderelection" diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 58b2e9ee..d91ffda7 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -36,6 +36,9 @@ type Config struct { // LoadBalancerClassOnly, will enable load balancing only for services with LoadBalancerClass set to "kube-vip.io/kube-vip-class" LoadBalancerClassOnly bool `yaml:"lbClassOnly"` + // ArpBroadcastRate, defines how often kube-vip will update the network about updates to the network + ArpBroadcastRate int64 `yaml:"arpBroadcastRate"` + // Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations Annotations string diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 7bb2b436..89d7a8c1 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -64,6 +64,7 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) VIPSubnet: config.VIPSubnet, EnableRoutingTable: config.EnableRoutingTable, RoutingTableID: config.RoutingTableID, + ArpBroadcastRate: config.ArpBroadcastRate, } // Create new service diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 668df4b1..efaac62c 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -128,7 +128,7 @@ func (sm *Manager) addService(service *v1.Service) error { return err } - log.Infof("adding VIP [%s] for [%s/%s] ", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + log.Infof("[service] adding VIP [%s] for [%s/%s] ", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) @@ -173,10 +173,10 @@ func (sm *Manager) upnpMap(s *Instance) { if sm.upnp != nil { log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.serviceSnapshot.Name) if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { - log.Infof("Service should be accessible externally on port [%d]", s.Port) + log.Infof("service should be accessible externally on port [%d]", s.Port) } else { sm.upnp.Reclaim() - log.Errorf("Unable to map port to gateway [%s]", err.Error()) + log.Errorf("unable to map port to gateway [%s]", err.Error()) } } } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index b005fc98..5cd91302 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -40,7 +40,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. } serviceLease := fmt.Sprintf("kubevip-%s", service.Name) - log.Infof("beginning leadership for service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, id) + log.Infof("[services election] for service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, 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{ @@ -54,6 +54,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. }, } + activeService[string(service.UID)] = true // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -70,7 +71,6 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. Callbacks: leaderelection.LeaderCallbacks{ OnStartedLeading: func(ctx context.Context) { // Mark this service as active (as we've started leading) - activeService[string(service.UID)] = true // we run this in background as it's blocking go func() { if err := sm.syncServices(ctx, service, wg); err != nil { @@ -81,7 +81,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. }, OnStoppedLeading: func() { // we can do cleanup here - log.Infof("service [%s] leader lost: %s", service.Name, id) + log.Infof("[services election] service [%s] leader lost: [%s]", service.Name, id) if activeService[string(service.UID)] { if err := sm.deleteService(string(service.UID)); err != nil { log.Errorln(err) @@ -96,7 +96,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. // I just got the lock return } - log.Infof("new leader elected: %s", identity) + log.Infof("[services election] new leader elected: %s", identity) }, }, }) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index a1160b04..4b3838ae 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -17,7 +17,7 @@ import ( ) func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { - log.Infof("watching endpoints for service [%s]", service.Name) + log.Infof("[endpoint] watching for service [%s] in namespace [%s]", service.Name, service.Namespace) // Use a restartable watcher, as this should help in the event of etcd or timeout issues var cancel context.CancelFunc var endpointContext context.Context @@ -116,7 +116,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser log.Errorf("%v", statusErr) } } - log.Infof("stopping watching endpoints for [%s]", service.Name) + log.Infof("[endpoints] stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) return nil //nolint:govet } diff --git a/pkg/vip/arp.go b/pkg/vip/arp.go index 4338d52a..7a8cee2f 100644 --- a/pkg/vip/arp.go +++ b/pkg/vip/arp.go @@ -12,8 +12,6 @@ import ( "net" "syscall" "unsafe" - - log "github.com/sirupsen/logrus" ) const ( @@ -169,7 +167,6 @@ func ARPSendGratuitous(address, ifaceName string) error { } // This is a debug message, enable debugging to ensure that the gratuitous arp is repeating - log.Debugf("Broadcasting ARP update for %s (%s) via %s", address, iface.HardwareAddr, iface.Name) m, err := gratuitousARP(ip, iface.HardwareAddr) if err != nil { return err diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index c840085f..813dfd34 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -40,7 +40,7 @@ func CreateIptablesClient() (*Egress, error) { } func (e *Egress) CheckMangleChain(name string) (bool, error) { - log.Infof("[egress] Cheching for Chain [%s]", name) + log.Infof("[egress] Checking for Chain [%s]", name) return e.ipTablesClient.ChainExists("mangle", name) } From 1dc035f606704c9e43f931b26f31e5da9c6d342d Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 9 Nov 2022 17:10:02 +0000 Subject: [PATCH 305/542] Update Makefile Bumping for a new release! --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 96d0fb6c..6e625b87 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.5 +VERSION := v0.5.6 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 47a8832d891b2be15ac80dea3cf4983360e6e5b5 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 10 Nov 2022 10:52:53 +0000 Subject: [PATCH 306/542] Fix to egress rules Signed-off-by: Dan Finneran --- pkg/manager/manager_arp.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 59067f26..5483b351 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -2,7 +2,6 @@ package manager import ( "context" - "fmt" "os" "strconv" "syscall" @@ -100,15 +99,16 @@ func (sm *Manager) startARP() error { } // This will tidy any dangling kube-vip iptables rules - i, err := vip.CreateIptablesClient() - if err != nil { - return fmt.Errorf("error Creating iptables client [%s]", err) - } if os.Getenv("EGRESS_CLEAN") != "" { - log.Info("[egress] Cleaning any dangling kube-vip egress rules") - cleanErr := i.CleanIPtables() - if cleanErr != nil { - log.Errorf("Error cleaning rules [%v]", cleanErr) + i, err := vip.CreateIptablesClient() + if err != nil { + log.Warnf("[egress] Unable to clean any dangling egress rules [%v]", err) + } else { + log.Info("[egress] Cleaning any dangling kube-vip egress rules") + cleanErr := i.CleanIPtables() + if cleanErr != nil { + log.Errorf("Error cleaning rules [%v]", cleanErr) + } } } From 7ebb54961be7f5a2b68823e35124cd11d20571d1 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 10 Nov 2022 10:58:33 +0000 Subject: [PATCH 307/542] Update release.yaml Allows manual trigger --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 320edf5b..10b01349 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,6 +4,7 @@ on: push: tags: - '*' + workflow_dispatch: jobs: docker: From dc40c4dc0b1e11893de6ff7f7c123ca97668a0e5 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 16 Nov 2022 13:03:27 +0000 Subject: [PATCH 308/542] Tidies the annotations Signed-off-by: Dan Finneran --- pkg/manager/services.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index efaac62c..a6549547 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -16,9 +16,13 @@ import ( ) const ( - hwAddrKey = "kube-vip.io/hwaddr" - requestedIP = "kube-vip.io/requestedIP" - vipHost = "kube-vip.io/vipHost" + hwAddrKey = "kube-vip.io/hwaddr" + requestedIP = "kube-vip.io/requestedIP" + vipHost = "kube-vip.io/vipHost" + egress = "kube-vip.io/egress" + egressDestinationPorts = "kube-vip.io/egress-destination-ports" + egressSourcePorts = "kube-vip.io/egress-source-ports" + endpoint = "kube-vip.io/active-endpoint" ) func (sm *Manager) deleteService(uid string) error { @@ -56,11 +60,11 @@ func (sm *Manager) deleteService(uid string) error { } // We will need to tear down the egress - if sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/egress"] == "true" { - if sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"] != "" { + if sm.serviceInstances[x].serviceSnapshot.Annotations[egress] == "true" { + if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/active-endpoint"], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations["kube-vip.io/egress-destination-ports"]) + err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) if err != nil { log.Errorf("%v", err) } @@ -143,18 +147,18 @@ func (sm *Manager) addService(service *v1.Service) error { } return err } - if service.Annotations["kube-vip.io/egress"] == "true" { - if service.Annotations["kube-vip.io/active-endpoint"] != "" { + if service.Annotations[egress] == "true" { + if service.Annotations[endpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations["kube-vip.io/active-endpoint"], service.Annotations["kube-vip.io/egress-destination-ports"], service.Annotations["kube-vip.io/egress-source-ports"]) + err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations[endpoint], service.Annotations[egressDestinationPorts], service.Annotations[egressSourcePorts]) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { - err = sm.updateServiceEndpointAnnotation(service.Annotations["kube-vip.io/active-endpoint"], service) + err = sm.updateServiceEndpointAnnotation(service.Annotations[endpoint], service) if err != nil { log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) } From 139add9d51abd4b68cdbcb4eb13a1f5d42428293 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 16 Nov 2022 13:20:17 +0000 Subject: [PATCH 309/542] Adds an annotation for flushing conntrack rules Signed-off-by: Dan Finneran --- pkg/manager/service_egress.go | 4 +- pkg/manager/services.go | 142 +++++++++++++++++++--------------- pkg/vip/egress.go | 35 ++++++--- 3 files changed, 108 insertions(+), 73 deletions(-) diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 63a7d162..bc4c2371 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -129,7 +129,7 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts s } } //_ = i.DumpChain(vip.MangleChainName) - err = i.DeleteExistingSessions(podIP) + err = vip.DeleteExistingSessions(podIP, false) if err != nil { return err } @@ -199,7 +199,7 @@ func TeardownEgress(podIP, vipIP, destinationPorts string) error { return fmt.Errorf("error changing iptables rules for egress [%s]", err) } } - err = i.DeleteExistingSessions(podIP) + err = vip.DeleteExistingSessions(podIP, false) if err != nil { return fmt.Errorf("error changing iptables rules for egress [%s]", err) } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index a6549547..66721c0c 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" @@ -23,70 +24,9 @@ const ( egressDestinationPorts = "kube-vip.io/egress-destination-ports" egressSourcePorts = "kube-vip.io/egress-source-ports" endpoint = "kube-vip.io/active-endpoint" + flushContrack = "kube-vip.io/flush-conntrack" ) -func (sm *Manager) deleteService(uid string) error { - //pretect multiple calls - sm.mutex.Lock() - defer sm.mutex.Unlock() - - var updatedInstances []*Instance - found := false - for x := range sm.serviceInstances { - log.Debugf("Looking for [%s], found [%s]", uid, sm.serviceInstances[x].UID) - // Add the running services to the new array - if sm.serviceInstances[x].UID != uid { - updatedInstances = append(updatedInstances, sm.serviceInstances[x]) - } else { - // Flip the found when we match - found = true - sm.serviceInstances[x].cluster.Stop() - if sm.serviceInstances[x].isDHCP { - sm.serviceInstances[x].dhcpClient.Stop() - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) - if err != nil { - return fmt.Errorf("error finding VIP Interface: %v", err) - } - - err = netlink.LinkDel(macvlan) - if err != nil { - return fmt.Errorf("error deleting DHCP Link : %v", err) - } - } - if sm.serviceInstances[x].vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) - err := sm.bgpServer.DelHost(cidrVip) - return err - } - - // We will need to tear down the egress - if sm.serviceInstances[x].serviceSnapshot.Annotations[egress] == "true" { - if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { - - log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) - if err != nil { - log.Errorf("%v", err) - } - } - } - } - } - // If we've been through all services and not found the correct one then error - if !found { - // TODO: - fix UX - //return fmt.Errorf("unable to find/stop service [%s]", uid) - return nil - } - - // Update the service array - sm.serviceInstances = updatedInstances - - log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances)) - - return nil -} - func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() @@ -147,7 +87,23 @@ func (sm *Manager) addService(service *v1.Service) error { } return err } + + // Check if we need to flush any conntrack connections (due to some dangling conntrack connections) + if service.Annotations[flushContrack] == "true" { + log.Debugf("Flushing conntrack rules for service [%s]", service.Name) + err = vip.DeleteExistingSessions(service.Spec.LoadBalancerIP, false) + if err != nil { + log.Errorf("Error flushing any remaining egress connections [%s]", err) + } + err = vip.DeleteExistingSessions(service.Spec.LoadBalancerIP, true) + if err != nil { + log.Errorf("Error flushing any remaining ingress connections [%s]", err) + } + } + + // Check if egress is enabled on the service, if so we'll need to configure some rules if service.Annotations[egress] == "true" { + log.Debugf("Enabling egress for the service [%s]", service.Name) if service.Annotations[endpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() @@ -171,6 +127,68 @@ func (sm *Manager) addService(service *v1.Service) error { return nil } +func (sm *Manager) deleteService(uid string) error { + //pretect multiple calls + sm.mutex.Lock() + defer sm.mutex.Unlock() + + var updatedInstances []*Instance + found := false + for x := range sm.serviceInstances { + log.Debugf("Looking for [%s], found [%s]", uid, sm.serviceInstances[x].UID) + // Add the running services to the new array + if sm.serviceInstances[x].UID != uid { + updatedInstances = append(updatedInstances, sm.serviceInstances[x]) + } else { + // Flip the found when we match + found = true + sm.serviceInstances[x].cluster.Stop() + if sm.serviceInstances[x].isDHCP { + sm.serviceInstances[x].dhcpClient.Stop() + macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) + if err != nil { + return fmt.Errorf("error finding VIP Interface: %v", err) + } + + err = netlink.LinkDel(macvlan) + if err != nil { + return fmt.Errorf("error deleting DHCP Link : %v", err) + } + } + if sm.serviceInstances[x].vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) + err := sm.bgpServer.DelHost(cidrVip) + return err + } + + // We will need to tear down the egress + if sm.serviceInstances[x].serviceSnapshot.Annotations[egress] == "true" { + if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { + + log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) + err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) + if err != nil { + log.Errorf("%v", err) + } + } + } + } + } + // If we've been through all services and not found the correct one then error + if !found { + // TODO: - fix UX + //return fmt.Errorf("unable to find/stop service [%s]", uid) + return nil + } + + // Update the service array + sm.serviceInstances = updatedInstances + + log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances)) + + return nil +} + func (sm *Manager) upnpMap(s *Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 813dfd34..d0eebff8 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -144,7 +144,7 @@ func (e *Egress) InsertSourceNatForDestinationPort(vip, podIP, port, proto strin return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment) } -func (e *Egress) DeleteExistingSessions(podIP string) error { +func DeleteExistingSessions(sessionIP string, destination bool) error { nfct, err := ct.Open(&ct.Config{}) if err != nil { @@ -157,17 +157,34 @@ func (e *Egress) DeleteExistingSessions(podIP string) error { log.Errorf("could not dump sessions: %v", err) return err } - - for _, session := range sessions { - //fmt.Printf("Looking for [%s] found [%s]\n", podIP, session.Origin.Dst.String()) - if session.Origin.Src.String() == podIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { - //fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) - err = nfct.Delete(ct.Conntrack, ct.IPv4, session) - if err != nil { - log.Errorf("could not delete sessions: %v", err) + // by default we only clear source (i.e. connections going from the vip (egress)) + if !destination { + for _, session := range sessions { + //fmt.Printf("Looking for [%s] found [%s]\n", podIP, session.Origin.Dst.String()) + + if session.Origin.Src.String() == sessionIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { + //fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) + err = nfct.Delete(ct.Conntrack, ct.IPv4, session) + if err != nil { + log.Errorf("could not delete sessions: %v", err) + } + } + } + } else { + // This will clear any "dangling" outbound connections. + for _, session := range sessions { + //fmt.Printf("Looking for [%s] found [%s]\n", podIP, session.Origin.Dst.String()) + + if session.Origin.Dst.String() == sessionIP /*&& *session.Origin.Proto.DstPort == uint16(destinationPort)*/ { + //fmt.Printf("Source -> %s Destination -> %s:%d\n", session.Origin.Src.String(), session.Origin.Dst.String(), *session.Origin.Proto.DstPort) + err = nfct.Delete(ct.Conntrack, ct.IPv4, session) + if err != nil { + log.Errorf("could not delete sessions: %v", err) + } } } } + return nil } From f84c4aaa8bc112800c5f6a15f70765ca9bb6f220 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 17 Nov 2022 16:17:18 +0000 Subject: [PATCH 310/542] added testing Signed-off-by: Dan Finneran --- demo/README.md | 46 ++++++++++++++++++++++++++++ demo/client/main.go | 56 +++++++++++++++++++++++++++++++++++ demo/{ => server}/Dockerfile | 0 demo/{ => server}/Makefile | 0 demo/{ => server}/deploy.yaml | 25 ++++++++++++++-- demo/{ => server}/go.mod | 0 demo/{ => server}/main.go | 2 +- 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 demo/README.md create mode 100644 demo/client/main.go rename demo/{ => server}/Dockerfile (100%) rename demo/{ => server}/Makefile (100%) rename demo/{ => server}/deploy.yaml (58%) rename demo/{ => server}/go.mod (100%) rename demo/{ => server}/main.go (97%) diff --git a/demo/README.md b/demo/README.md new file mode 100644 index 00000000..10595094 --- /dev/null +++ b/demo/README.md @@ -0,0 +1,46 @@ +# Demo client-server + +This contains some example code to determine how long "failovers" are taking within kube-vip, the server component should live within the cluster and the client should be externally. + +## Deploy the server + +Simply apply the manifest to a working cluster that has kube-vip deployed: + +``` +kubectl apply -f ./demo/server/deploy.yaml +``` + +Retrieve the loadBalancer IP that is fronting the service: + +``` +kubectl get svc demo-service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +demo-service LoadBalancer 10.104.18.147 192.168.0.217 10002:32529/UDP 117m +``` + +## Connect the client + +From elsewhere, clone the kube-vip repository and connect the client to the server endpoint (loadBalancer IP) with the following command: + +``` +go run ./demo/client/main.go -address= +``` + +You will only see output when the client has reconcilled the connection to a pod beneath the service, where it will print the timestamp to reconnection along with the time in milliseconds it took: + +``` +15:58:35.916952 3008 +15:58:45.947506 2005 +15:58:57.983151 3007 +15:59:08.013450 2005 +15:59:20.046491 3008 +15:59:30.076341 2507 +15:59:42.110747 3008 +``` + +## Kill some pods to test + +On a machine or control plane that has `kubectl` and has the credentials to speak to the cluster we will run a command to find the demo pod and kill it every 10 seconds: + +`while true ; do kubectl delete pod $(kubectl get pods | grep -v NAME | grep vip| awk '{ print $1 }'); sleep 10; done` + diff --git a/demo/client/main.go b/demo/client/main.go new file mode 100644 index 00000000..35617cb1 --- /dev/null +++ b/demo/client/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "net" + "time" +) + +const udpdata = "a3ViZS12aXAK=kube-vip" + +func main() { + address := flag.String("address", "127.0.0.1", "The address of the server") + port := flag.Int("port", 10002, "the port of the server") + interval := flag.Float64("interval", 1000, "Interval in milliseconds") + flag.Parse() + var errorTime time.Time + var errorOccured bool + for { + p := make([]byte, 2048) + conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", *address, *port)) + conn.SetDeadline(time.Now().Add(time.Duration(*interval) * time.Millisecond)) + if err != nil { + //fmt.Printf("Connectivity error [%v]", err) + if !errorOccured { + errorTime = time.Now() + errorOccured = true + } + conn.Close() + continue + } + + fmt.Fprintf(conn, udpdata) + + _, err = bufio.NewReader(conn).Read(p) + if err != nil { + //fmt.Printf("read error %v\n", err) + if !errorOccured { + errorTime = time.Now() + errorOccured = true + } + conn.Close() + continue + } + time.Sleep(time.Duration(*interval) * time.Millisecond) + if errorOccured { + finishTime := time.Since(errorTime) + //fmt.Printf("connectivity reconciled in %dms\n", finishTime.Milliseconds()) + //t :=time.Now().Format("15:04:05.000000") + fmt.Printf("%s %d\n", time.Now().Format("15:04:05.000000"), finishTime.Milliseconds()) + + errorOccured = false + } + } +} diff --git a/demo/Dockerfile b/demo/server/Dockerfile similarity index 100% rename from demo/Dockerfile rename to demo/server/Dockerfile diff --git a/demo/Makefile b/demo/server/Makefile similarity index 100% rename from demo/Makefile rename to demo/server/Makefile diff --git a/demo/deploy.yaml b/demo/server/deploy.yaml similarity index 58% rename from demo/deploy.yaml rename to demo/server/deploy.yaml index cb29e4e4..19327764 100644 --- a/demo/deploy.yaml +++ b/demo/server/deploy.yaml @@ -6,7 +6,7 @@ metadata: app: kube-vip-demo name: kube-vip-demo spec: - replicas: 3 + replicas: 1 selector: matchLabels: app: kube-vip-demo @@ -30,4 +30,25 @@ spec: ports: - containerPort: 10001 - containerPort: 10002 -status: {} \ No newline at end of file +status: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: demo-service + namespace: default + labels: + app: demo-service + annotations: + kube-vip.io/egress: "true" +spec: + type: LoadBalancer + # "Local" preserves the client source IP and avoids a second hop for + # LoadBalancer and NodePort + externalTrafficPolicy: Local + ports: + - name: demo-udp + port: 10002 + protocol: UDP + selector: + app: kube-vip-demo \ No newline at end of file diff --git a/demo/go.mod b/demo/server/go.mod similarity index 100% rename from demo/go.mod rename to demo/server/go.mod diff --git a/demo/main.go b/demo/server/main.go similarity index 97% rename from demo/main.go rename to demo/server/main.go index 24aab371..9d2ecec3 100644 --- a/demo/main.go +++ b/demo/server/main.go @@ -60,7 +60,7 @@ func main() { fmt.Println("error: ", err) } - ServerConn.WriteTo(buf[0:n], addr) + ServerConn.WriteTo(buf[0:n], ) } } } From 6d5533ca583ecef82558c7b5d55883ce27168eab Mon Sep 17 00:00:00 2001 From: Steve Sloka Date: Sat, 26 Nov 2022 11:52:05 -0500 Subject: [PATCH 311/542] linter: Clean up some linter errors Cleans up errors found when running `make` that golangci-lint found. Signed-off-by: Steve Sloka --- .github/workflows/ci.yaml | 2 +- demo/client/main.go | 37 ++++++++++++++++++++++++----------- pkg/equinixmetal/utils.go | 3 +-- pkg/kubevip/config_manager.go | 3 +-- pkg/manager/manager.go | 3 +-- pkg/manager/service_egress.go | 2 +- pkg/manager/services.go | 2 +- pkg/service/manager.go | 3 +-- 8 files changed, 33 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 286aba9d..2373ca18 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,7 @@ jobs: with: go-version: '1.19' - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.2 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.50.1 - name: checks run: make check - name: test docker build diff --git a/demo/client/main.go b/demo/client/main.go index 35617cb1..2a4e9e9c 100644 --- a/demo/client/main.go +++ b/demo/client/main.go @@ -16,41 +16,56 @@ func main() { interval := flag.Float64("interval", 1000, "Interval in milliseconds") flag.Parse() var errorTime time.Time - var errorOccured bool + var errorOccurred bool for { p := make([]byte, 2048) conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", *address, *port)) - conn.SetDeadline(time.Now().Add(time.Duration(*interval) * time.Millisecond)) + if err != nil { + if !errorOccurred { + errorTime = time.Now() + errorOccurred = true + } + continue + } + + err = conn.SetDeadline(time.Now().Add(time.Duration(*interval) * time.Millisecond)) if err != nil { //fmt.Printf("Connectivity error [%v]", err) - if !errorOccured { + if !errorOccurred { errorTime = time.Now() - errorOccured = true + errorOccurred = true + } + if err = conn.Close(); err != nil { + fmt.Printf("Error closing connection [%v]", err) } - conn.Close() continue } - fmt.Fprintf(conn, udpdata) + _, err = fmt.Fprint(conn, udpdata) + if err != nil { + fmt.Printf("Error writing data [%v]", err) + } _, err = bufio.NewReader(conn).Read(p) if err != nil { //fmt.Printf("read error %v\n", err) - if !errorOccured { + if !errorOccurred { errorTime = time.Now() - errorOccured = true + errorOccurred = true + } + if err = conn.Close(); err != nil { + fmt.Printf("Error closing connection [%v]", err) } - conn.Close() continue } time.Sleep(time.Duration(*interval) * time.Millisecond) - if errorOccured { + if errorOccurred { finishTime := time.Since(errorTime) //fmt.Printf("connectivity reconciled in %dms\n", finishTime.Milliseconds()) //t :=time.Now().Format("15:04:05.000000") fmt.Printf("%s %d\n", time.Now().Format("15:04:05.000000"), finishTime.Milliseconds()) - errorOccured = false + errorOccurred = false } } } diff --git a/pkg/equinixmetal/utils.go b/pkg/equinixmetal/utils.go index 95d2734e..6403fd24 100644 --- a/pkg/equinixmetal/utils.go +++ b/pkg/equinixmetal/utils.go @@ -3,7 +3,6 @@ package equinixmetal import ( "encoding/json" "fmt" - "io/ioutil" "os" "github.com/packethost/packngo" @@ -46,7 +45,7 @@ func GetPacketConfig(providerConfig string) (string, string, error) { } // get our token and project if providerConfig != "" { - configBytes, err := ioutil.ReadFile(providerConfig) + configBytes, err := os.ReadFile(providerConfig) if err != nil { return "", "", fmt.Errorf("failed to get read configuration file at path %s: %v", providerConfig, err) } diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 128024f2..423423ca 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -2,7 +2,6 @@ package kubevip import ( "fmt" - "io/ioutil" "os" "strconv" "strings" @@ -36,7 +35,7 @@ func OpenConfig(path string) (*Config, error) { // Check the actual path from the string if _, err := os.Stat(path); !os.IsNotExist(err) { // Attempt to read the data - configData, err := ioutil.ReadFile(path) + configData, err := os.ReadFile(path) if err != nil { return nil, err } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 2f705045..37c4e186 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -2,7 +2,6 @@ package manager import ( "fmt" - "io/ioutil" "os" "os/signal" "path/filepath" @@ -151,7 +150,7 @@ func (sm *Manager) Start() error { } func returnNameSpace() (string, error) { - if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { if ns := strings.TrimSpace(string(data)); len(ns) > 0 { return ns, nil } diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index bc4c2371..b2e9ea29 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -43,7 +43,7 @@ func (sm *Manager) iptablesCheck() error { return nil } -func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, sourcePorts string) error { +func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts string) error { // serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() // if err != nil { // serviceCIDR = "10.96.0.0/12" diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 66721c0c..f07fbd6c 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -110,7 +110,7 @@ func (sm *Manager) addService(service *v1.Service) error { if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations[endpoint], service.Annotations[egressDestinationPorts], service.Annotations[egressSourcePorts]) + err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations[endpoint], service.Annotations[egressDestinationPorts]) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 69a448bd..18f62758 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -2,7 +2,6 @@ package service import ( "fmt" - "io/ioutil" "os" "strings" @@ -96,7 +95,7 @@ func (sm *Manager) Start() error { } func returnNameSpace() (string, error) { - if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { if ns := strings.TrimSpace(string(data)); len(ns) > 0 { return ns, nil } From f4a9e1b65b792b23fc3d51253e229cc3e8ced486 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Mon, 28 Nov 2022 15:46:15 -0800 Subject: [PATCH 312/542] Fix several CVEs Signed-off-by: lubronzhan --- go.mod | 8 ++++---- go.sum | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 7eb364ee..0a054066 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.0.0-20221004154528-8021a29435af - golang.org/x/sys v0.0.0-20221010170243-090e33056c14 + golang.org/x/net v0.2.0 + golang.org/x/sys v0.2.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 k8s.io/api v0.25.2 k8s.io/apimachinery v0.25.2 @@ -95,8 +95,8 @@ require ( golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/term v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index effd3fb4..2613d480 100644 --- a/go.sum +++ b/go.sum @@ -518,8 +518,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= -golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -609,11 +609,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -621,8 +622,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 1e4ef9f2b12d71233ed9fe5c0acf919f76b3953c Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 1 Dec 2022 11:09:54 +0000 Subject: [PATCH 313/542] garbage collection for goroutines Signed-off-by: Dan Finneran --- pkg/cluster/clusterLeaderElection.go | 4 ++-- pkg/manager/manager.go | 9 +++++--- pkg/manager/manager_arp.go | 4 +++- pkg/manager/watch_annotations.go | 20 ++++++++++++------ pkg/manager/watch_endpoints.go | 31 ++++++++++++++++++++++++---- pkg/manager/watch_services.go | 20 +++++++++++++----- 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index d5a1ab6e..0a7c6096 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -122,7 +122,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * go func() { <-signalChan - log.Info("Received termination, signaling shutdown") + log.Info("Received termination, signaling cluster shutdown") // Cancel the context, which will in turn cancel the leadership cancel() // Cancel the arp context, which will in turn stop any broadcasts @@ -318,7 +318,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro } } - log.Infoln("Exiting Annotations watcher") + log.Infoln("Exiting Node watcher") return nil } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 2f705045..b2023143 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -40,9 +40,12 @@ type Manager struct { //BGP Manager, this is a singleton that manages all BGP advertisements bgpServer *bgp.Server - // This channel is used to signal a shutdown + // This channel is used to catch an OS signal and trigger a shutdown signalChan chan os.Signal + // This channel is used to signal a shutdown + shutdownChan chan struct{} + // This is a prometheus counter used to count the number of events received // from the service watcher countServiceWatchEvent *prometheus.CounterVec @@ -114,8 +117,8 @@ func (sm *Manager) Start() error { // Add Notification for SIGTERM (sent from Kubernetes) signal.Notify(sm.signalChan, syscall.SIGTERM) - // Add Notification for SIGKILL (sent from Kubernetes) - signal.Notify(sm.signalChan, syscall.SIGKILL) //nolint + // All watchers and other goroutines should have an additional goroutine that blocks on this, to shut things down + sm.shutdownChan = make(chan struct{}) // If BGP is enabled then we start a server instance that will broadcast VIPs if sm.config.EnableBGP { diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 5483b351..3a034b0f 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -31,10 +31,12 @@ func (sm *Manager) startARP() error { // Shutdown function that will wait on this signal, unless we call it ourselves go func() { <-sm.signalChan - log.Info("Received termination, signaling shutdown") + log.Info("Received kube-vip termination, signaling shutdown") if sm.config.EnableControlPlane { cpCluster.Stop() } + // Close all go routines + close(sm.shutdownChan) // Cancel the context, which will in turn cancel the leadership cancel() }() diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index c7c7c9db..d79ffada 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -69,15 +69,23 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("error creating annotations watcher: %s", err.Error()) } + exitFunction := make(chan struct{}) go func() { - <-sm.signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context - rw.Stop() + select { + case <-sm.shutdownChan: + log.Debug("[annotations] shutdown called") + // Stop the retry watcher + rw.Stop() + return + case <-exitFunction: + log.Debug("[annotations] function ending") + // Stop the retry watcher + rw.Stop() + return + } }() ch := rw.ResultChan() - //defer rw.Stop() for event := range ch { // We need to inspect the event and get ResourceVersion out of it @@ -124,7 +132,7 @@ func (sm *Manager) annotationsWatcher() error { default: } } - + close(exitFunction) log.Infoln("Exiting Annotations watcher") return nil diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 4b3838ae..202d4380 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -38,8 +38,28 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser return fmt.Errorf("error creating endpoint watcher: %s", err.Error()) } + exitFunction := make(chan struct{}) + go func() { + select { + case <-sm.shutdownChan: + log.Debug("[endpoint] shutdown called") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return + case <-exitFunction: + log.Debug("[endpoint] function ending") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return + } + }() + ch := rw.ResultChan() - //defer rw.Stop() + var lastKnownGoodEndpoint string for event := range ch { @@ -108,14 +128,17 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } case watch.Deleted: - cancel() - rw.Stop() + // Close the goroutine that will end the retry watcher, then exit the endpoint watcher function + close(exitFunction) + log.Infof("[endpoints] deleted stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) + return nil case watch.Error: errObject := apierrors.FromObject(event.Object) statusErr, _ := errObject.(*apierrors.StatusError) - log.Errorf("%v", statusErr) + log.Errorf("endpoint -> %v", statusErr) } } + close(exitFunction) log.Infof("[endpoints] stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) return nil //nolint:govet } diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 7ee80dae..a36429dc 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -59,13 +59,22 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { return fmt.Errorf("error creating services watcher: %s", err.Error()) } + exitFunction := make(chan struct{}) go func() { - <-sm.signalChan - // Cancel the context - rw.Stop() + select { + case <-sm.shutdownChan: + log.Debug("[endpoint] shutdown called") + // Stop the retry watcher + rw.Stop() + return + case <-exitFunction: + log.Debug("[endpoint] function ending") + // Stop the retry watcher + rw.Stop() + return + } }() ch := rw.ResultChan() - //defer rw.Stop() // Used for tracking an active endpoint / pod for event := range ch { @@ -195,10 +204,11 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } status := statusErr.ErrStatus - log.Errorf("%v", status) + log.Errorf("services -> %v", status) default: } } + close(exitFunction) log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") return nil } From f830b389da298faf30e23c08d93cb00179119c58 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 1 Dec 2022 11:23:21 +0000 Subject: [PATCH 314/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6e625b87..3f073f4d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.6 +VERSION := v0.5.7 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 45aae3ee7cffcbb6647929a1d2c178f85d7cbee3 Mon Sep 17 00:00:00 2001 From: George V <39589642+GeorgeGedox@users.noreply.github.com> Date: Sun, 4 Dec 2022 00:01:44 +0200 Subject: [PATCH 315/542] Update broken links in k3s docs Fix broken documentation links --- docs/usage/k3s/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index 60266208..a6febbfb 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -36,7 +36,7 @@ curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manif ## Step 3: Generate a Kube-Vip DaemonSet Manifest -Refer to the [DaemonSet manifest generation documentation](/install_daemonset/#generating-a-manifest) for the process to complete this step. +Refer to the [DaemonSet manifest generation documentation](/installation/daemonset/#generating-a-manifest) for the process to complete this step. Either store this generated manifest separately in the `/var/lib/rancher/k3s/server/manifests/` directory, or append to the existing RBAC manifest called `kube-vip-rbac.yaml`. As a general best practice, it is a cleaner approach to place all related resources into a single YAML file. @@ -50,4 +50,4 @@ Once the cluster is installed, you should be able to edit the `kubeconfig` file ## Step 5: Service Load Balancing -If wanting to use the `kube-vip` [cloud controller](/usage/on-prem), pass the `--disable servicelb` flag so K3s will not attempt to render Kubernetes Service resources of type `LoadBalancer`. If building with `k3sup`, the flag should be given as an argument to the `--k3s-extra-args` flag itself: `--k3s-extra-args "--disable servicelb"`. To install the `kube-vip` cloud controller, follow the additional steps in the [cloud controller guide](/on-prem/#install-the-kube-vip-cloud-provider). +If wanting to use the `kube-vip` [cloud controller](/docs/usage/cloud-provider/), pass the `--disable servicelb` flag so K3s will not attempt to render Kubernetes Service resources of type `LoadBalancer`. If building with `k3sup`, the flag should be given as an argument to the `--k3s-extra-args` flag itself: `--k3s-extra-args "--disable servicelb"`. To install the `kube-vip` cloud controller, follow the additional steps in the [cloud controller guide](/docs/usage/cloud-provider/#install-the-kube-vip-cloud-provider). From 9c603518675ffc54ce88caefef1a529c1c57fa37 Mon Sep 17 00:00:00 2001 From: Efim <94497805+fimmicon@users.noreply.github.com> Date: Tue, 6 Dec 2022 14:27:18 +0200 Subject: [PATCH 316/542] Fix broken link in docs --- docs/architecture/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index fae1f691..962a573a 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -69,7 +69,7 @@ This section details the flow of events in order for `kube-vip` to advertise a K 1. An end user exposes an application through Kubernetes as a Service type `LoadBalancer`. For example, imperatively using `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` 2. Within the Kubernetes cluster, a Service object is created with the `spec.type` set to `LoadBalancer`. -3. A controller (typically a [Cloud Controller](/usage/on-prem)) has a loop that "watches" for Services of the type `LoadBalancer`. +3. A controller (typically a [Cloud Controller](/usage/cloud-provider)) has a loop that "watches" for Services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this Service along with doing anything that is network specific for the environment where the cluster is running. 5. Once the controller has an IP address, it will update the Service field `spec.loadBalancerIP` with the IP address. 6. `kube-vip` Pods implement a "watcher" for Services that have a `svc.Spec.loadBalancerIP` address attached. From 9c7a1e60be3b4d2e02baa5743174d707af3884a2 Mon Sep 17 00:00:00 2001 From: Daniel Pereira Date: Tue, 27 Dec 2022 17:46:44 -0300 Subject: [PATCH 317/542] fix: endpoints watcher Without this specific ClusterRole rule, kube-vip would not be able to listen for `endpoints` changes when deployed as a DaemonSet, thus causing the IP addresses not being announced and the following error message every second: ``` E1227 20:37:20.290479 1 retrywatcher.go:130] "Watch failed" err="unknown (get endpoints)" ``` --- docs/manifests/rbac.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manifests/rbac.yaml b/docs/manifests/rbac.yaml index f35d79aa..0480d0ec 100644 --- a/docs/manifests/rbac.yaml +++ b/docs/manifests/rbac.yaml @@ -12,7 +12,7 @@ metadata: name: system:kube-vip-role rules: - apiGroups: [""] - resources: ["services", "services/status", "nodes"] + resources: ["services", "services/status", "nodes", "endpoints"] verbs: ["list","get","watch", "update"] - apiGroups: ["coordination.k8s.io"] resources: ["leases"] From 1dc74c4249538904d85ce0a53eaf73d29dcf78b8 Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Fri, 6 Jan 2023 22:39:04 +0800 Subject: [PATCH 318/542] bgp: Let gobgp figure out NEXT_HOP path attribute According to UpdatePathAttrs in gobgp internal/pkg/table/path.go, gobgp will fill NEXT_HOP with BGP session local address if given NEXT_HOP is an unspecified address, such as 0.0.0.0 and ::. It is better to use that address as NEXT_HOP, since the BGP TCP connection ensures the address reaches the node. See: https://github.com/osrg/gobgp/blob/v3.10.0/internal/pkg/table/path.go#L223 Signed-off-by: zyxwvu Shi --- pkg/bgp/peers.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index f58c6258..a832e9f8 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -84,18 +84,9 @@ func (b *Server) getPath(ip net.IP) *api.Path { Origin: 0, }) - var nh string - if b.c.NextHop != "" { - nh = b.c.NextHop - } else if b.c.SourceIP != "" { - nh = b.c.SourceIP - } else { - nh = b.c.RouterID - } - //nolint a2, _ := ptypes.MarshalAny(&api.NextHopAttribute{ - NextHop: nh, + NextHop: "0.0.0.0", // gobgp will fill this }) return &api.Path{ From 35a93d8275c3334a2c0b35363d5dc6927223bd20 Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Fri, 6 Jan 2023 22:44:40 +0800 Subject: [PATCH 319/542] bgp: Advertise IPv6 host prefix using MpReachNLRIAttribute MP-BGP protocol requires IPv6 prefixes to be advertised in a path attribute called MP_REACH_NLRI. Without the attribute non-IPv4 prefixes can not be advertised. This prevents IPv6 loadBalancerIps and control plane addresses from being advertised to the network. Signed-off-by: zyxwvu Shi --- pkg/bgp/peers.go | 74 ++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index a832e9f8..2f779f8f 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -63,40 +63,60 @@ func (b *Server) AddPeer(peer Peer) (err error) { }) } -func (b *Server) getPath(ip net.IP) *api.Path { - var pfxLen uint32 = 32 - if ip.To4() == nil { - if !b.c.IPv6 { - return nil - } - - pfxLen = 128 - } - - //nolint - nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ - Prefix: ip.String(), - PrefixLen: pfxLen, - }) +func (b *Server) getPath(ip net.IP) (path *api.Path) { + isV6 := ip.To4() == nil //nolint - a1, _ := ptypes.MarshalAny(&api.OriginAttribute{ + originAttr, _ := ptypes.MarshalAny(&api.OriginAttribute{ Origin: 0, }) - //nolint - a2, _ := ptypes.MarshalAny(&api.NextHopAttribute{ - NextHop: "0.0.0.0", // gobgp will fill this - }) - - return &api.Path{ - Family: &api.Family{ - Afi: api.Family_AFI_IP, + if !isV6 { + //nolint + nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: ip.String(), + PrefixLen: 32, + }) + + //nolint + nhAttr, _ := ptypes.MarshalAny(&api.NextHopAttribute{ + NextHop: "0.0.0.0", // gobgp will fill this + }) + + path = &api.Path{ + Family: &api.Family{ + Afi: api.Family_AFI_IP, + Safi: api.Family_SAFI_UNICAST, + }, + Nlri: nlri, + Pattrs: []*any.Any{originAttr, nhAttr}, + } + } else { + //nolint + nlri, _ := ptypes.MarshalAny(&api.IPAddressPrefix{ + Prefix: ip.String(), + PrefixLen: 128, + }) + + v6Family := &api.Family{ + Afi: api.Family_AFI_IP6, Safi: api.Family_SAFI_UNICAST, - }, - Nlri: nlri, - Pattrs: []*any.Any{a1, a2}, + } + + //nolint + mpAttr, _ := ptypes.MarshalAny(&api.MpReachNLRIAttribute{ + Family: v6Family, + NextHops: []string{"::"}, // gobgp will fill this + Nlris: []*any.Any{nlri}, + }) + + path = &api.Path{ + Family: v6Family, + Nlri: nlri, + Pattrs: []*any.Any{originAttr, mpAttr}, + } } + return } // ParseBGPPeerConfig - take a string and parses it into an array of peers From 95ae62e9eb638df7c571513a702043f21f42c2af Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Fri, 6 Jan 2023 22:46:12 +0800 Subject: [PATCH 320/542] bgp: Remove unused Config fields Signed-off-by: zyxwvu Shi --- pkg/bgp/types.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/bgp/types.go b/pkg/bgp/types.go index 2eaad2bc..e97bc8c8 100644 --- a/pkg/bgp/types.go +++ b/pkg/bgp/types.go @@ -14,12 +14,10 @@ type Peer struct { type Config struct { AS uint32 RouterID string - NextHop string SourceIP string SourceIF string Peers []Peer - IPv6 bool } // Server manages a server object From b83a9938057e9a11f6207aa80a8b2f55b47da887 Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Fri, 6 Jan 2023 23:10:39 +0800 Subject: [PATCH 321/542] bgp: Allow IPv6 BGP peer to be specified with brackets Ability to specify BGP port is removed, for two reasons: 1. IPv6 peer addresses contain colons, and the SpiltN func breaks IPv6 addresses. 2. Typical network devices do not allow changing BGP port, so this is rarely used. Signed-off-by: zyxwvu Shi --- pkg/bgp/peers.go | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 2f779f8f..b931bc56 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -14,16 +14,6 @@ import ( // AddPeer will add peers to the BGP configuration func (b *Server) AddPeer(peer Peer) (err error) { - port := 179 - - if t := strings.SplitN(peer.Address, ":", 2); len(t) == 2 { - peer.Address = t[0] - - if port, err = strconv.Atoi(t[1]); err != nil { - return fmt.Errorf("unable to parse port '%s' as int: %s", t[1], err) - } - } - p := &api.Peer{ Conf: &api.PeerConf{ NeighborAddress: peer.Address, @@ -46,7 +36,7 @@ func (b *Server) AddPeer(peer Peer) (err error) { Transport: &api.Transport{ MtuDiscovery: true, RemoteAddress: peer.Address, - RemotePort: uint32(port), + RemotePort: uint32(179), }, } @@ -127,10 +117,30 @@ func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) { } for x := range peers { - peer := strings.Split(peers[x], ":") + peerStr := peers[x] + if peerStr == "" { + continue + } + isV6Peer := peerStr[0] == '[' + + address := "" + if isV6Peer { + addressEndPos := strings.IndexByte(peerStr, ']') + if addressEndPos == -1 { + return nil, fmt.Errorf("no matching ] found for IPv6 BGP Peer") + } + address = peerStr[1:addressEndPos] + peerStr = peerStr[addressEndPos+1:] + } + + peer := strings.Split(peerStr, ":") if len(peer) != 4 { return nil, fmt.Errorf("BGP Peer configuration format error :::") } + if !isV6Peer { + address = peer[0] + } + ASNumber, err := strconv.Atoi(peer[1]) if err != nil { return nil, fmt.Errorf("BGP Peer AS format error [%s]", peer[1]) @@ -142,7 +152,7 @@ func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) { } peerConfig := Peer{ - Address: peer[0], + Address: address, AS: uint32(ASNumber), Password: peer[2], MultiHop: multiHop, From 1dfda79af81c9a07ddc9ad462c37952d9b3d003c Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Sun, 8 Jan 2023 00:50:45 +0800 Subject: [PATCH 322/542] bgp: Make password and multiHop params optional Also fix a CodeQL alert. Signed-off-by: zyxwvu Shi --- pkg/bgp/peers.go | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index b931bc56..640c88bc 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -134,27 +134,36 @@ func ParseBGPPeerConfig(config string) (bgpPeers []Peer, err error) { } peer := strings.Split(peerStr, ":") - if len(peer) != 4 { - return nil, fmt.Errorf("BGP Peer configuration format error :::") + if len(peer) < 2 { + return nil, fmt.Errorf("mandatory peering params : incomplete") } + if !isV6Peer { address = peer[0] } - ASNumber, err := strconv.Atoi(peer[1]) + ASNumber, err := strconv.ParseUint(peer[1], 10, 32) if err != nil { return nil, fmt.Errorf("BGP Peer AS format error [%s]", peer[1]) + } + password := "" + if len(peer) >= 3 { + password = peer[2] } - multiHop, err := strconv.ParseBool(peer[3]) - if err != nil { - return nil, fmt.Errorf("BGP MultiHop format error (true/false) [%s]", peer[1]) + + multiHop := false + if len(peer) >= 4 { + multiHop, err = strconv.ParseBool(peer[3]) + if err != nil { + return nil, fmt.Errorf("BGP MultiHop format error (true/false) [%s]", peer[1]) + } } peerConfig := Peer{ Address: address, AS: uint32(ASNumber), - Password: peer[2], + Password: password, MultiHop: multiHop, } From d01903194b596d77076f939e289fcb13b1e0d3f2 Mon Sep 17 00:00:00 2001 From: zyxwvu Shi Date: Sun, 8 Jan 2023 01:08:49 +0800 Subject: [PATCH 323/542] doc: Update bgp_peers description Signed-off-by: zyxwvu Shi --- docs/flags/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 5a99a677..613b3786 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -57,7 +57,7 @@ These environment variables are usually part of a `kube-vip` manifest and used w More environment variables can be read through the `pkg/kubevip/config_envvar.go` file. | Category | Environment Variable | Usage | Notes | -| ------------------- | ---------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------- | +| ------------------- | ---------------------- |-------------------------------------------------------------|---------------------------------------------------------------------------------| | **Troubleshooting** | | | | | | `vip_loglevel` | default 4 | Set to `5` for debugging logs | | **Mode** | | | | @@ -85,7 +85,7 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `bgp_routerid` | `` | Typically the address of the local node | | | `bgp_routerinterface` | Interface name | Used to associate the `routerID` with the control plane's interface. | | | `bgp_as` | default 65000 | The AS we peer from | -| | `bgp_peers` | `` | Comma separated list of BGP peers | +| | `bgp_peers` | `` | Comma separated list of BGP peers (IPv6 addresses should be enclosed with `[]`) | | | `bgp_peeraddress` | `` | Address of a single BGP Peer | | | `bgp_peeras` | default 65000 | AS of a single BGP Peer | | | `bgp_peerpass` | "" | Password to work with a single BGP Peer | From af5860633b6a509052f9898fe60521700c364d2b Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Couaillier Date: Mon, 16 Jan 2023 16:35:49 +0000 Subject: [PATCH 324/542] adding iptables-wrappers script to entrypoint Signed-off-by: Pierre-Antoine Couaillier --- Dockerfile_iptables | 7 ++++++- entrypoint_iptables.sh | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 entrypoint_iptables.sh diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 01e236b7..ff1f003c 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -16,4 +16,9 @@ FROM alpine:3.16.2 RUN apk add --no-cache iptables # Add kube-vip binary COPY --from=dev /src/kube-vip / -ENTRYPOINT ["/kube-vip"] +COPY /entrypoint_iptables.sh / +# Adding iptables-wrapper-installer from https://github.com/kubernetes-sigs/iptables-wrappers +ADD https://raw.githubusercontent.com/kubernetes-sigs/iptables-wrappers/v2/iptables-wrapper-installer.sh / +RUN chmod 755 /entrypoint_iptables.sh /iptables-wrapper-installer.sh + +ENTRYPOINT ["/entrypoint_iptables.sh"] diff --git a/entrypoint_iptables.sh b/entrypoint_iptables.sh new file mode 100644 index 00000000..f55773e1 --- /dev/null +++ b/entrypoint_iptables.sh @@ -0,0 +1,6 @@ +#!/bin/sh +echo "Executing /iptables-wrapper-installer.sh to configure iptables ..." +/iptables-wrapper-installer.sh + +echo "Executing /kube-vip $@" +exec /kube-vip "$@" From 631960fb0c304c82d9ce25ff3fcf5f09846eef2a Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 16 Jan 2023 20:57:34 +0000 Subject: [PATCH 325/542] Keep watching services after losing leadership Signed-off-by: Dan Finneran --- pkg/manager/servicesLeader.go | 2 ++ pkg/manager/watch_endpoints.go | 39 ++++++++++++++++++++++------------ pkg/manager/watch_services.go | 8 +++---- testing/nodes | 10 ++++----- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 5cd91302..46ad0275 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -72,6 +72,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. OnStartedLeading: func(ctx context.Context) { // Mark this service as active (as we've started leading) // we run this in background as it's blocking + wg.Add(1) go func() { if err := sm.syncServices(ctx, service, wg); err != nil { log.Errorln(err) @@ -100,5 +101,6 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. }, }, }) + log.Infof("[services election] for service [%s] stopping", service.Name) return nil } diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 202d4380..ea99cfc0 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -22,7 +22,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser var cancel context.CancelFunc var endpointContext context.Context endpointContext, cancel = context.WithCancel(context.Background()) - + var electionActive bool defer cancel() opts := metav1.ListOptions{ @@ -71,6 +71,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser cancel() return fmt.Errorf("unable to parse Kubernetes services from API watcher") } + // Build endpoints var localendpoints []string for subset := range ep.Subsets { for address := range ep.Subsets[subset].Addresses { @@ -83,27 +84,19 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } } - log.Debugf("[%d], endpoints, last known good [%s]", len(localendpoints), lastKnownGoodEndpoint) - // Check how many local endpoints exist (should ideally be 1) + log.Debugf("[endpoint watcher] local endpoint(s) [%d], last known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, electionActive) + stillExists := false if len(localendpoints) != 0 { if lastKnownGoodEndpoint == "" { lastKnownGoodEndpoint = localendpoints[0] // Create new context - endpointContext, cancel = context.WithCancel(context.Background()) //nolint:govet - defer cancel() //nolint + //endpointContext, cancel = context.WithCancel(context.Background()) //nolint:govet + //defer cancel() //nolint wg.Add(1) if service.Annotations["kube-vip.io/egress"] == "true" { service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint } - go func() { - err = sm.StartServicesLeaderElection(endpointContext, service, wg) - if err != nil { - log.Error(err) - } - wg.Wait() - }() - } else { // check out previous endpoint exists for x := range localendpoints { @@ -118,6 +111,26 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser //rw.Stop() } } + if !electionActive { + go func() { + // This is a blocking function, that will restart (in the event of failure) + for { + // if the context isn't cancelled restart + if endpointContext.Err() != context.Canceled { + electionActive = true + err = sm.StartServicesLeaderElection(endpointContext, service, wg) + electionActive = false + if err != nil { + log.Error(err) + } + } else { + electionActive = false + break + } + } + wg.Done() + }() + } } else { if lastKnownGoodEndpoint != "" { lastKnownGoodEndpoint = "" diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index a36429dc..6639d955 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -118,7 +118,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - //log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Debugf("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) // Scenarios: // 1. @@ -138,7 +138,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } - wg.Wait() + wg.Done() } }() // We're now watching this service @@ -150,7 +150,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } - wg.Wait() + wg.Done() }() } } else { @@ -158,7 +158,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } - wg.Wait() + wg.Done() } } diff --git a/testing/nodes b/testing/nodes index 4d23b100..3ecc09ec 100644 --- a/testing/nodes +++ b/testing/nodes @@ -4,8 +4,8 @@ #NODE03=k8s03.fnnrn.me #NODE04=k8s04.fnnrn.me #NODE05=k8s05.fnnrn.me -NODE01=192.168.0.31 -NODE02=192.168.0.32 -NODE03=192.168.0.33 -NODE04=192.168.0.34 -NODE05=192.168.0.35 +NODE01=192.168.0.191 +NODE02=192.168.0.192 +NODE03=192.168.0.193 +NODE04=192.168.0.194 +NODE05=192.168.0.195 From 1b4bba08006b07865f43ad0b8e157809ff4146ba Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 19 Jan 2023 15:10:21 +0000 Subject: [PATCH 326/542] New Release --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f073f4d..2a0bc672 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.7 +VERSION := v0.5.8 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From 7ad4e27084218ddf8ff6e8e8c9077e2236ba22eb Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 2 Feb 2023 10:30:35 +0000 Subject: [PATCH 327/542] Fixes to negative waitgroup Signed-off-by: Dan Finneran --- pkg/manager/watch_services.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index a36429dc..5396f6c4 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -118,7 +118,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - //log.Infof("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Debugf("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) // Scenarios: // 1. @@ -134,31 +134,36 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context go func() { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Add Endpoint watcher + wg.Add(1) err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) if err != nil { log.Error(err) } - wg.Wait() + wg.Done() } }() // We're now watching this service watchedService[string(svc.UID)] = true } } else { + // Increment the waitGroup before the service Func is called (Done is completed in there) + wg.Add(1) go func() { err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) if err != nil { log.Error(err) } - wg.Wait() + wg.Done() }() } } else { + // Increment the waitGroup before the service Func is called (Done is completed in there) + wg.Add(1) err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) if err != nil { log.Error(err) } - wg.Wait() + wg.Done() } } From 9f728278fd361aafa260b50735c40a285a0a8b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petar=20Obradovi=C4=87?= Date: Thu, 2 Feb 2023 11:50:52 +0100 Subject: [PATCH 328/542] Fix service deletion not registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Petar Obradović --- pkg/manager/watch_services.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 6639d955..005c5003 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -160,7 +160,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } wg.Done() } - + activeService[string(svc.UID)] = true } case watch.Deleted: svc, ok := event.Object.(*v1.Service) From 3a8a94fcc9b19ec085449d31371a9c0d2cdef08e Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 8 Feb 2023 12:58:44 +0000 Subject: [PATCH 329/542] Adds services testing and fixes missing context Signed-off-by: Dan Finneran --- pkg/manager/watch_services.go | 11 +- testing/e2e/services/services.go | 216 +++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 testing/e2e/services/services.go diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 5396f6c4..ce47f548 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -17,9 +17,14 @@ import ( watchtools "k8s.io/client-go/tools/watch" ) +// TODO: Fix the naming of these contexts + // activeServiceLoadBalancer keeps track of services that already have a leaderElection in place var activeServiceLoadBalancer map[string]context.Context +// activeServiceLoadBalancer keeps track of services that already have a leaderElection in place +var activeServiceLoadBalancerCancel map[string]func() + // activeService keeps track of services that already have a leaderElection in place var activeService map[string]bool @@ -28,6 +33,7 @@ var watchedService map[string]bool func init() { // Set up the caches for monitoring existing active or watched services + activeServiceLoadBalancerCancel = make(map[string]func()) activeServiceLoadBalancer = make(map[string]context.Context) activeService = make(map[string]bool) watchedService = make(map[string]bool) @@ -124,7 +130,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // 1. if !activeService[string(svc.UID)] { wg.Add(1) - activeServiceLoadBalancer[string(svc.UID)] = context.TODO() + activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) // Background the services election if sm.config.EnableServicesElection { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { @@ -189,7 +195,8 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } - activeServiceLoadBalancer[string(svc.UID)].Done() + // Calls the cancel function of the context + activeServiceLoadBalancerCancel[string(svc.UID)]() activeService[string(svc.UID)] = false watchedService[string(svc.UID)] = false diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go new file mode 100644 index 00000000..42513465 --- /dev/null +++ b/testing/e2e/services/services.go @@ -0,0 +1,216 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "path/filepath" + "time" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + + "github.com/kube-vip/kube-vip/pkg/k8s" + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + watchtools "k8s.io/client-go/tools/watch" +) + +// Methodology + +// 1. Create a deployment +// 2. Expose the deployment + +func main() { + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") + clientset, err := k8s.NewClientset(homeConfigPath, false, "") + if err != nil { + log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) + } + log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + + d := "kube-vip-deploy" + s := "kube-vip-service" + err = createDeployment(ctx, d, clientset) + if err != nil { + log.Fatal(err) + } + err = createService(ctx, s, clientset) + if err != nil { + log.Error(err) + } + + log.Warnf("🧹 deleting Service [%s]", s) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + log.Warnf("🧹 deleting Deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + d = "kube-vip-deploy-leader" + err = createDeployment(ctx, d, clientset) + if err != nil { + log.Fatal(err) + } + for i := 1; i < 5; i++ { + err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset) + if err != nil { + log.Fatal(err) + } + } + for i := 1; i < 5; i++ { + log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + } + log.Warnf("🧹 deleting deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } +} + +func createDeployment(ctx context.Context, name string, clientset *kubernetes.Clientset) error { + replicas := int32(2) + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "kube-vip", + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "kube-vip", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "web", + Image: "nginx:1.14.2", + Ports: []v1.ContainerPort{ + { + Name: "http", + Protocol: v1.ProtocolTCP, + ContainerPort: 80, + }, + }, + }, + }, + }, + }, + }, + } + result, err := clientset.AppsV1().Deployments(v1.NamespaceDefault).Create(ctx, deployment, metav1.CreateOptions{}) + if err != nil { + return err + } + + log.Infof("📝 created deployment [%s]", result.GetObjectMeta().GetName()) + return nil +} + +func createService(ctx context.Context, name string, clientset *kubernetes.Clientset) error { + service := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "default", + Labels: map[string]string{ + "app": "kube-vip", + }, + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Port: 80, + Protocol: v1.ProtocolTCP, + }, + }, + Selector: map[string]string{ + "app": "kube-vip", + }, + ClusterIP: "", + Type: v1.ServiceTypeLoadBalancer, + }, + } + log.Infof("🌍 creating service [%s]", service.Name) + _, err := clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, service, metav1.CreateOptions{}) + if err != nil { + log.Fatal(err) + } + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return clientset.CoreV1().Services(v1.NamespaceDefault).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + log.Fatal(err) + } + ch := rw.ResultChan() + + ready := false + testAddress := "" + // Used for tracking an active endpoint / pod + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + ready = true + testAddress = svc.Status.LoadBalancer.Ingress[0].IP + } + } + default: + + } + if ready { + break + } + } + var Client http.Client + var backoffSchedule = []time.Duration{ + 1 * time.Second, + 3 * time.Second, + 10 * time.Second, + } + + for _, backoff := range backoffSchedule { + _, err = Client.Get(fmt.Sprintf("http://%s", testAddress)) + if err == nil { + log.Info("🕸️ succesfully retrieved web data") + return nil + } + log.Errorf("⏰ retry in [%v] : [%+v]", backoff, err) + time.Sleep(backoff) + } + + return fmt.Errorf(" web retrieval timeout ") +} From aa296d8211f3b3dc98d6995ddc8eb1575915c6b7 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 8 Feb 2023 13:57:01 +0000 Subject: [PATCH 330/542] Fixes to linting Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 42513465..d451d12e 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -203,9 +203,10 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien } for _, backoff := range backoffSchedule { + //nolint _, err = Client.Get(fmt.Sprintf("http://%s", testAddress)) if err == nil { - log.Info("🕸️ succesfully retrieved web data") + log.Info("🕸️ successfully retrieved web data") return nil } log.Errorf("⏰ retry in [%v] : [%+v]", backoff, err) From a66b84a77e874ba8bedc9c76a968def3d56f1f9c Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 8 Feb 2023 14:05:37 +0000 Subject: [PATCH 331/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2a0bc672..e5753f5b 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.8 +VERSION := v0.5.9 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From d93e0cdf9cf4acff7d40b2172a283b674d7079f8 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 10 Feb 2023 16:36:20 +0000 Subject: [PATCH 332/542] Ensures a leadership will be restarted Signed-off-by: Dan Finneran --- pkg/manager/watch_endpoints.go | 86 ++++---- pkg/manager/watch_services.go | 8 +- testing/e2e/services/services.go | 364 +++++++++++++++++++++++++++---- 3 files changed, 365 insertions(+), 93 deletions(-) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index ea99cfc0..e81cd2f0 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -19,10 +19,8 @@ import ( func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { log.Infof("[endpoint] watching for service [%s] in namespace [%s]", service.Name, service.Namespace) // Use a restartable watcher, as this should help in the event of etcd or timeout issues - var cancel context.CancelFunc - var endpointContext context.Context - endpointContext, cancel = context.WithCancel(context.Background()) - var electionActive bool + leaderContext, cancel := context.WithCancel(context.Background()) + var leaderElectionActive bool defer cancel() opts := metav1.ListOptions{ @@ -41,6 +39,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser exitFunction := make(chan struct{}) go func() { select { + case <-ctx.Done(): + log.Debug("[endpoint] context cancelled") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return case <-sm.shutdownChan: log.Debug("[endpoint] shutdown called") // Stop the retry watcher @@ -84,59 +89,68 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } } - log.Debugf("[endpoint watcher] local endpoint(s) [%d], last known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, electionActive) + log.Debugf("[endpoint watcher] local endpoint(s) [%d], last known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + + // Find out if we have any local endpoints + // if out endpoint is empty then populate it + // if not, go through the endpoints and see if ours still exists + // If we have a local endpoint then begin the leader Election, unless it's already running + // - stillExists := false + // Check that we have local endpoints if len(localendpoints) != 0 { - if lastKnownGoodEndpoint == "" { - lastKnownGoodEndpoint = localendpoints[0] - // Create new context - //endpointContext, cancel = context.WithCancel(context.Background()) //nolint:govet - //defer cancel() //nolint - wg.Add(1) - if service.Annotations["kube-vip.io/egress"] == "true" { - service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint - } - } else { + // if we haven't populated one, then do so + if lastKnownGoodEndpoint != "" { + // check out previous endpoint exists + stillExists := false + for x := range localendpoints { if localendpoints[x] == lastKnownGoodEndpoint { stillExists = true } } - if stillExists { - break - } else { + // If the last endpoint no longer exists, we cancel our leader Election + if !stillExists && leaderElectionActive { cancel() - //rw.Stop() } + + } else { + lastKnownGoodEndpoint = localendpoints[0] + } + + // Set the service accordingly + if service.Annotations["kube-vip.io/egress"] == "true" { + service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint } - if !electionActive { + + if !leaderElectionActive { go func() { + leaderContext, cancel = context.WithCancel(context.Background()) + // This is a blocking function, that will restart (in the event of failure) for { // if the context isn't cancelled restart - if endpointContext.Err() != context.Canceled { - electionActive = true - err = sm.StartServicesLeaderElection(endpointContext, service, wg) - electionActive = false + if leaderContext.Err() != context.Canceled { + leaderElectionActive = true + err = sm.StartServicesLeaderElection(leaderContext, service, wg) if err != nil { log.Error(err) } + leaderElectionActive = false } else { - electionActive = false + leaderElectionActive = false break } } - wg.Done() }() } } else { + // If there are no local endpoints, and we had one then remove it and stop the leaderElection if lastKnownGoodEndpoint != "" { lastKnownGoodEndpoint = "" cancel() - //rw.Stop() - //return nil + leaderElectionActive = false } } @@ -148,7 +162,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser case watch.Error: errObject := apierrors.FromObject(event.Object) statusErr, _ := errObject.(*apierrors.StatusError) - log.Errorf("endpoint -> %v", statusErr) + log.Errorf("[endpoint] -> %v", statusErr) } } close(exitFunction) @@ -165,11 +179,6 @@ func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1. return err } - // id, err := os.Hostname() - // if err != nil { - // return err - // } - currentServiceCopy := currentService.DeepCopy() if currentServiceCopy.Annotations == nil { currentServiceCopy.Annotations = make(map[string]string) @@ -182,13 +191,6 @@ func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1. log.Errorf("Error updating Service Spec [%s] : %v", currentServiceCopy.Name, err) return err } - - // updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} - // _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - // if err != nil { - // log.Errorf("Error updating Service %s/%s Status: %v", i.ServiceNamespace, i.ServiceName, err) - // return err - // } return nil }) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index ce47f548..4a004bcd 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -69,12 +69,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context go func() { select { case <-sm.shutdownChan: - log.Debug("[endpoint] shutdown called") + log.Debug("[services] shutdown called") // Stop the retry watcher rw.Stop() return case <-exitFunction: - log.Debug("[endpoint] function ending") + log.Debug("[services] function ending") // Stop the retry watcher rw.Stop() return @@ -124,7 +124,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - log.Debugf("service [%s] has been added/modified it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) + log.Debugf("service [%s] has been added/modified with addresses [%s] and is active [%t]", svc.Name, svc.Spec.LoadBalancerIP, activeService[string(svc.UID)]) // Scenarios: // 1. @@ -171,7 +171,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } wg.Done() } - + activeService[string(svc.UID)] = true } case watch.Deleted: svc, ok := event.Object.(*v1.Service) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index d451d12e..b47a163f 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -26,6 +26,16 @@ import ( // 2. Expose the deployment func main() { + _, ignore_simple := os.LookupEnv("IGNORE_SIMPLE") + _, ignore_deployments := os.LookupEnv("IGNORE_DEPLOY") + _, ignore_leaderFailover := os.LookupEnv("IGNORE_LEADER") + _, ignore_leaderActive := os.LookupEnv("IGNORE_ACTIVE") + _, ignore_localDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") + + d := "kube-vip-deploy" + s := "kube-vip-service" + l := "kube-vip-deploy-leader" + ctx, cancel := context.WithCancel(context.TODO()) defer cancel() homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") @@ -35,56 +45,149 @@ func main() { } log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) - d := "kube-vip-deploy" - s := "kube-vip-service" - err = createDeployment(ctx, d, clientset) - if err != nil { - log.Fatal(err) - } - err = createService(ctx, s, clientset) - if err != nil { - log.Error(err) - } + if !ignore_simple { + // Simple Deployment test + log.Infof("🧪 ---> simple deployment <---") + err = createDeployment(ctx, d, 2, clientset) + if err != nil { + log.Fatal(err) + } + _, _, err = createService(ctx, s, clientset, false) + if err != nil { + log.Error(err) + } - log.Warnf("🧹 deleting Service [%s]", s) - err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) - if err != nil { - log.Fatal(err) - } + log.Warnf("🧹 deleting Service [%s]", s) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } - log.Warnf("🧹 deleting Deployment [%s]", d) - err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) - if err != nil { - log.Fatal(err) + log.Warnf("🧹 deleting Deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } } + if !ignore_deployments { + // Multiple deployment tests + log.Infof("🧪 ---> multiple deployments <---") - d = "kube-vip-deploy-leader" - err = createDeployment(ctx, d, clientset) - if err != nil { - log.Fatal(err) + err = createDeployment(ctx, l, 2, clientset) + if err != nil { + log.Fatal(err) + } + for i := 1; i < 5; i++ { + _, _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, false) + if err != nil { + log.Fatal(err) + } + } + for i := 1; i < 5; i++ { + log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + } + log.Warnf("🧹 deleting deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, l, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } } - for i := 1; i < 5; i++ { - err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset) + if !ignore_leaderFailover { + // Failover tests + log.Infof("🧪 ---> leader failover deployment (local policy) <---") + + err = createDeployment(ctx, d, 2, clientset) + if err != nil { + log.Fatal(err) + } + _, leader, err := createService(ctx, s, clientset, true) + if err != nil { + log.Error(err) + } + + err = leaderFailover(ctx, &s, &leader, clientset) + if err != nil { + log.Error(err) + } + + log.Warnf("🧹 deleting Service [%s]", s) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + log.Warnf("🧹 deleting Deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } } - for i := 1; i < 5; i++ { - log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) - err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) + + if !ignore_leaderActive { + // pod Failover tests + log.Infof("🧪 ---> active pod failover deployment (local policy) <---") + + err = createDeployment(ctx, d, 1, clientset) + if err != nil { + log.Fatal(err) + } + _, leader, err := createService(ctx, s, clientset, true) + if err != nil { + log.Error(err) + } + + err = podFailover(ctx, &s, &leader, clientset) + if err != nil { + log.Error(err) + } + + log.Warnf("🧹 deleting Service [%s]", s) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + log.Warnf("🧹 deleting Deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } } - log.Warnf("🧹 deleting deployment [%s]", d) - err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) - if err != nil { - log.Fatal(err) + if !ignore_localDeploy { + // Multiple deployment tests + log.Infof("🧪 ---> multiple deployments (local policy) <---") + + err = createDeployment(ctx, l, 2, clientset) + if err != nil { + log.Fatal(err) + } + for i := 1; i < 5; i++ { + _, _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, true) + if err != nil { + log.Fatal(err) + } + } + for i := 1; i < 5; i++ { + log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + } + log.Warnf("🧹 deleting deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, l, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } } } -func createDeployment(ctx context.Context, name string, clientset *kubernetes.Clientset) error { - replicas := int32(2) +func createDeployment(ctx context.Context, name string, replica int, clientset *kubernetes.Clientset) error { + replicas := int32(replica) deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -105,7 +208,7 @@ func createDeployment(ctx context.Context, name string, clientset *kubernetes.Cl Spec: v1.PodSpec{ Containers: []v1.Container{ { - Name: "web", + Name: "kube-vip-web", Image: "nginx:1.14.2", Ports: []v1.ContainerPort{ { @@ -129,7 +232,7 @@ func createDeployment(ctx context.Context, name string, clientset *kubernetes.Cl return nil } -func createService(ctx context.Context, name string, clientset *kubernetes.Clientset) error { +func createService(ctx context.Context, name string, clientset *kubernetes.Clientset, localTraffic bool) (string, string, error) { service := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -152,6 +255,9 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien Type: v1.ServiceTypeLoadBalancer, }, } + if localTraffic { + service.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal + } log.Infof("🌍 creating service [%s]", service.Name) _, err := clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, service, metav1.CreateOptions{}) if err != nil { @@ -170,6 +276,7 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien ready := false testAddress := "" + currentLeader := "" // Used for tracking an active endpoint / pod for event := range ch { @@ -186,6 +293,7 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) ready = true testAddress = svc.Status.LoadBalancer.Ingress[0].IP + currentLeader = svc.Annotations["kube-vip.io/vipHost"] } } default: @@ -195,23 +303,185 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien break } } - var Client http.Client - var backoffSchedule = []time.Duration{ - 1 * time.Second, - 3 * time.Second, - 10 * time.Second, + err = httpTest(testAddress) + if err == nil { + return testAddress, currentLeader, nil } + return "", "", fmt.Errorf("web retrieval timeout ") +} - for _, backoff := range backoffSchedule { +func httpTest(address string) error { + Client := http.Client{ + Timeout: 1 * time.Second, + } + var err error + for i := 0; i < 5; i++ { //nolint - _, err = Client.Get(fmt.Sprintf("http://%s", testAddress)) + + _, err = Client.Get(fmt.Sprintf("http://%s", address)) if err == nil { - log.Info("🕸️ successfully retrieved web data") + log.Infof("🕸️ successfully retrieved web data in [%ds]", i) return nil } - log.Errorf("⏰ retry in [%v] : [%+v]", backoff, err) - time.Sleep(backoff) + time.Sleep(time.Second) + } + return err +} + +func leaderFailover(ctx context.Context, name, leaderNode *string, clientset *kubernetes.Clientset) error { + go func() { + log.Infof("💀 killing leader five times") + for i := 0; i < 5; i++ { + p, err := clientset.CoreV1().Pods("kube-system").List(ctx, metav1.ListOptions{}) + if err != nil { + log.Fatal(err) + } + + for x := range p.Items { + if p.Items[x].Spec.NodeName == *leaderNode { + if p.Items[x].Spec.Containers[0].Name == "kube-vip" { + err = clientset.CoreV1().Pods("kube-system").Delete(ctx, p.Items[x].Name, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + log.Infof("🔪 leader pod [%s] has been deleted", p.Items[x].Name) + } + } + } + time.Sleep(time.Second * 5) + } + }() + + log.Infof("👀 service [%s] for updates", *name) + + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return clientset.CoreV1().Services(v1.NamespaceDefault).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + log.Fatal(err) } + ch := rw.ResultChan() - return fmt.Errorf(" web retrieval timeout ") + go func() { + time.Sleep(time.Second * 30) + rw.Stop() + }() + + // Used for tracking an active endpoint / pod + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == *name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + } + } + case watch.Modified: + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == *name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔍 updated with address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + *leaderNode = svc.Annotations["kube-vip.io/vipHost"] + } + } + default: + + } + } + return nil +} + +func podFailover(ctx context.Context, name, leaderNode *string, clientset *kubernetes.Clientset) error { + go func() { + log.Infof("💀 killing active pod five times") + for i := 0; i < 5; i++ { + p, err := clientset.CoreV1().Pods(v1.NamespaceDefault).List(ctx, metav1.ListOptions{}) + if err != nil { + log.Fatal(err) + } + found := false + for x := range p.Items { + if p.Items[x].Spec.NodeName == *leaderNode { + if p.Items[x].Spec.Containers[0].Name == "kube-vip-web" { + found = true + err = clientset.CoreV1().Pods(v1.NamespaceDefault).Delete(ctx, p.Items[x].Name, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + log.Infof("🔪 active pod [%s] on [%s] has been deleted", p.Items[x].Name, p.Items[x].Spec.NodeName) + } + } + } + if !found { + log.Warnf("😱 No Pod found on [%s]", *leaderNode) + } + time.Sleep(time.Second * 5) + } + }() + + log.Infof("👀 service [%s] for updates", *name) + + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return clientset.CoreV1().Services(v1.NamespaceDefault).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + log.Fatal(err) + } + ch := rw.ResultChan() + + go func() { + time.Sleep(time.Second * 30) + rw.Stop() + }() + + // Used for tracking an active endpoint / pod + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == *name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + } + } + case watch.Modified: + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == *name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔍 updated with address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + *leaderNode = svc.Annotations["kube-vip.io/vipHost"] + } + } + default: + + } + } + return nil } From 9ab8b909bf5495b8e54ac68193892df5cb5b4e99 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 10 Feb 2023 16:41:48 +0000 Subject: [PATCH 333/542] linter fix Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index b47a163f..a1865635 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -1,3 +1,5 @@ +// !codeanalysis + package main import ( From b62b331be8e2fe821b09e435952b1ccdaa40f836 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 10 Feb 2023 18:02:46 +0000 Subject: [PATCH 334/542] more linting Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index a1865635..b81d4976 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -1,5 +1,4 @@ -// !codeanalysis - +//nolint:govet package main import ( From 71b490d735a2867122b54545d56dbbb50e87f1f3 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 10 Feb 2023 18:09:55 +0000 Subject: [PATCH 335/542] stupid linter Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 48 +++++++++++++++++--------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index b81d4976..83ede717 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -27,11 +27,11 @@ import ( // 2. Expose the deployment func main() { - _, ignore_simple := os.LookupEnv("IGNORE_SIMPLE") - _, ignore_deployments := os.LookupEnv("IGNORE_DEPLOY") - _, ignore_leaderFailover := os.LookupEnv("IGNORE_LEADER") - _, ignore_leaderActive := os.LookupEnv("IGNORE_ACTIVE") - _, ignore_localDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") + _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") + _, ignoreDeployments := os.LookupEnv("IGNORE_DEPLOY") + _, ignoreLeaderFailover := os.LookupEnv("IGNORE_LEADER") + _, ignoreLeaderActive := os.LookupEnv("IGNORE_ACTIVE") + _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") d := "kube-vip-deploy" s := "kube-vip-service" @@ -46,14 +46,14 @@ func main() { } log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) - if !ignore_simple { + if !ignoreSimple { // Simple Deployment test log.Infof("🧪 ---> simple deployment <---") err = createDeployment(ctx, d, 2, clientset) if err != nil { log.Fatal(err) } - _, _, err = createService(ctx, s, clientset, false) + _, err = createService(ctx, s, clientset, false) if err != nil { log.Error(err) } @@ -70,7 +70,7 @@ func main() { log.Fatal(err) } } - if !ignore_deployments { + if !ignoreDeployments { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments <---") @@ -79,7 +79,7 @@ func main() { log.Fatal(err) } for i := 1; i < 5; i++ { - _, _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, false) + _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, false) if err != nil { log.Fatal(err) } @@ -97,7 +97,7 @@ func main() { log.Fatal(err) } } - if !ignore_leaderFailover { + if !ignoreLeaderFailover { // Failover tests log.Infof("🧪 ---> leader failover deployment (local policy) <---") @@ -105,7 +105,7 @@ func main() { if err != nil { log.Fatal(err) } - _, leader, err := createService(ctx, s, clientset, true) + leader, err := createService(ctx, s, clientset, true) if err != nil { log.Error(err) } @@ -128,7 +128,7 @@ func main() { } } - if !ignore_leaderActive { + if !ignoreLeaderActive { // pod Failover tests log.Infof("🧪 ---> active pod failover deployment (local policy) <---") @@ -136,7 +136,7 @@ func main() { if err != nil { log.Fatal(err) } - _, leader, err := createService(ctx, s, clientset, true) + leader, err := createService(ctx, s, clientset, true) if err != nil { log.Error(err) } @@ -158,7 +158,7 @@ func main() { log.Fatal(err) } } - if !ignore_localDeploy { + if !ignoreLocalDeploy { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments (local policy) <---") @@ -167,7 +167,7 @@ func main() { log.Fatal(err) } for i := 1; i < 5; i++ { - _, _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, true) + _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, true) if err != nil { log.Fatal(err) } @@ -233,7 +233,7 @@ func createDeployment(ctx context.Context, name string, replica int, clientset * return nil } -func createService(ctx context.Context, name string, clientset *kubernetes.Clientset, localTraffic bool) (string, string, error) { +func createService(ctx context.Context, name string, clientset *kubernetes.Clientset, localTraffic bool) (string, error) { service := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -306,9 +306,9 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien } err = httpTest(testAddress) if err == nil { - return testAddress, currentLeader, nil + return currentLeader, nil } - return "", "", fmt.Errorf("web retrieval timeout ") + return "", fmt.Errorf("web retrieval timeout ") } func httpTest(address string) error { @@ -362,7 +362,7 @@ func leaderFailover(ctx context.Context, name, leaderNode *string, clientset *ku }, }) if err != nil { - log.Fatal(err) + return err } ch := rw.ResultChan() @@ -395,7 +395,10 @@ func leaderFailover(ctx context.Context, name, leaderNode *string, clientset *ku if svc.Name == *name { if len(svc.Status.LoadBalancer.Ingress) != 0 { log.Infof("🔍 updated with address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) - httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + err = httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + if err != nil { + return err + } *leaderNode = svc.Annotations["kube-vip.io/vipHost"] } } @@ -443,7 +446,7 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber }, }) if err != nil { - log.Fatal(err) + return err } ch := rw.ResultChan() @@ -476,7 +479,8 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber if svc.Name == *name { if len(svc.Status.LoadBalancer.Ingress) != 0 { log.Infof("🔍 updated with address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) - httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + err = httpTest(svc.Status.LoadBalancer.Ingress[0].IP) + log.Fatal(err) *leaderNode = svc.Annotations["kube-vip.io/vipHost"] } } From 285f4e514c8090e73a450702234d68916f0f21c9 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 10 Feb 2023 18:14:17 +0000 Subject: [PATCH 336/542] this should be it Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 83ede717..c3c09999 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -318,12 +318,13 @@ func httpTest(address string) error { var err error for i := 0; i < 5; i++ { //nolint + r, err := Client.Get(fmt.Sprintf("http://%s", address)) //nolint - _, err = Client.Get(fmt.Sprintf("http://%s", address)) if err == nil { log.Infof("🕸️ successfully retrieved web data in [%ds]", i) return nil } + r.Body.Close() time.Sleep(time.Second) } return err @@ -480,7 +481,9 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber if len(svc.Status.LoadBalancer.Ingress) != 0 { log.Infof("🔍 updated with address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) err = httpTest(svc.Status.LoadBalancer.Ingress[0].IP) - log.Fatal(err) + if err != nil { + log.Fatal(err) + } *leaderNode = svc.Annotations["kube-vip.io/vipHost"] } } From c10b4105b92f5496a163c9e38fffad2d1c3afc39 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 15 Feb 2023 13:52:25 +0000 Subject: [PATCH 337/542] Fixes and testing for endpoints Signed-off-by: Dan Finneran --- cmd/kube-vip.go | 5 ++++- pkg/manager/watch_endpoints.go | 16 ++++++++++++---- testing/e2e/services/services.go | 24 +++++++++++++++++------- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index d344bb59..2db5d4c6 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -210,7 +210,6 @@ var kubeVipManager = &cobra.Command{ Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { - log.Infof("Starting kube-vip.io [%s]", Release.Version) // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) if err != nil { @@ -220,6 +219,10 @@ var kubeVipManager = &cobra.Command{ // Set the logging level for all subsequent functions log.SetLevel(log.Level(initConfig.Logging)) + // Welome messages + log.Infof("Starting kube-vip.io [%s]", Release.Version) + log.Debugf("Build kube-vip.io [%s]", Release.Build) + // start prometheus server if initConfig.PrometheusHTTPServer != "" { go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{ diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index e81cd2f0..c6a69fed 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -76,11 +76,12 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser cancel() return fmt.Errorf("unable to parse Kubernetes services from API watcher") } + // Build endpoints var localendpoints []string for subset := range ep.Subsets { for address := range ep.Subsets[subset].Addresses { - + log.Debugf("[endpoint] %s", ep.Subsets[subset].Addresses[address].IP) // Check the node is populated if ep.Subsets[subset].Addresses[address].NodeName != nil { if id == *ep.Subsets[subset].Addresses[address].NodeName { @@ -89,7 +90,6 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } } - log.Debugf("[endpoint watcher] local endpoint(s) [%d], last known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -112,7 +112,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } // If the last endpoint no longer exists, we cancel our leader Election if !stillExists && leaderElectionActive { + log.Warnf("[endpoint] existing [%s] has been removed, restarting leaderElection", lastKnownGoodEndpoint) + // Stop the existing leaderElection cancel() + // Set our active endpoint to an existing one + lastKnownGoodEndpoint = localendpoints[0] + // disable last leaderElection flag + leaderElectionActive = false } } else { @@ -148,11 +154,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } else { // If there are no local endpoints, and we had one then remove it and stop the leaderElection if lastKnownGoodEndpoint != "" { - lastKnownGoodEndpoint = "" - cancel() + log.Warnf("[endpoint] existing [%s] has been removed, no remaining endpoints for leaderElection", lastKnownGoodEndpoint) + lastKnownGoodEndpoint = "" // reset endpoint + cancel() // stop services watcher leaderElectionActive = false } } + log.Debugf("[endpoint watcher] local endpoint(s) [%d], known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: // Close the goroutine that will end the retry watcher, then exit the endpoint watcher function diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index c3c09999..dff91905 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -32,6 +32,7 @@ func main() { _, ignoreLeaderFailover := os.LookupEnv("IGNORE_LEADER") _, ignoreLeaderActive := os.LookupEnv("IGNORE_ACTIVE") _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") + nodeTolerate := os.Getenv("NODE_TOLERATE") d := "kube-vip-deploy" s := "kube-vip-service" @@ -49,7 +50,7 @@ func main() { if !ignoreSimple { // Simple Deployment test log.Infof("🧪 ---> simple deployment <---") - err = createDeployment(ctx, d, 2, clientset) + err = createDeployment(ctx, d, nodeTolerate, 2, clientset) if err != nil { log.Fatal(err) } @@ -74,7 +75,7 @@ func main() { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments <---") - err = createDeployment(ctx, l, 2, clientset) + err = createDeployment(ctx, l, nodeTolerate, 2, clientset) if err != nil { log.Fatal(err) } @@ -101,7 +102,7 @@ func main() { // Failover tests log.Infof("🧪 ---> leader failover deployment (local policy) <---") - err = createDeployment(ctx, d, 2, clientset) + err = createDeployment(ctx, d, nodeTolerate, 2, clientset) if err != nil { log.Fatal(err) } @@ -132,7 +133,7 @@ func main() { // pod Failover tests log.Infof("🧪 ---> active pod failover deployment (local policy) <---") - err = createDeployment(ctx, d, 1, clientset) + err = createDeployment(ctx, d, nodeTolerate, 1, clientset) if err != nil { log.Fatal(err) } @@ -162,7 +163,7 @@ func main() { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments (local policy) <---") - err = createDeployment(ctx, l, 2, clientset) + err = createDeployment(ctx, l, nodeTolerate, 2, clientset) if err != nil { log.Fatal(err) } @@ -187,7 +188,7 @@ func main() { } } -func createDeployment(ctx context.Context, name string, replica int, clientset *kubernetes.Clientset) error { +func createDeployment(ctx context.Context, name, nodeName string, replica int, clientset *kubernetes.Clientset) error { replicas := int32(replica) deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ @@ -224,6 +225,10 @@ func createDeployment(ctx context.Context, name string, replica int, clientset * }, }, } + + if nodeName != "" { + deployment.Spec.Template.Spec.NodeName = nodeName + } result, err := clientset.AppsV1().Deployments(v1.NamespaceDefault).Create(ctx, deployment, metav1.CreateOptions{}) if err != nil { return err @@ -241,6 +246,9 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien Labels: map[string]string{ "app": "kube-vip", }, + // Annotations: map[string]string{//kube-vip.io/egress: "true" + // "kube-vip.io/egress":"true", + // }, }, Spec: v1.ServiceSpec{ Ports: []v1.ServicePort{ @@ -254,6 +262,7 @@ func createService(ctx context.Context, name string, clientset *kubernetes.Clien }, ClusterIP: "", Type: v1.ServiceTypeLoadBalancer, + // ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal, }, } if localTraffic { @@ -322,9 +331,10 @@ func httpTest(address string) error { if err == nil { log.Infof("🕸️ successfully retrieved web data in [%ds]", i) + r.Body.Close() + return nil } - r.Body.Close() time.Sleep(time.Second) } return err From acea12d09a14b427abc9e54a8b1560c56ee27f26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Feb 2023 14:14:28 +0000 Subject: [PATCH 338/542] Bump golang.org/x/net from 0.2.0 to 0.7.0 Bumps [golang.org/x/net](https://github.com/golang/net) from 0.2.0 to 0.7.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/compare/v0.2.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 0a054066..20d43182 100644 --- a/go.mod +++ b/go.mod @@ -24,8 +24,8 @@ require ( github.com/spf13/cobra v1.6.0 github.com/stretchr/testify v1.8.0 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.2.0 - golang.org/x/sys v0.2.0 + golang.org/x/net v0.7.0 + golang.org/x/sys v0.5.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 k8s.io/api v0.25.2 k8s.io/apimachinery v0.25.2 @@ -95,8 +95,8 @@ require ( golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect - golang.org/x/term v0.2.0 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 2613d480..8abfaaa1 100644 --- a/go.sum +++ b/go.sum @@ -518,8 +518,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -609,12 +609,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -623,8 +623,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 98c885dff5f246f10de696cc3d0edbe22147e560 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 19 Feb 2023 15:58:03 +0000 Subject: [PATCH 339/542] Adds e2e testing of services Signed-off-by: Dan Finneran --- Makefile | 3 + testing/e2e/e2e/Dockerfile | 16 ++ testing/e2e/e2e/Makefile | 61 +++++ testing/e2e/e2e/e2e | Bin 0 -> 4562944 bytes testing/e2e/e2e/go.mod | 7 + testing/e2e/e2e/go.sum | 15 ++ testing/e2e/e2e/main.go | 66 ++++++ testing/e2e/services/kind-config.yaml | 9 + testing/e2e/services/kind.go | 74 ++++++ testing/e2e/services/kubernetes.go | 282 ++++++++++++++++++++++ testing/e2e/services/services.go | 327 +++++++++++++++----------- 11 files changed, 722 insertions(+), 138 deletions(-) create mode 100644 testing/e2e/e2e/Dockerfile create mode 100644 testing/e2e/e2e/Makefile create mode 100755 testing/e2e/e2e/e2e create mode 100644 testing/e2e/e2e/go.mod create mode 100644 testing/e2e/e2e/go.sum create mode 100644 testing/e2e/e2e/main.go create mode 100644 testing/e2e/services/kind-config.yaml create mode 100644 testing/e2e/services/kind.go create mode 100644 testing/e2e/services/kubernetes.go diff --git a/Makefile b/Makefile index e5753f5b..75d710b9 100644 --- a/Makefile +++ b/Makefile @@ -112,3 +112,6 @@ manifests: e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -tags=e2e -v -p testing/e2e + +service-tests: + E2E_IMAGE_PATH=plndr/kube-vip:dev go run ./testing/e2e/services diff --git a/testing/e2e/e2e/Dockerfile b/testing/e2e/e2e/Dockerfile new file mode 100644 index 00000000..410ddd7a --- /dev/null +++ b/testing/e2e/e2e/Dockerfile @@ -0,0 +1,16 @@ +# syntax=docker/dockerfile:experimental + +FROM golang:1.19-alpine as dev +RUN apk add --no-cache git ca-certificates +RUN adduser -D appuser +COPY . /src/ +WORKDIR /src + +ENV GO111MODULE=on +RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ + --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=linux go build -ldflags '-s -w -extldflags -static' -o e2eClient /src/main.go + +FROM scratch +COPY --from=dev /src/e2eClient / +CMD ["/e2eClient"] diff --git a/testing/e2e/e2e/Makefile b/testing/e2e/e2e/Makefile new file mode 100644 index 00000000..2ea6e738 --- /dev/null +++ b/testing/e2e/e2e/Makefile @@ -0,0 +1,61 @@ + +SHELL := /bin/bash + +# The name of the executable (default is current directory name) +TARGET := e2e +.DEFAULT_GOAL: $(TARGET) + +# These will be provided to the target +VERSION := 0.0.1 +BUILD := `git rev-parse HEAD` + +# Operating System Default (LINUX) +TARGETOS=linux + +# Use linker flags to provide version/build settings to the target +LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -s" + +# go source files, ignore vendor directory +SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*") + +DOCKERTAG ?= $(VERSION) +REPOSITORY = plndr + +.PHONY: all build clean install uninstall fmt simplify check run + +all: check install + +$(TARGET): $(SRC) + @go build $(LDFLAGS) -o $(TARGET) + +build: $(TARGET) + @true + +clean: + @rm -f $(TARGET) + +install: + @echo Building and Installing project + @go install $(LDFLAGS) + +uninstall: clean + @rm -f $$(which ${TARGET}) + +fmt: + @gofmt -l -w $(SRC) + +docker: + # @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @docker buildx build --platform linux/amd64 --push -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . + @echo New Multi Architecture Docker image created + +simplify: + @gofmt -s -l -w $(SRC) + +check: + @test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" + @for d in $$(go list ./... | grep -v /vendor/); do golint $${d}; done + @go tool vet ${SRC} + +run: install + @$(TARGET) diff --git a/testing/e2e/e2e/e2e b/testing/e2e/e2e/e2e new file mode 100755 index 0000000000000000000000000000000000000000..4cd6189dbdffaa4afbf70bffd6c1f445e8fd2594 GIT binary patch literal 4562944 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 s)F@z=0pDP= zzc*HW*|c`4_9qVB*M}Ul{hcjJnKN3D1OBzL2rZ-+57-agDF#xr9qS_kYu3jXO>{d> zO=7sYWce~;j1LswGK;&1Ik?bzfW+(vdetHE+}}%=3vf?+frQLa+=Th`!l;a?>M|;wYuq*`p1wyKX6iiT*Z<($>F5v{_m@VSAB7!e4v+^d&tk-A7S@SjejuX zFJ0qKIGCSj!U)a&=H6Gr#^kS7_kVLwr8prDzDA!1s9@8B>Xo@b_JSQ~E~YnDjS&D! zn`X?-+KyZ8tgBd5fb=gEJtSBlsVJ&v!mbNw5uzHT5OoswhYljU6| z;@yatX34o8*Zraa#&l^`+5-8E`@W>8j+yrHiwU|BxWO-aQjTw019x6g25|02_u4Wz zJJ|h=*F-4;DPQyKvrfTu=Blr=e-qM!6Xs3se^x%fSU8hQX&m)r*I-|IslF_@q_1J% zUe0DnX@1xVKG9zNSeQkO1Zxgt#v-W*bdN|3oUNGx&Ziq~%8-?#N(5>9m9!ouS`UWA zwM*Nek8lI$sZibHudi}Kf19_Qla35^cW2AdRN)2D(7L%dI;qLffUW_2noKa^$dCy+P{8b(=fUjEg`hVL^qHOe-di4vOFu}nnrS<~Z`%0<%WnjUSxJyv7jc27Gqk4g zgN0mi_C9VK_ig^r{)t!7K1n0<+*iDKiAwh@!VugEp8JI8KaEefN&c2%Eq6HAH%H4( z!yX@Os--{o$F`w+X3~(kbgPAi+`fKwP;|ECMai(isdD%0UX5yxj|;!9@p>+anKPZ_dBfkjERPFvl4J;GE93x?EKB`QF*)0lcQcmKJVjSMW(OIc|+7A0`aba>BK6?DbA-TAmoPtdXvc${jVGr~dnI_J2-jcS9NZ zN3KxMBwX0&cfQx#f6#Ic)4k}A`2)HAQ^i`IQbTK82DazT%TTG9rAxVwUN>un^XfQP ze$i@dIyzGPy>@18%ytH(R41gb^8>MUpPq(K(vu^+;!JlqkNby-tUB`k*du&!!_@Gz z%`t?(!K->jQ-uZbU1T8qFdAyBn;98(Ad;$;y9^{4l(p?nt&OX z_}kpcxmc=MuGB2U??}qD${E!bglF<>9|?}%BRQ$mbojFSkzv3*XRW@dNJIpG zNJs3YqOEfNj$SYpQIme3Lvn124V!(!Q`NKF03(_Rcu@rQv)8-AdPaQ zucI6X1w*SBai?s*Rk7q<8bCDk@*Fo3dVDLt=e`OhMMu3HNj`jl8MgGhps-6%OAgyp zfs@<*j;!|G-1Y;#{Pu@+X}<&3c$@OeIH3=Nx9y>_;R*z=3>g>v>6&1?iB}w=JwBRJ zcC!DPb&M`p9u`ZMmBkXD<=W>j1ft1%^)?b;QxZ*>pV830vw71nu?GAtmvx#Q9@7?2 zqs24a7f8#@E{AmJIY(fd(cV6A;sT8E4wpL!Yp zS

  • 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 g^j6DTD=Q{_^>UCQ_O<@awZf5Lw&pN_c& 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

    7=Nm%LIA^rfbV}%E;zU;^m{V3aEeMB{`5qv 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� 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 z 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

    RoS^Ql;`X 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�v&KAK7R;~n8yNVRu~T591)oT}g)5~F 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ଘqTw0HfleDlLj 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


    -6XTe|8vG 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%0DZfuN#nHMx=TtUq`m7E?k!}j>btr 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¥nG_K&L4nj=ZvLasA#||%3fVmT*K|rVD_VLCo$@0as0TxP8guBu#FuW@*ocq zUc**j32oV5sx!B#3okr1@>=lAN6y}*f~=wy_v84A@dF}3rhCa?5WxuqRj

    QLjb? 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

    ^?C|A{)CI9|J@|STUmqt8+=0CS^7T z^xmpxmR(b>88Fq?#_OWvr`!5+7M&(_r4u8gE|LwkX&U;MMJpi6&nRw8kqZ!L01>^n zU24g5jX^HpMpb~0+-{!wK$v5Kc;?{1J!HPOq*w?;9$(KG6eL0&uSxHpVhouDG9ANS z&EQ5z)P=vgs7KpIf1h=#@yTXip=|1w_v8~0aVU8oD%^ZlMU7=#a45H}m=0jhO8>$4 zIjw9`~Bvk-W&nI4VD;tdNwks2NhCKk1RR2oi6X?OOdmzg>OXa zc(HJr?!(xarbA4a!{aO(&Zvui9#bd=9!MxUyV!l#!bghtr?Eo97{W zaSR+Jns$%0lUj0%HfZC6;g(w;RZpGopb(iVq&acMc3ufiqR8QK^0*l%Hh(W67ZUma zKkId$wrxH%ZjKR7Kbf{ASyjE5h59bD6x9v1q2nZafK@Pl!&g{$P?gMmu)&)w5)oqs z>D;9P)rGEZazX1fs>wg)_c%!opNwHgo^gZRX?@gK%w!t$BN|NCW}kw!Xy7Pa_GSbj zDRtA>_)ezAFBS1BdTP!YTu9Va*WyU__0kJ%A+??Ov1%>w#_bGc{2KH|ao>s@mUFzZ zxv{-|%YPKoV*?1m_YSYh#R**5^BN2JgGluD)W5HKZJUjXhu~zJh}Hb7br zk*AhE@NS+$IXQ&$fnn=l(-uAEaOwq=9;fb!oRmikuqS>%~nY#!z zTS~?*TVpJ|EGV&j8r>+kI+sSiCU%XWvepRaK#i|!^Ruo^p&wUrnEfsCFLSYljSzGg%OWP(%y&JeaG^xBw@s0@HsGF^p)Uobqm+! z59eTFP=?il1<_FVr(V}NWW&03vC#93DHG5kO;)G#{65V;KBP*rnvMv#G{7d^>P9`i z$xZL2Z)!}6Se^NzY@{78Rnx28(ariA&iKP}cm>pw?oJHZlsjU|AGC|o;e0{o(vl}6 z_2&+kalAtR9;9bnZQS%9SSpAhdz)}~EPo-s9dlGQcOkc1&8YG!SY3J@(cVxOt z$uKFq!18wS+TCg%SSDBE1V+jM`!6(w?M*-m);JhMmJjxfN*o8t9BI6p11Ll^M2A@Y zfeoC1g&Yu?*pGOm3$j$oxsUB9i{i-s9pqHYiVw-?-wTlg#Zv$ft{T%wzsJ&#pRqGad zCqBU{ijL&>^{KH=-}aP5VhSIa>x94U@Hk{sGTgdJadl4sL8ZP>?vxzg5PinFF}x?Y zp>sVYC~jyl@*L2!J6dWmIlv2~8#;KF{Xq&&)Xh@@n$zf^IEFaKCcc1Vg7bwU9bPu> zHe3trkByBOf=v$}NE+`nn$m});X{uarQHHKd=#jqv~y|x2KUl6ennTp&+o!o8({#4 z)JQ**vc3{Yh_7YCl;18E=1p3EOY<@ee7Z))bPx%$^J*+(UvILTGo$tpwuMauj@yME zRDKzh2zqJ5s7}kLz>MK#ZvJtkP*04boI?{YdUP@Hi!lelx~9ZaJBm-mDlq}BLv>)Ex{D6+fP=iOR2G7B6GhKuMis@pyn#Ax-= z0^eCwgZz>eewxh>`@rfe3Oh#|xc#QENc`vzZ%iWNiQ#uwMaZS0DJXA6;Jy&d)hl+| zR$SSNs2$nq6e2DabUdRU-)0P{aCTk&Q~X~dt+=(duF~H6bN_9t&q+0H59Kq| zUS`euZ)r1cwEPjyto>VQV3>TbQsNGQEW258;SWV+do_!7zP{i0a_XPfbbbXZMHh3D zdU1u+@7H#-gm!I>f!ftbtOCD1oD+!~S~#Wp&Zi(~h09G)CY>7QMIo5LuO(fqGHhJ) z!m}q%XQDf*#d>U?prdIn&xQ;09b9UVhwleX{AO>lVIl$4+QN0I9yYuW=17<3#{iiv zHZ`E4532Tj;XEoIhdAS*Iz-ig-?T?tizM1=8ge|{2)myjoFcMDe)*x3`+mAHMy=&e zqY$q1rCh3O1OjYyKKy}w3kI4i@Q}=&r;KQOFBVwa-@#P%nJRbm^h?}ld``0MdxA=; zL&xOHEBMd)^>UOVn@TLtg1hf5@qad1xCU-Gb+65%cv&Pen6U?#ZPUFi=@Esu=aqCr zC#T(aWo{NU&#J0E!K0+MKw>PN!b#1XW1%agJ%8cCGa+q!T;JJ1Y%MiYcEX@dvWo&tR8q>n{1!KOn!zn@*>G{qx? z6;cjkNZ;Z@D-jd$zXVcZ2+6JQ&ah(puGlpK*SCC0;y~6Q1QFfW7 z^{XFiZ48h*V|+vB7HBEx5lj|#(!i%U4umP3`IQhKKMA>4v$+x(7sxsI1l0-t-AmoQ zJNslGG(`m4TkS&c$RX&omEB+!PExsWP_H@OXvop6>6K}D$xNCuD7cW9WUgXcx1#GF zFTvy2_S1V|A!IY(9C3cz&j*RuHwpZG)r%U0nR=6mxB6&G!cuMwSk-lE5&&T3B#J9Wj)j8$2triK zkQ%~1O0T0))D(8YW1hidIp+o7m5c~70F6qN`6W<%NGgXg$TpN}4oo7HS+yMiLy)U@|xxCH9r!I(76H>KcTbJW5|0f!$CAxZa$1x#2zq9e)ZZ4 z#K~{Mqt26b{Tt_&RuuReKTBQEk6?^yiYm(5cCsZ0_6P4%cv(Zo@FU>584lwhh{#g0 zuW$O}MHVESU_OF`!IfQe7gLo3b9EU5l}S7BsRBz207fTpS@mlN2zB+UQ_RIO(#6Ns z{o5D=Ei@|!r;U%ZisOxY+`VZvLP*J>hge(kV68?egtFDLesIz0ttn512}Now+*who zH<%b#z?7ef=ZVfq;5PLqwG4^OIfalIp(;Gss|krP(>u2sD-_f0gsb(lS-*v9#-zUT zXbLhsA5^4mIK_>vh7rWKuuk*p(n+jF*2%S|sd^KG3w*~yI9eiT`~c7-2kGH2$j@UB zl^;aL8?ezLk3^2_8TUASy0L$FU-~nf-&g?|q5a&H${GquCX>fw0&7x1oZV#0Sdy2b zktKJ#MtIpsa4A?nr#m5h(Qs?l)Xt#jwd;?On zG^Zs+U)Tl7!qMu=SFSS$koVW=l-+#rT&Bq+FL|4T%IGk~nRH9If|{RwYUMeTnD3M43j4DqDsjr}YC#P2ebF{(Aapm$Co4y5`N zb8U$-hVkVA>}Pm(K7pYZ@%XLDl^1kWc-m~sh2h!(0noI!yp(#I3r<5t3(MI1uQ@~Y zp7f6Co>s)%nG&T5iZO|I*d?&C2GX>Fl2_>Z7^F(}_qx}tk0nq(XxN{j)9Z4;JKc@j z97rx1~H5Z)XiciO~)a+c_R+BSHlaMBmH3s$$BF`Uitkp5NV_sjhO z^E7jQyF9f&?Bsn;q%IzK&`&rEt+U#SxU;&u@{s0WYk>rduJ}<%(&Unyt41KlYZLQ) zp>&K3bjuEyUH1T(JvhAYe&oEEJxMZtVqcO3oCS9D_%psMz(2<%fTf;RMJ z;Sw960a%(Hb<_^xEUTw@)!;#zeg@$U>LXAvUq44M#%O=}QnR<)SkD3rP&;=F*_IzX zAxJLj6&T>|uvfGHIe_xu%_PaW_f-3#7;ODL&FfSIpNf{-})TI|rJsf^d zgUjnG`S71vD~fjkYy1R(*CVND^G|8o-$eRb5`Sj*+nI4sc`9$@_K$7A9TWKJt=_c= ze9pA1S(;G-KI|&Ayb$-q87IQP%G1Bt9u>;TxB;Km7ykdyCw_P8qy0Pc#GFwIE}Rr&4UDll`{P<1EOF z4Fn4g52+}!e~JG^f-Ug6B4PRf=6S3tSM@fI7l?u+R>M9KF&$F5`0?)*9)?Js6&KXt z64aq8xH0il17i4b9>sHSJxD5T-NFs(5+uu{{};I)K|E$qo+;ky&vZIH0+M=451F$m zJzTM;S*S_8S zP~G#(Fxas{79Rs8CmsyT9fj+J1s>D}3hI-gCCz`~!ubk~Fme-*{E%6Qq zYKP1_1(k$N<4i!OI8&z*UfZF#;Ylmft);&dQ6L}eHjjd~dF#5Zo?E>ESOR*T3`>L_ z4IZHF$=`m6bx~qVA+~9j-JcK?n0xs4R?4D?y!H(jh_^2O`E#WI^akn-Gd<|UwSnzJ zi%9)md06w=4^8Wx4`NCdlyhpV+k2A60}q~`_l?3uso~fB9%g7L@kpcp(CGAh;5daj zgu>Ko8HSoDk)RkRbFpz|U~YNuGRBaQloKbZ#1Bn7mtgktoh+^Zes{~{eF?@vF7IC2Z`|%_p=kG%q`F-!!~I9!n|mDf(g)C zEsz(%gJk4Z@SS_cR%3HxAiG+nQoK>cn81^(OXgp(`AI7{M~(kYts%mm*7SWt z752(`31vmQWZV;96bBy}*@?yE2@cdhtEjdosXj4xE`(L&iWhKf$Mvo1|Q3n7Qw>S=xLTx(-G z-S?O=y7&ychHvpfA_dgAzo!%4*mVVVfuVYz7Ebpz9PJ79&ptX9k)%L8AJ*z>s{H8R z{FRIqZ=}r=ZX21S(5^2u6(mS`a9L|+-dno!-L`77yyj9JJ>3X~=b?*shGhrpD%&tg z`WoEl6jxW-7l_68eZR*aZ0YXV&8$ajH|&h%`*)%YD#QZk6XZV;QNDb{?qnC;IoCdW z-h3Vez~Sj!S#--#60#*J6NOea90(f##FhViRJ4eIy-e<7iVU8b_cDLm%SR+@7}R&O zn;~%1s)Fg`lcl1<ELGabK+k;zcna|v&9;%+U1 zTg|UXad-V7i*fwrp$7>4edp-8J#eR)L=Rqn^EQrQ4wG_ezI%WpxOaRjQ2!^(1thrT zVvskz7X#4Q7=D{6?Ij;=K*Z7omMzG})k}Cma;(CcD zU3J!^2#WT++WV0S9OOPg=oh~`J~TdaWj&i`4VcH$1ry=YGGYZYZ+gJ-n2&tz^hK*{pPB7h8wVp8W1hui3C>1P7ID+Iig@si;p zSj0E7G_{5BXhAH4y^_(O9Vhm^ zjGTy3B z0mhFlUgu?=vyfJ!bYD?DtmS#yPtQtIUm-AtIy<;%ZgqvwE{k+rvV7C!SaLD2#KO$Q z8iX}xX;7U#Ysr0my;K+d5adUp)!muXlx`_yI{OT>&BWl>$h4ho!MF)+-`U6qLK?b2 zZN^d@_m$Ld+GJ8EpB4`LVuO9lGA_t9^J6tYPo<~Yt2itIt%&fQ?qFg?!CGk?lQwuw-_ANtk4k3|SyKJl`67F4 zKy8E}RUe5L{2V=abp%bWYO69m0|3C!u{>(o;dj<55ildja^~Zww*y07e&}T^%LL!X8}~FA zG^p)7EO+=aOSU&c5>E(?2mS2hnZAx_*jv_JN<+ z{F22Lh*EP;#;8fop#uzz2U+sD;QvkFORM)vP$6a_OkAV&_WvQCn2{b@ghU+&5&Q{3 zT$K?B9%d2oB)XHH1nUK{gw)RMc(o+-p_|;6X^=kXw`PyO7J}{9^i3^?&%P{6o zR5$0Cnb?6s2#2eRyI;uuTR9O$9YHA5-uTVrdB9LH(7ZHR#OF&QuE|(Kb#a%SP1`Uc zLA$Zr+%b*~y@ZYy(q9oAG*26*kHUyp75a6@3tPIS?hQPenNrX~&K9BOLM^cA{&knG zwp>)908+4W>a?RVeQ!{_GMl}Ncrc0OmnyO3H($KSakg_x1`GgeieKIrT$0A~)sac_ zl}pQ}W(C!K@Rz@+o}iHn@LPacnA?Cto#Lfu;~Z;uZ;?|^CidMkANEgi1JQ+`jw1#_?6^kgZr6_ogP$?IgI?HYZd=xMY(`b*DiH=^g9OLCcqQ zPYPJSdMhO$AdbWrfs%4JaiI0aC>-0`o1VwyQDBN?>Yr-HbIX(yBYVEa)gJRF{`jU^ zHjl{ko=K`oA9An{YbyKW)u*#)9fguQeF=!C6G?CBihm9U!TsBa;tcxn2;KP7fOI)L z@Ri$6iwf}$R^>-Bb-Y+bq))&PU+-LYbvj@qD#YBZhhm8D)7c*;V z4QG0US(;Hr;;#^dbk{JvuQ`{Rh)VR>1Ku-cH``rMvzuzw6kdTw2YhB`yOTtS?f57n zf=H_u8dl6B&Knw1SqFoeCbqm}9zrwmwcy?+$T+61Y%~zF3ux!o)6Ue@mq2ge3!@Ts zQWTa6nx%>5{b$(ofWgpGPbG6MtaLmxqu67RdT;LHL?;vyKVTtc5S=(q6sN9ApW>=?1$5F#Cl(fAJE+97OFOQyTVytlw4^Uys?&Fna8Wyyq0tmBps*?U{H+ zOGf7|)72gdJVNgr6L!pL>UMr17pcwXAI{7t7C(uKYXR62Yfs0Ygx=P?VNMkD;ul!@ z&R)fvwK<6k|8T0yJF{f5k+&*84*_ehH_K9cx@WhTL1p;-fb$K#N&%r{RP&TkCH6H; zF7m-b8}+;Q;`4BtOzt5FWI;6_k{QMewCaNupNDcC_R5fSvgc~|^Vy1-_g4|5P#G8= zemdId=Hb_=U%4iP>x4I!5GpQIZtdg_gZ&bgxHV0@=>SxJs@JYh9w9% zBAcveku`YCS=N?jv{GZ!-9tttX&tSd*>K~{`dx8iZ1Q@YdmeSH#Y~;Iy%9qFa%B0F z#!ueJ($jK`Wbj1a^~-5{;grAhq711$;*==y_$5;s3)UBTY=1)vUCYUqh6LxECVVsD zcA1=%T$!B`-_*voe%?X4NXSn z?=|Jw-!JnTTNufhr+)RTh$OTU7j$~<`i64pr)a~kBlzKQb9lFJ=Co*sbZ9JTJV6$L$T{(Xz2z!dU!gy%$&*GqEW2F9ekvk6SOqJ)!5&!ug#D0?J>9z zj=fh6M*O_+%=>nd=KjyM&MJaBTajJI{?d*zY)4tc6TwBH&3oaCQ-K=xk3DRv!)NFL zFUS^UUEwrVu(?QS(tAU}$J7~Y0Mh)@cImO=ZZc26wMt*s(q~GR!ByO<=wJ$c2Wl$HtXkssWEL&d9;kDrs~jGQLa1 zXrQFjcr*aG+dRrH<;IVEnbQR9Yq1^b&&4Z`F34N3(vwH@e^EVlJ2q9r-Hy%{ZViI? z5BKs)2&G|m($s#-a#R`JPDIl|NtW6;w4(kO0HU<6R+ILdJ)E&>kzYHZreKrY6r54O zap6KP=^9tU`OHD>W2-UCPld>}cE$5Ip^_uU8yV$hJ80Ex99mX!iRN!$g91xPrv2h) zXI-N6q`+m0-XXe&(S!!4oaA)gJq+kGVRq;`O~a)YsiK5gHH;~^%s!|Iz@$v7e1;jC z|G0It5LO5R+?E6Pi!zq-W3F%BOx&HE(3rglxWQ3GK=O5E)ErA>aME>iGwTOwy@n$C zy}rm+Mk`~)tkM(5LIT#WdP3S4Ms-}tw`DLf-lG@4n3yB@ZaWAICOv4BO{Mk*>ryug z-E<&zBiz17lO=*a{33Q^J6+{#69oY3Z2(O&^b%g5a02{fsfLtN=9x2+3=O&ofN+;O zM_4#EwrXk&xZ(Ir9wveWY+Ra=21w53(3*Nts;6oN4Ahb*uwiWF+G>1E44$#1c(I)E zetd&nmeSb1f$* zZE=XjT>h!r^Ls3YLY}AM@(93qAOnL;KbE)i;{!5~pn5EX`+73x3d$m{wh4BYk}%;o z@mO_rV*9vr!Km!_G3diQCl)jIbVL{AGy=rK%87ZWANn@+#WGm!q(p*}RX=axkl|au zAtpNXD{Cvt!*bU5gIjunMPm45a)0Rn^$DTDyC-v`TzFZ+wqk03=?U@LAW>FV7~iXi z@he~Qa=bLZKGh+|^g1JI+saB}!sqYMsTkkM^Le^?=nD=0>h&*DR$5HQPEmbq@Oi^Z zpP~-e1Qe2FaPnyak>x%_;DMk-p%?w-YAFu4efyW!oN*sWFe^tZQjBl@m?~oqgu?K} z7SYU!Vtkk_uZR%!&*m*m+RQ5|`S5x6{+A!g@?TlTYD;& ziyXsPaOpSvNDvxdI92P-RbtJIB2ge(iyKdzmegXG-UTn!1Bg8#_H#_-dpBf!!23>G z1pdEeL51};V=&Ut@V(6?ZwA&>TW$DUV=Z53<@PS|!Rb+sf^9U*Ed;NoZ-H|Fc~F%% z^!LRRr_-Fs?JhN}PPLp3h)1(C?s_gpnvI!!L-87ehfm-U$pVP&Y1ud#3!tGK5Ry;Azk|AAsuN8b-eqXM|Zuj0E_qf+7E-$S5HGyoFt6* zt8EFGMRgxbv%vU|lyARtOcPE;J@BqHS-=Z9)mFGJ-x3o9U%l$Ud)79F-$n0!wSVg0 zALt2bH+R}GQ;d#cyj5Furr9L#b|uc{wZ z%yWU|tZ;$SS{n>|#aF-_bRz~K=5(?Id5p{Ar^>AFm6Ylv?89cn6@2e!^KMbY99&mL zI{@!A4F1ANpy#vRW1JNC9l(wRY?zwIxoJ2c?|>d`gFt-GM?@)()fWyS9AFX>E`3ld zdEysZ`qS;0#eS@}^ik3H)u#>RTDi{FxDGnpu#&W)V<_FTX?qoQVm(2{PRGRJ$HZT} z_n$Jp+MW7f>MB};hs#BDt@Ri29cdluHYW6&G zqN=w|dT$o6^cRD!=5*}N_v6$1{Y!`7tQNKXqw|5r8DNAxupkzET<#JJ0mWl0-Lz=B z9>r*8GR*_5TgwYh_jzI}sLfxGpA(M#{afz6#8~C?cb`Aw^tx=)D zOXw%s(Zc2vmOVHB>84rNJQ)@7EGE)pC2*TR$XqiTk%Tdf+<<87Z^JVGWWS zttBL&wzyh=hF}1V+7iVo{lN9SYJ{Y0*Ek`p*iq`QL)1((MRjD$h05*CW+WS*j8h33 z5Vs2yT@evpQRs@Sp7jH7Xa8dj`${8yQB_`b!H*z*PTRs^T}z7c&RLkM4+F0>{M6RH zbVpQEO36_tzCdykmxJzgPYI9UG9=Jvh?d!+lt_wEIarVqanh zji5yRVz=p?Th`=0-W7OpZcCY3(J|qtpvRTjsw2QA@@=%p?ffcmO$q&shN#xg%|pj~ zb-v0U#17ZDkdv(4N1kjdkg5=qC6oqo>(FFW^?-iSrxT`Ur{U9yt$oSJU=n$E=gaWq zAM!8k5WME;!b+I!1*6M%=sm^b+)rYIviZ83?7)Q-%~6zI$R2jFZFLhLRergon2S8+ zD9n~X_~Wj!jT#SNk*|w^(Gb@zAPj1Y2A+Q6L~9xx``joV z+*hpDWXn2;rFP*$tm1;1WGi^$M!HTi^-zQ1ud0ka%5>KC@+#Q#9t~ht?GFjU2i{Ow z@8C#9>rYyCKLYTwkZ18ZGY|u_v&f@i9e9$a4sC}rR5-i{1A77}`vuRwFX6GIeQ0cB zSbQM|JpkhXqp|^BH>o>eZs8q>1%!;Hi}d&uFvL^F`Ou)&muMWkReudT4(j08t$JIy zlB!#?^hi!;x6$k?!kT(*jrZ5$(3PC|VnPS?=@Isc3P(~%?45>^8Ih{@;;L;rsY`D!)05kYAleSwa*zEXk4xJIst~X^Ej55c4ttc zC<~6G(6llVPkU<9xP(WhmZoL`o}tfwOZ&r;{bV0r-x+OC5lNM8p*(tN;h&hFeW)iR zjEzWs7o&XxD9%Hr7*#y^b{z-mJ8cRgNc~?}0}j{coflPBa7CzcTnu)Ig_}$y2UQEO3cq?~9$maR0`_jdC@IH6q-_ zFA~;y`FG+O1JLy&$BgaWB~Ivm3W&{Pu&=0*V6SvF#-~0%LVw-@gxvfLQlT2NFL}^n zRTew$vPYVgTRn*E-MN{^1UQqofSmw@;F*+ z(CAPo+OWQwHGd)%@+0NoHxLhHI{|~0L#sGMUXZ}=`)EP~Yj*|=qDv@yGZAbX#7VgV zPwz_^M~yptH3fbS09)Z-v?j4AbY>>QL=lqULX)}pEItFZ@y1W_RL|PnU^n}HrF)Io zF$!AJcS-kX%P;Ls2S9e3Wk-nd$MoFtX|bJ$YWZ!^)pbpDweQTns`dRq$JZe?>Frj} z!FIJ$&Z#oCCtz=y=sG~tWLkLW4Fw8jE@gt2N7nNY0=~RY-(IqKT`~Ez-Vbrf`85I_ zngECop|~JOCqV5lKoJOrthaK$<6{wEawZnk>TwKpt)m|IIieK_SUX2B0jY!7qGb0aeR9ZNZFL*->)39Xd@ruGkDB~w)zpt z*UZs5{q|uGsgR8%i|ZER4bmd~M2`ifD3-=ol9ncs&IeeELrxoxewq;ElQ<}?+MU&} z%gGGGlYosq#x`H}vN8>(o<=d>$dQ3QOW%|3wccAb#TO8qD5@5Qg)w5%5ba2$WKZol zi?{E@r~~VPQadt{TpQWHF8{u^Gb@Pgq1Pg3QAPXEtLUGU8$^+Brh&manM$N%bZZNh zUn{2c&!Pe7MnqvE-;75tCm=fdvrxvEnhYusaQ|~in3Dj-0d1lB28Qg1i%s30lqbOt zVAN}G0D7tCS^vIXFwva$D5AAuhS3RPCW}DSs(oF!0JE`<4-rUytEyxK(mZ%(VW5i- zC5!eg>x!VVVZ`8xt;UY7c4wywU=dD%N0CEO_SC;jr;cFAyz9anP zdDs)L+-xMD4y23IPq8xvtn3#wtlAjr)-%1_~Sh{n<@PfQ$uQ&}4JI$u}wTiOXj!lVmh2W;{ z6*9>Vn7KkmpER8*3Kto-y0tdED;6xXqCC<|g>y9q6@m8Ol43#sncKBX<4~cuRXxF@ zC?I;d21P>U!3Ok(&y~%&xxujdbFQfov#W(Rqp6muuRfOo9al6dubXfG=s=1Jn=qzbkLov(7S8d(B&PEaAqhmvqMj;vwedz)8>>Ri0zN;0Y3$nss0jmqU(mWc_k}yCe;JOgb8-pB!L4Ud4n&v0jENDm zpnr5fWvmX(CMQY&S#_Lq+$0YY~Ous}Dyd5K}0Jbu**{FV(-| zei%7UbiAH@L~9l{EHX>|JVULLQLA~n7pQ7->lNF<*sN~(W4?9-kskN@7G-|P+M7<- zp7b!nV3T)g6hBChkt6TAJJC1M{M{{WLOOKP4&}{MXMWk_ z#ZRM&XyM*T>C(?~Ir1t#BU0cRY6g@YzIC1e6ZES%$1%!m2${s29o7rA9=zi9j7pnI ztb=cq_r+}MD69YL{FB-zO!nAJWbBf}QG1;ykk_JER#L|w#UJeq7cfJQ?TTeS>si_b zE|g&lA~)O(qhLL{hkq_~(Ht>+ZX2-n?*DUSQG6wK?-}Jh=XcZ?(->H9!0lss11m$HxVGRJ!419I&h8Z#WtT*N)8 z)Y2F;jx+4NW9f~)yVpH)y?(@^y2HF--plVb8Lc6xT-{6pjApEnN&3yf+|^ChJfOHBPcnoQC%JSn+43ZLP~JNEzpS`I2L&@Y z1Ne_dKBYH6-%axdq?2ilKpM?(BEaQCmlaz0eWoSB!pUzr%fDn0zrMEv%WZ(El0`&( zRLzG(OJM>VLd7a+PhbOs(~)~3;s1H?z4@vYV?Op7`$Y5cW#yjvnUNvZA7&kj9OR7D z#yg0N1le>vj}c`M8;h?G?uj^Ywj1IN_h5Up$~M^CPp+(FW6ng!ZR&M1Ta`z!UnXR? z!@@zBOkIk`U{6KQ*N^F74C-oi;`;%|c^tB;UWmvE&%M!+?^zSdh9z0^S0M;$9Fd6f7j)c+tQE!77IB z&OgaOuY|kBV0kM*Ii|?G+{Y=;ZG4YM|DEyrBE2^=CYKov~aq2|c_S`&-b z#z@+i|G#b4d3g!K9aA9cxviE0@W`@C4RbT2GZ`g%D-xHlMKdG8oHWNaumJRPh~9@* zua$Lhqem!`!QS?NSQy~9%aOq^&ORt^R@@*Qi|@jC+|n*ZUQ^~#?SF(RR93SN&^>1g zhC;#p3*BOiCpH^$aaS5~J}FudCmD8s&Kv;WeN501uz|MsmKm(0lK0;hFs{T83la=i z$G8rbm-aQl(*)k)ET38ND3Yzx_)sK?tHCL_n-WNU$*)j4;f2>E;BKj7C%Q!^du{tW z0W@WmLMp8rX98kVywK==Pd(}}+`~c-D)KTo^rD9v8U|s;Yga`}_Q`k&(qH>+Jglp? zkQ?B)0BZ9mHl9N1%`^9C%jmz{fkrx&$G<=dA`C99ABdwv-^X~6OZbEUwJ^x0}pA>j1VFf$x1gAF64s((Wmc{N&;;Q`E5RDCLdT=)D-yz5{%zxVo}KT zVkB(fwDFe_!H}HYvm7mMo>!20S}ph}m0=yqy|KpCV&g6}g$m31vGJcX=cRIQI$x7ve9q}MWS(e?Mcf!H1WEl>NE zfW=)@@~%1Jxj7z93a1H1vb&BmKC{zdVN|^p!W{($+C7vs?49n)f@e#Mj_FX2A3Exh zrH(Zul)>StC&>$SP29jc#ryC{(4d$$3+hL=9x06?{=*nj)+xb5wFI~| z7R9X5xLL^hXy(?HeQ6ME+b>1S8YM7pPzLi*Wohm)*+?~$2<5Y|Tko*+Pnwjtz4M4X zCWDJ0iJ2YSFnkoN1K-p{{S{^H#jq~tbuXb8iT>j#;Ja*k>%gkT3bI}igZ3?KGc^8pXZ*&^$K7yfgWiV=hy`J>zTL#x%7isE;!AZs98VUrl*s16 zI_)tBOpt3&?0qsORX7~Ru6rgaJN>~}okIWXxRVQvz=qf&Q;FLxvH)Jnx7hx}7XdTR z_5qxM`o@~nRJ{*8y{6i2&!S0yXfSkfA9PLLBhp`@X6pLBsSZ?N-Zs#BM zb|`{2i6zz%%n@jc7*`@jWq$m_&D$@?pDf?ETOfPgQcfK^6y%~uc$Ag4ND-;;lh@=0 zb(SvuM$~?^FC+8o;?NF{-7YG{o)7r{+h4VHGqjqm5ezQmAb84iMjIvOpx~@+Et3sQ zTx-0EnxS0@cg;97`@KkwIjJNslDI)tQN&#xRGyvuLGFgJ4Pn34UNoPbpUSNEU8Z|J zhLkp_dU)EMQ@XW|x7zs$!y8D}Ga&m~1RAgru{Gcz!X4zQR}#5j~fB#s|iJQ$fj z@Kw^C`WUhOrec4>kc+Xok-=^`_cHhBtA^(bku6G6^`ONH@2xUjl=dZ;*3?s*07*c$ zzlpjK1;%zN101nfS6N+~q(Dz)$df3A3rCbUQuOvdwhU=r5Gj3?)Ua7)WMe}}eU6HF zNjxX0^r=+NG`MU)?wi_g_zxx=9#BV>4s?0FoyOAnWQg7&0WKqj*+P3+E_WA2Q^mu! zRr|S|QAg!dyA5C{gr5O4@fvx7;C3-bS_lmLHDe+^FW__KXTCTn`%A=xK)D@>1;xU_ zmU9y^kxN8a*+2U0YQa@*<>}m>vp&uhDs1C10e4@Ak7CKB`$O5Ff=IefpX<2mn6Y>|qna-2s7M%(yFv9r^{RI9N> z{|P;VOE#=^h?`vP@Dg{)$_-M10*_twdN*Q|MmtCM2G)dc{!z+Xil)ieL2$4OHt;!Gefc+0c{1Q7osVB8nM2WcF8V_z+h)Ah40E zm%!U_8EkRkn)p5C%%UrLTTIr4{F$10vMQ*)TKevkH`HSOlerPbjRy7}C^xV1X=$E= zImkx!Y9s7-$;WtAVs-^wy-X?IsKBJrd=IbP;?(q&PjLK0f)W_#P}-}-lzeKt12uG% z0u;ZGd8<>Q0!}C|ddMd4_}rfP1znOnhTS!rK<0sMmvE8k+?iTB@8%s7Q|y4esx`Af z$z*&%8R?g9uk}tvQJgRq?W~(Tb_7U9flU`};+J$8HHJc3pb4?+PBIX zav#x%zUL#ubUYB-veuEi;p4*MlCeEmzQHA4w8}~OQzI{K3Kr%$Y6{m^6K>)Y0-Qc# zjv5?vbF!I}jk>AdR5FZN3_uJqhB|WyumJRC zUoR^>OmfM-eW)J;|EMqEkRQ?2&r@8{^!!aRNUl#nv+rNZw4=N5wg`~X590h8N!%*Y z8;#Ml7@UqA$cQ>GvPmg?%q+3>hJTpe1=t$)qHuX~?Q$V>X~#}O*N!ZoKD1ISA@~kS z(R*6A0P6iOTcL}Uzdo|Z@~XOQX*nRYLzXnY0+ilcAH=2aIcuH1I)Z)&N8W!RDkv$2 zW&Cu*JH!MAR2>e~HSKRmIy$qY7NMj=?rceLk*|uBt>N2B7n$EtR0^X^ij)ani=M`jxXDR)>=w2nnHWqbOLDjMspd`xUT2LdiLrHE{BL>SV|@W3n2waxZ;$dLgM+R ziw-=nUbbqRN!~xaa#VSn@zQ`gZk$_dsGosCZ3uNYhYDp)2lSuIdN^bRZ>OYR^|%M(UwH4?vLiztEMaQ3bt5*BOA zN>Pk0=9YM#H)l%raixF#%Az+?vTC|PIGDY6@P2O5JVXMl#DaF6G5Y~gvhFXK3Mnxu zutc+A0=db-QTlPyzgvs|4l~Ml0vz3D*s)Wp<)(ITX3wG%V0pLCl{lpuzcDQ#rZ zGXxZo?@QLO7W7^`n(8GVop>xYO6vgfASkrZODvy~Lrz^IIA$k-=a@2XNoT!c9LQT2 zKMZDggH7G97m48nO^gPpg#i|*GKHG5lHuf7+dGO4$A(*`=sQ55m`-mFU!I>V=;k&? z)I$(D!+f|MaRuy(s$&vEZ>pq3Ck+z+Lz{PZt}ltb(}JJejL8iC@Vv3b@#cSD%5s{L zM1rPc%-~9iKev)3EY28Tx8?Jl_0Y;wkJ3Q5e3TOK#QTM{J{R}LGKLJ=7fe5tuUmPH z>(Wtt_O(CaPDz=FXmxcM?{EK&vp(81DClcr>QXELzW6uYVT>a!DceGUk3UjW4%h{1 z12(iC|7VhR44b@H$=p0V#rOmpMcQAUh4c3pdJt1`j=6e`MZ0_LZodUQ&>K6yI_n zmmbqiFI;uT=8oELp;%=Z&;KT9#+5kq45M}$AA1SIgWv?#sSXY~W(k9k;s0L9vs3pA zrO(Xwtrfi4b+F-~-`3@$fquc8Bt+ynj6?mWjs^Afs$kaI|7+5{;#O4_E{HN~cb zV#d#81;3S(O7^6m&@qHoZ>RZW4UCES0(`LP%c&ur{_Cwf~)?YPGWvwTw-UpQ1gqS)WTxp8YY-r~y1M z!6v>S4#`LE=z?(=7y*H~ecOC!+4fK2p-m1_dUDk^h`I=vLdNB(-Q~e5XqEh_%5ppn zPDJV}ciyV{7sv?!tBgYUUKa2VMtbB-%*%mNa=#L7+R~~c0!VnqL?~`0Hu@?wZjN>q zZJ9<*7Z>u2Vru`ypAAV)6_i?VcY2vEjVRrgoy2lo&e+-FcTaH~!KB3ooj#!Cc{Wk1 z0*mqw1H!Y06T->Pi?)VgxCWmKX!%X@e1VeE!0JV7#1am%2gNJ&|0k3vO+Y**62y*# zw3!%RJq&5g_XiFe&xLv^v~C>S-;cCXWHkt|G03+)D6pGJ9;pCGB$hP)BXL zMvjW*lf}_DY>WsD5-~?PqS}UT%VR>m!#L0;aW;KHEYMkTux$}Noe*M)!GER)u6Y%f zyN6B4kJgPJ97&!4Fc~Nl<07w&ivP4a@_ZTk&xh7sAVfM4SfXd`4a1hVS1BS6M7txU z%mhvEbE0!bGCAxKJ~ZDtuhVE*-0{~oVJE3mu$d@(dd+?Yu3;vsKG~di0?4^Zh3bVf z#Xxx-2IoBKvx$1r*BdN4U3I9n_lhA~C7@`YvQ%gHihhGLwJxilS94mh(S<|T?4eZ< zv=xzFM0AoivQ8%;^~9%gDJzhos{BE5;M1D+0iI;rQOtOE%f9iX@o5@(m|OrQ`K$ayZ5UevA3CpJocRSa#9n3yH0?2)BR22VLK|;UTcIn8#gae2VsHZunM;uS1lxK>ws`AgGSE5`CqF<-33DEJz>a|}t z6s3BPaA36{WI^0iVw_2?o_>CVdL%h1ey1b_35>w5bn;bijTw?F_{Giw6fTxLN#`&x z`WMOF9&kyk8V=S`>^u>Td20Ugs6w-lB?P+;T|rbd$Sbc>cuc)8Mj)VJd>u zR{18F#m^UHww@LUBxwmI%7yrz#|EAD?T-_E+=?Fq04Ddm4(3KY5DrH%VllXaLJIwbVQX>%~Ki)jqLhn`0Igy}e1T!;pDGwn2{lnI5iwaJ?1J5+1j!8XHfoDGps! z2TkWgQQ_W;$TnjpFno4)SO$~wC6*a;#&LxQoKY!N?Xr-D$g~9~g)J;kCoNS8PDG8r zu+ep8nCreMc2P!#e>mcMKx_Otrb#ef4kb1KhS@b-=SCLHUD#Xm3_2$!Y|_rki$Z5p zwH?nc;)@2J8kg8T0mTVg-khye3(=4$f3l8>EDbw|1r6@17d+*zgq;kw?;e}lWXLrq+P#G z9_LS@LtrYD`724Y{~j5^DFxmykVzzFpDn`^XRN1^$1IpPx7do-309;KgYH4`ZE^J0<~g9jt}fA-5f8eu6s+a$I$)u}>&|4k;5JAfKxRMCPnI|2 zE)qYF-APW{KNt@iWLC>8^4gLLPo)X_plt`Y! zduC{bJlT>OyyD-OZUt#PC%C5i%^2kTX`jYnP$SrDU?*PpYM_z>y5o?)R8+4p(-}=K(kjFA}?rLM>$3;J)6sp;g@WWY#!$5^Cv0Yx7 zN{U&f^XxmNAeE`=u@_5IRy^PYzogvLo@ip#*g95hap!np9i(@BBc1?IFpn_uTCxclW(O{I0* zYvUIu)dJk51i~()=`T>PhJxcTCj01Th?|JXzHVHEzm3U9%kq)*R1zu-dAc77ql<74 z!g&4m*B4&itT3!;rPs7lXwa7V&{VDoMzu>FBs`sXG)FNtoIZAVgv+F+P)^rPK^BzaNMI`D#h0pk!s*5nk_ z`Yer-6eKIqE?8d`EAbnG%NrCLNZR#*PjJWM5`lyNpXFVgum0EPsYfdt%u)OHy$#d6uN#JauoOMu_`g6F_`du;epk})$GIV-tz;zX~AVg&q6f8{B|>MHY* z3NgB>)=MX?L-~Yg4?q^0aUdS~+V&}3Xi}ZzCo{~!URj`2JC@$`IJ5n{@8uN$4yKK} zP1z%T7p)hjm!e8?n2uGp{ac9eFqWE$$BLr&`4Yh`hscVq(pkjAbIL*n`qs$b=YeS{ z6-v3aA5cWiXE*)b4)Gkv4#(Y&nzQcZ$0$(Qfjy3_0$t;4fV!|Tw;HTb0P(o4Wa;!p~Ffh#)lHHyDlLwu#h0}$GOGVm;E za^9E*C|}4Z?6HHwen$H-BX^`%7I;g_}-)RUNG|0a@azei&pphm;6e<7}Juv$1g-kN{UfT22hg4;kC58;O+`wBe zHEgLeNU$eqk4*XURl4Dh(E3G7G?{OiYF$ODsEx}r;rGFfb?hMrT{$%>Ch6zO^Pbgk zW*wcRc)8)l!DA2JHynJ+X$-@1Fy>ImcT$Qc9p*i1ACF)0gsrD6Sw*|3Mz|!@@*(H!f->iK91~FRi zBhB}9zNq)!4I+4zyo+XDHim$h-20`ys@mMBt-c>$B}{7+yu;5l&ne#goaE7kem+IJ zthHDp`FWP0oc|*TB$h4w6&}$M4EL>Nja3}ZunZ&jj0d*A3k6M6TRS!u4ioVn?t-3~ zw0f%GCqXPWc`d9R&aiB|k&q0MXC&VvB4dqY9w?74C(0`XT>cQ&+9>Z5kb z9R&!L`(Tgh^YQl_gX%K>F-vhQjq!UvWXdX?E;+-sWFsxyYRsJdshb;e%m z2CxQy70e!`ev@IAh@VPUx1o$#tQ6{ZA3DmK>2JF#;4gNx*i1>3{B$>dKJ2K7f zQm@n|vF1|Cj~*-n_&L)C0Zgn>T2SGvM9$%f#eC_3L)p{#;JBp4ViB9^S^3Eh{r6(h zkjWE1D9KdF`-O1auIK#(Ez7>#M`d??1z-AhnvwOrjZ~myd>RV(w|PFao!`L04c24+ zQQ}GpZNG{Pe=_6M;ONeND>eXC{|Hb8UH9goK2OL>@-MdDFt-+QUHxfklX&If4V4BJ z(8eqG>E~kBqdu=UQhCq%};57sXV zrV17vTz}6OCK7hq0$@_(?oM6e*6A}f{R&(9vWRaIxv;lu=VoYyh?#0GY072WNl!W7 zKL*y=B9Un+CC|jyJ-@#d=sV%aC{wPC`O)0%vcwQyH?0QFTz`w})bHVdKae*mxqnWCP3?rqX@ZI_N*A(J(>6gY``t>t zCE+GZ6yEeL_x&0W=CGZr(74f?aPalYwmEK&G7W5KaMQ?NiO&YwfXV%1vk-_) zfWwKPK8X(sW(k`B$*Ln*qUH60rh6?WvO0znG>i-Nm)z)DV(5mOL-$Tt2>+Pa+@+9l z-aYPEAV6#=Cc&|XUl+2lJ+*Br5OGH{%wcGe`Drbsg%hYx+N5bzSuapHGj4d-9mP79 zQz-AaG$k8}8u%ITz;)M4PYjnCwt@B;zVlitj3^iEm;~Enl(7$YFI4HB*~h;}eXgWa13R4u{;Qtz z0eHe<>#C%)3N$(1CymO2sUUUH`|ZZP0rPa=Hm?d@#A zm4omP8Qu@xl#lEZzB4o}g}53M4JxUa?lv>};6>M@X7BERebX5Mx*JmxwiW(Sv%zrZ zhL@w&g80_DuMh#h4Y(X%9z6zmpTLR}C03zECoj^T2$2$Sg?`|yLa1Rt8QDI0l!c`9 z*VaDhFirpN`Dt?Oo&|uN3|YFYkkPq$9$2L8Umj{u9Vb-2kEhQ$B#taAquz~+eO()k z8T&V@jRz4d^K>}5LT$@m@q|zLK~J~ck+LKeCkj+#YGhiAbrK8;m4KDbJ(D-``7+M< zEUVD%$W9C0b92FQ7RFSdL==LeH}O-8P8$k#fu1}0`6NQXraT^J&ooPT7?ioG&C=|< zfk-&3vUwSUI4wNj^0)p}@3%$}u6{Mf@8mKmVJS&)<`-KvvD5_vqE?}_SZWigi0pOJ zw1t^Byo)ohZZVOIaS5eT(R!L9Vd;7mMa1_B5&DRL`=@*v&&8J9O-FJ<0d{eBFbY-D zq8;}PO_-QQQ^u+)I=DCKY@3bqTEiXr>6s|M$b+qzB^GQ`waIF5jx1dG4HQD&D`R?! z1@t+%PcahpM=Dnkd`^Oi86zf$he}rA79c$-sCGrb82G>u%Q414mwg_&gP_j;%g`gs zy_npH_LX$pK>SKf64wk#CR}$IAB5~t=1Q;qw8N%8ISr08e?v1L9<}FFU@L?BIn@-N zVcG)cM&S1D&C#r!g~-2@kShJXWFAe$55}xmg&uMzuaAV1ISJ5Aq1wxjdcwJ+00|Q2 zZ77e=AR8+gy@S5lXaTuaBZ{O+N|bsY&V2x4MCY8jW4HCSOr=PxxaZwo_0n_3p4#vF zjC6li(d@j32x}WSM#A%W;m(&tY0G9}9^)ltUK3<}X(rw=S$a^D8Uj@-6wd}cjfWA< zv_L=Xk!t5~-@;RMPOX7XNN$}jC$)zUgGy2V#^sY7>W(TI#M~;(XIfMALgFWW$C**U z(DIzxj8uf@`Xan9P=cXy_1~$zz;d%#VYqRdUkBZSD_J`8;4T9rl{F_Yb~0K}#385Q zf1f~>_kuodd!D*C>Q-aMv|aW83KfLh8e+(7S@{kK@V0tnZMcPObrr(79jcVu$)&Lq zAhB)JEd$AhLLA0w-h}vU$A~Y}KT5OEHNbm8{XQ(%uz{!T>0n*LZCYO@`Lce-PAdN=p5$uA>F`!?d9JUT!&vP!8 zss*FENmk?)K)GQntu;6yY+sHmZDU9GNGlxi4rr%~!CrgKsO-#s74J>RbA29IQTA$7 z6E54wIfo143`Tqs+3n)7`l#kLZ^Rv%x_b_3fNy4L8=#PgWIYa3)&M@jnXyd0HvoFN zw=7O4=Q<=;XSPtRpK>JgBVl<#kMzrOvsQXG>jRQ`w_M>jzTGoG+}|Hk8-IO3;13 z1w~F1oQ!|Zj5$5#q_6n3L4Q%^rp&>6twNKFs=-=`7R|7!YBx-d@>A2?tqQJ?Z@oH4 z|Be)jF$p9{b|EJj%FJHt#jYaK`zIw-Sdaijcg%&TV{+=CH6`2! z)i}dXse!HMXq`8nAc&4##-BN&eoQm zvi$xe3ZrJM<);5F$JuId9stvQ@`x>QN>U=S*T(W)(@ximbCR{a{M~;lCInjLcoaP5w-#fZDmxm2UC| z1vl@*LH(4ft0wQfiJj7BBV+31OONN!YacTqE?@J82F}@#1@p%b%RAKy>e<60z%wbj zgtIBcsn3$QoiuKSzF*G*5^zsY>xPSnB&Z z+%pf=h{2-}uq<`;cDzMl&3E1sejz105v4g81ZH?aV%G`t4$D}|l}RGdqMghFZM!=C zxJ$J~hss*c+5z!;6=$NR5%RqK#0iF+#6a`i+GR>$=~AEMm(?nMlaS}=oADQJG6*GZ zgxtWp3wi)JKh_o=u|Hq~&;GpAP6`!?1-T5^Y+SZt^j#cNDX6UyG- z#|DXPNDO$iyiBQQT7~&7(i0V7-VERyNScPUx*w0(xW%OEFHiynL7V~!d@mDL8+Stb z)a5l2+VNMi?60myYFHtDVXi)9)ByAEWdSNy1FaK!_9t-1aEJPTl`kB@Mv%nvi5Ljg z*VYESz2Z^6f?&bl6P1{8!S*@}adm{Dlp z##&Nx%d8_rggxrbr#|g~Yp{(vh7l~;83FgmX)ez-TIsvx_!9)5c53Bh9l$ni zJC>MgMKUYdx!RnL&v4F14P=-BY+g0v8SNuc0<0Pke+CAvlkbym@zI6PMo5YNi4KvD z_sa|&<9POA)f}sm0C7LM)H2)b;lf6Y&9zuXeCH6?ee`UV}`@E;xLy z_y@qyUXlTHJzRRQZL@9TUn-nlzD7{#c6!yh)$$;^j^{G0R8ph4agWLo?^vdo|2{Wf zFlV+tf&iiA|IhA>+yKb8Mx~Tlfi0Zm*6LPbyZjV*Ya$SCO8ileemEfB%7asY`Re;r zbTKb>pJ;$MWho50T2Znba{6I)qR%p3lsHKgT&9tNT6KPzp4JC${6^?-1${(x9%K_} z;^Oija?TJJzdh&__!$UA>e6~??F*;yCpJH82$`5RklW8j+x$TP>BN+NUKM9j8^5yv zm&I$CxF|7<3|X&?$?LltFkJ!r(W%idx+qWP7;sxQz;F zR}TC*B`E9G-^K1ZJIt^{TvyCC%Xla8YOW>31}%lKaGM(@_-Q9-z^R>l}kop#ul`XLvpdDr{h>EU)LxNzR#9luWUF(wHT*1lqUP8>y znC^s4W`brdwZyn3Z`fWao`}BQNXN~9>!2$l?7@_mEl6EHQZMx1!)t`(4{+6dN_0^Z z{}Zvr?}c8l##^#5CU?+GWhpRi3Z1yvGEepKv?u&07V@t<-qZwh-`H7}tBwvK{~OO6 zw_v?L*Na1kPEw(?s8_4xbr`AjBg=yrc#SNwg~^4)H>R^CJjPh9l!!>Ik5Uaz>Em0vX-0RxoWyPnr$9KP2$c~r;P)Abo&vIp zaF(4Q?I${v&gaC}5TQw%q8GC-Hy?dsMzepWSL`|8d>&R3`4^9TZ}R3m`oZllc;{`w z1jOe$2^zuT{;`nWJ%xRGHQXa<&hly#Xf{QLjzpWP3NIY0{!%ox7FF3sS<#gA=;LV> zJ5d%fwddnezJ2}c-7#nae?a^t3(;TXtUIkcPp1iJaJn+HjLJW`*0EsWK<&LKi{Fkm zh5f>`kcJkfQZGZ zF%8nq0P#z%m(#2AduqT4Ymg#Z_lw*TN`&R350WiE@?tb0k$6D4V7+mxY#`oj7h?+D zYrIrV?hLZYR4>3PpQ_l>Jh1I6&Og(_;2OQ6&cGdyiO*3|1D_=Z6Wo2}I{;~c*@LtqCDE{rY^P5@zkr9(O zfUP<3UrG9wPFtCFzm!noqq4R@CUif@!9imQi^B?5`h>{7(ghUrxocNz30^C(VuvF9 zKp0^!=DWSJLK;Z}bN7IaVwS!$kNwzwi3*KLNXlteP4AtY=^8*x_gc6_Wn1ewd59A7 z=MvKkLo?%)hb5`KGsi|)(qblv$WEFsA;Zzftk0jqAg;}DAHS8mPSS*>K*Maiw%Lf#eI8_Rh z1|hy%zUvJ#34ei+B(q@x^!s(UQYA5sH!3@ZN%` zhR`z*Eltwljwb1L<6_~QWM4?z@o|c91T0(N4YJ4m+X12nN$#55OlDO_ zZ2XPP<&hS?NBhfzEB(U-Os6wgX|Ud~Lvo6f?hlVbKX)aD2OsS{OsU&ro4rwIHAJo| zg@7C{I}u6j;`<=Pb5!%N?ZZ{V3#-gy)~QCW&s_mN9E5!sADM|&m>NBcw;oT^EDlWg zU&i_q7hvq1!pZvS-cqG{vi*CJQ=bxK?oCr~iQpdV+wvo&b|(>8(g`!c;cWIytydjy zhpD4>wTZ_v#>m$VY4Rb!&uy)Q>oV$9&t{bcax1rRVJPyY&k$Ci`x?JYi51Q=b8G5lv73KAJA1zD}GEV?Rh~mppC>DEth%HPBP3cFRpS|nQBaS! zgx&nkOR9XRl8K~5N zB({?T#0y!~VKD=EZ!Wb}IXL*tJ!P-hs+njoOB&UQG)sB>@Uk=%JwMHU6~!8)KE}*s&PamGy4vedXYU9zkGe8Iw$-uG56ur81{;a2dPR`M}rDYgYc!xcY+Y^EO|1MOcgf z{mcxqj1a+egI~5;7MgerGa{t4xZHE8e&s<|bS{sGAaKe6T=AU!MbG2hd~)~)Rq-Bl zitJ2l87~~gM;NAl$wQ9Na4U+j6!4DoSBu8pW24%^|CS>ot-rD_J&Zn3e%zxXjL;n)&N-R3rT7rZHcSLii~s4H?) zBW);O0Vy{f$~EAlIij}5hMzjH)4xzsZf;Wz{V<8yc``T*`m4K4j5#Aaq{%p&7OTH9 z7ug6yh}{D6kD`;c*1F1g0+-y@Q`KaACl-H3bGY5wp2LM^&>4UH5YO zM`}zIdaQ98Im+Xam(7CrKEF4*y z7{d)_56VNxtpcISds23?8nlbk-ctWSUrwMT#!8XW{Lj}BHrBt>A1k!zw>k!e`u#xO zY+HVd7fHkscoWQWDKQDQOf_M&GhPyT^={>)i1#iK%7hE=U4Li2mbsbUmwTvh=~ETH zPQm`uUCnhue&$10F(ZStu_ZC_fpv~aP2I7t#M#;vKYfl?gt&9AqZ_8<*bN()3R2^w z3#36By|YX;9Gt74-#V(R8r2xYQ_-gZ2O+ug-0yrE-C=Bm$GiS)_>9741!rdoSq+Z{-BYAy9^EcPW<9iT?Cb4>lkA3cFF7h?QvKfY9m<$2#C zgXAuY`m#6_<)F< z6fU%+Q%n$d_g|mW_zhG0(_~KOHr-DLR%g1Vr*VAB9^;Q?8@Sr7FJr{j&v=EPVG<{31ojZ^L5LLJsqrf{lrfgZIkPt-`Z(T_j5S_aOyG5+-8neGTwr36IW z+Kc+c8{;ma+BB8h4xA|WrM7`Y2-35UogGF(e{ei05;7e>`J+C!Ygqajt<;!}vaRuE+pZ)wE*gi%()cvlBFq1<~Z5D*6T3 zXK7=Ome;?yeVdd>m=}aP(&g6(Q>C5a^Bp@ci62MqJ)RR>$%)`s*G*Y5h80!`AL`+q^-?;*WXT5| zA)DM=?hnrH4p>zI_h^9^-wxKzgIbX1tAqg;p|vkyP%302u+4^;XaM`+rjXER)qf#b z0>>g5TjW78#MvB!lWzEx42Lz!-zeycR(b`(-fh7=ktKwwAdxWADG zc`}J*ovt>w28jh>?QT2PzyvQWagRtn#?^1|TtSXl*{nY{mwqLaD`NMXAI{2pX2k!| zsm~q;3aX*>93z@hz_NALDC1ITPyUp@o{CB-qGz{@^7Zoy{!J@Ug$-)4nW&4E7^g^e zx(q|Yl@;b|p%5DlvrM+vR*&62Qos)gh%C9zR%SZau&jQ*UCDY0?lc8 zVW1aqip^+t(dd4gzM9drcXk&RoRbdySaOP%)$jDgs3Xe#(q*{rftC1<%n0rkS`=20 z0ScjycAMc2i0`=d?+%I_%e%_J@cB5%xXtMvF2EE@in!Q^1?8CbFP3=n_JG<%zq2%* zQD!c)TKP0MC;*^%VwZ|XezZsHbhR<21B@x4P$MM-U@0ILSq#&a3VIUUh*cW zi-(63hP_yNA~zi<5In%PL;v1EFO_<;0=J1f=9;BM4pI3(6x>%bXY{&K*99WL8Isnw z#Az_XMyvuA{lk)DE=C9<8=|pSU}IYw3`Y4MUKdWIbE$9*#^xqaOGTEE0g zVqO~JO}qyyfy|H~3nVwuDKa4&S_#Di1Qp;l4%IZu9dEX~JALhi@HJPiE{0~vzCQ4_ z`SJk;Si*D;nPVXTi$KUgpFK|8`YLbhGN98}1B%J<4KA`6<2cn5`yK2saN_v%k zZ)NC#_xYH6!bKBKnUeP5QSM=r;TF{g2=9uS`|n(c6BmjPFX`1I(trZe=nx=hNSLgC zBVhdkZ|8p6nytT4%t$sLJ!g&Q3q&UPCcmz5vGt~^5wEp~ow5#-K(bCmR|YBBN_I+? z&|iM|zvEq?OoWhz3&^HH5sj4EN~8RPF&%IT9^JfFCxBekkhvY>l!WDGg{fBPx%1-? ztKQj%PqLitJvYm47Ct>?KL^JY{UyY%lA8ow5D_k<2}yosf1wH1rJJLG!^;lABzGQh zY;e#bxyC%z=!AW>3W0mW>Zi(Zr+CR=;wnUZNR*Wo zY6p;H>Qc^^A8SoQKFf?=7z*=ktiMNhQGo1Lt&{$dL(g23@IW1b0}m!^hQ6A6pSedM zd4w(Gj>rpOu_JM#e3C_2-POH|2oV!MkS-^}qGiwC+~98?)+TN>p1=)ARGpu#?pnS^ z6hNWMk^-~3Rdc95tkoWqm1U$GIWhy6RCu+u2< z5=ovUu--oHS`#{Z5Hi^`AXb^-m>k!~4ROcL*s|a;vJ*E}=K_qDtcB8qVzv!K?ulR} zF;;Jb_Sl=wu127R`%C;xNV&3^6)Zj;?yoKqJ&-s&er#26$KVW5AthgUB!yQ>*;x-ciR`dI+ZC?Z4ksG!^? z{m;E?vTF^gX^Ue?iM-QY=`Ct2lJTVBcKs}e)v-MHna-m!+nN+Bb!sDtK+v1<^a~C> zF%oPbJF>3+1M>~%bKvjMo9m$42?bM5{4&*lOnP`d>FxiL*AP%7pNet;!lYNp$Au^Mr;4ACF4Z->+g!&otFT&W*h;&kx z0fgq%;zp;cXMF}P`VpUBK7T6NwvIc?);bmbn!Nz{-PdgzO&Nai%D_Cq_U^-9GLFUe z6|%z}qX1M1ap%*cuLpdN7A>yFl%W@dKf^$kF`HOIDEQWcqFE0~7|Wlo+Jql-qM$oy z!(iFAJ!ueO6uVI_}8O7+YIMoYhgy2OkXxVQ+g4q(>vVsS<{lQkv3dJAP3?;dUSDzS%R$5ap`lP zl=nHs4}mZ)nAh`M&?#{odkf-Nhw@>bRv^r+|1C^ZSuZ+Wuv1?DpTYGOzGI|JPVWyh zvSZ95nWG zCOB6NifZw5zKoYrUoBsfqb;uwlBLo9nKFaRga7#R$OO9k87!^D% zyIeFgZa3J0`Fbhx44Wt>whvyuGQCX4oplqS7q`51bg^>SP|0_MLp|2v|9N=E&Tx!Z z*c4y@n~Q6^c&M4J$p$$45sm?-KR$CRer+4!Uz&7XGTJ6>v~UPuJ@TW(f6u^n3a`iiKa-i z2jiQSv4?yVJXa1SmiS=|-8%aYu3j>X%3gE;?QlQ;?3NahJRQ`UF=f20bMMEo@F1W8 zdu{}Ioeg=3uXYLUY%LFEP0AhzLz-Qaqy7s!D9O_NX7L4PX|-Nv4vo`Hr3YPp=g&~t zLkb1%khN(p)7tCZhUhVdI-9ud(ndESdfrv&jS*iAu(xalvgC!EEYSO|-Ytnx(T$q( z1BH2uA%;e{HyU3zx7ckdHjasox3SbLN0aQmcVJb;);2!-=?M_}2{lv$(xjeH zBq&k@1$#hIY+NiTioyw?qA1l~gB3d}DvC-(MX{n{R}415243$~6q5X&XU)vslSA(N z{=WD7{`mg*HcV#bnKf(HtXWfcIWI0NnfTbqpFaP`E1@38zjOE%3-5h?`Pji{mEZEx z9X)%IwasZ%T6g28_q99w`J7wE z_Wf>tpF4N7xp?!Tx4yEb)y%DT)pTA`wyyEUwr!eES~o^?(7%B9o4PaXZ_ z`$KPA`13Qj|M}`a7Y#jP-M1%w)O7jg%}q!A{^TRe+qKJ?Q4#6&=fDfjX>+fm#?L#e=bU*2}4Ntau_t-c8_}8;b zJ}ND^=&EJ$XU1Rj%jj4B^?Z|)mp}5z)IVYqN`HBLR@=AsF1l*q^W9?CJQCkDu=&b< zX@{RT^rModz2}_sY3uoA-*k9-{Y(E|+JED?XKSv0b;E+EDpzE6d9eR`gNC;q`uxS0 zKA3#h-5*a|xc$Jbg;RelIcxs7+񺊪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 z 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%0A0D+kRUf|jO{@VL?qJ&l=$&FriyUsPY&VqO20 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 z z^><6>E*bf?e(rXeE3m}qwfAOMv$GB38Le-$KzlcSKq>Cc!U_b|I6KswnuW%0AG%bE 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 literal 0 HcmV?d00001 diff --git a/testing/e2e/e2e/go.mod b/testing/e2e/e2e/go.mod new file mode 100644 index 00000000..d25994bc --- /dev/null +++ b/testing/e2e/e2e/go.mod @@ -0,0 +1,7 @@ +module github.com/kube-vip/kube-vip/testing/e2e/servicesClient + +go 1.19 + +require github.com/sirupsen/logrus v1.9.0 + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/testing/e2e/e2e/go.sum b/testing/e2e/e2e/go.sum new file mode 100644 index 00000000..ed655373 --- /dev/null +++ b/testing/e2e/e2e/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testing/e2e/e2e/main.go b/testing/e2e/e2e/main.go new file mode 100644 index 00000000..61a620ba --- /dev/null +++ b/testing/e2e/e2e/main.go @@ -0,0 +1,66 @@ +package main + +// This is largely to test outbound (egress) connections +import ( + "fmt" + "net" + "net/http" + "os" + "strings" + "time" + + log "github.com/sirupsen/logrus" +) + +func main() { + // Lookup environment variables + mode, exists := os.LookupEnv("E2EMODE") + if !exists { + log.Fatal("The environment variable E2ESERVER, was not set") + } + + switch mode { + case strings.ToUpper("SERVER"): + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello!") + }) + + log.Info("Starting server at port 80") + if err := http.ListenAndServe(":80", nil); err != nil { + log.Fatal(err) + } + case strings.ToUpper("CLIENT"): + address, exists := os.LookupEnv("E2EADDRESS") + if !exists { + log.Fatal("The environment variable E2EADDRESS, was not set") + } + for { + + // Connect to e2e endpoint with a second timeout + conn, err := net.DialTimeout("tcp", address+":12345", time.Second) + if err != nil { + log.Fatalf("Dial failed: %v", err.Error()) + } + _, err = conn.Write([]byte("The Grid, a digital frontier")) + if err != nil { + log.Fatalf("Write data failed: %v ", err.Error()) + } + + // buffer to get data + received := make([]byte, 1024) + _, err = conn.Read(received) + if err != nil { + log.Fatalf("Read data failed:", err.Error()) + } + + println("Received message: %s", string(received)) + + conn.Close() + // Wait for a second and connect again + time.Sleep(time.Second) + } + default: + log.Fatalf("Unknown mode [%s]", mode) + } + +} diff --git a/testing/e2e/services/kind-config.yaml b/testing/e2e/services/kind-config.yaml new file mode 100644 index 00000000..58644b0d --- /dev/null +++ b/testing/e2e/services/kind-config.yaml @@ -0,0 +1,9 @@ +# three node (two workers) cluster config +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane +- role: worker +- role: worker +- role: worker +EOF diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go new file mode 100644 index 00000000..5deb03d2 --- /dev/null +++ b/testing/e2e/services/kind.go @@ -0,0 +1,74 @@ +package main + +import ( + "os" + "os/exec" + "time" + + log "github.com/sirupsen/logrus" + kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/kind/pkg/cluster" + "sigs.k8s.io/kind/pkg/cmd" + load "sigs.k8s.io/kind/pkg/cmd/kind/load/docker-image" +) + +var provider *cluster.Provider + +func createKind() error { + clusterConfig := kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv4Family, + }, + Nodes: []kindconfigv1alpha4.Node{ + { + Role: kindconfigv1alpha4.ControlPlaneRole, + }, + { + Role: kindconfigv1alpha4.WorkerRole, + }, + { + Role: kindconfigv1alpha4.WorkerRole, + }, + { + Role: kindconfigv1alpha4.WorkerRole, + }, + }, + } + + imagePath := os.Getenv("E2E_IMAGE_PATH") + + provider = cluster.NewProvider(cluster.ProviderWithLogger(cmd.NewLogger()), cluster.ProviderWithDocker()) + err := provider.Create("services", cluster.CreateWithV1Alpha4Config(&clusterConfig)) + if err != nil { + log.Error(err) + return deleteKind() + + } + loadImageCmd := load.NewCommand(cmd.NewLogger(), cmd.StandardIOStreams()) + loadImageCmd.SetArgs([]string{"--name", "services", imagePath}) + err = loadImageCmd.Execute() + if err != nil { + log.Error(err) + return deleteKind() + } + cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") + if _, err := cmd.CombinedOutput(); err != nil { + log.Fatal(err) + } + cmd = exec.Command("kubectl", "create", "-f", "https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml") + if _, err := cmd.CombinedOutput(); err != nil { + return deleteKind() + } + cmd = exec.Command("kubectl", "create", "-f", "https://kube-vip.io/manifests/rbac.yaml") + if _, err := cmd.CombinedOutput(); err != nil { + return deleteKind() + } + log.Infof("💤 sleeping for a few seconds to let controllers start") + time.Sleep(time.Second * 5) + return nil +} + +func deleteKind() error { + log.Info("🧽 deleting Kind cluster") + return provider.Delete("services", "") +} diff --git a/testing/e2e/services/kubernetes.go b/testing/e2e/services/kubernetes.go new file mode 100644 index 00000000..5c0497c6 --- /dev/null +++ b/testing/e2e/services/kubernetes.go @@ -0,0 +1,282 @@ +package main + +import ( + "context" + "fmt" + "time" + + appsv1 "k8s.io/api/apps/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/cache" + + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + watchtools "k8s.io/client-go/tools/watch" +) + +// service defines the settings for a new service +type service struct { + name string + egress bool // enable egress + policyLocal bool // set the policy to local pods + testHttp bool +} + +type deployment struct { + replicas int + server bool + client bool + address string + nodeAffinity string + name string +} + +func (d *deployment) createKVDs(ctx context.Context, clientset *kubernetes.Clientset) error { + ds := appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "kube-vip-ds", + Namespace: "kube-system", + Labels: map[string]string{ + "app.kubernetes.io/name": "kube-vip-ds", + }, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/name": "kube-vip-ds", + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app.kubernetes.io/name": "kube-vip-ds", + }, + }, + Spec: v1.PodSpec{ + ServiceAccountName: "kube-vip", + HostNetwork: true, + Containers: []v1.Container{ + { + Args: []string{ + "manager", + }, + Env: []v1.EnvVar{ + { + Name: "vip_arp", + Value: "true", + }, + { + Name: "vip_cidr", + Value: "32", + }, + { + Name: "svc_enable", + Value: "true", + }, + { + Name: "svc_election", + Value: "true", + }, + { + Name: "EGRESS_CLEAN", + Value: "true", + }, + { + Name: "vip_loglevel", + Value: "5", + }, + }, + Image: "plndr/kube-vip:dev", + Name: "kube-vip", + SecurityContext: &v1.SecurityContext{ + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{ + "NET_ADMIN", + "NET_RAW", + }, + }, + }, + }, + }, + }, + }, + }, + } + + _, err := clientset.AppsV1().DaemonSets("kube-system").Create(ctx, &ds, metav1.CreateOptions{}) + if err != nil { + return err + } + + return nil + +} +func (d *deployment) createDeployment(ctx context.Context, clientset *kubernetes.Clientset) error { + replicas := int32(d.replicas) + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: d.name, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "kube-vip", + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "kube-vip", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "kube-vip-web", + Image: "plndr/e2e:0.0.1", + Ports: []v1.ContainerPort{ + { + Name: "http", + Protocol: v1.ProtocolTCP, + ContainerPort: 80, + }, + }, + ImagePullPolicy: v1.PullAlways, + }, + }, + }, + }, + }, + } + + if d.server { + deployment.Spec.Template.Spec.Containers[0].Env = + []v1.EnvVar{ + { + Name: "E2EMODE", + Value: "SERVER", + }, + } + } + + if d.client && d.address != "" { + deployment.Spec.Template.Spec.Containers[0].Env = + []v1.EnvVar{ + { + Name: "E2EMODE", + Value: "CLIENT", + }, + { + Name: "E2EADDRESS", + Value: d.address, + }, + } + } + + if d.nodeAffinity != "" { + deployment.Spec.Template.Spec.NodeName = d.nodeAffinity + } + + result, err := clientset.AppsV1().Deployments(v1.NamespaceDefault).Create(ctx, deployment, metav1.CreateOptions{}) + if err != nil { + return err + } + + log.Infof("📝 created deployment [%s]", result.GetObjectMeta().GetName()) + return nil +} + +func (s *service) createService(ctx context.Context, clientset *kubernetes.Clientset) (string, string, error) { + svc := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: s.name, + Namespace: "default", + Labels: map[string]string{ + "app": "kube-vip", + }, + }, + + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Port: 80, + Protocol: v1.ProtocolTCP, + }, + }, + Selector: map[string]string{ + "app": "kube-vip", + }, + ClusterIP: "", + Type: v1.ServiceTypeLoadBalancer, + }, + } + + if s.egress { + svc.Annotations = map[string]string{ //kube-vip.io/egress: "true" + "kube-vip.io/egress": "true", + } + } + if s.policyLocal { + svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal + } + + log.Infof("🌍 creating service [%s]", svc.Name) + _, err := clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, svc, metav1.CreateOptions{}) + if err != nil { + log.Fatal(err) + } + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return clientset.CoreV1().Services(v1.NamespaceDefault).Watch(ctx, metav1.ListOptions{}) + }, + }) + if err != nil { + log.Fatal(err) + } + ch := rw.ResultChan() + go func() { + time.Sleep(time.Second * 10) + rw.Stop() + }() + ready := false + testAddress := "" + currentLeader := "" + // Used for tracking an active endpoint / pod + for event := range ch { + + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) + svc, ok := event.Object.(*v1.Service) + if !ok { + log.Fatalf("unable to parse Kubernetes services from API watcher") + } + if svc.Name == s.name { + if len(svc.Status.LoadBalancer.Ingress) != 0 { + log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + ready = true + testAddress = svc.Status.LoadBalancer.Ingress[0].IP + currentLeader = svc.Annotations["kube-vip.io/vipHost"] + } + } + default: + + } + if ready { + break + } + } + if s.testHttp { + err = httpTest(testAddress) + if err != nil { + return "", "", fmt.Errorf("web retrieval timeout ") + + } + } + return currentLeader, testAddress, nil +} diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index dff91905..be2cd0d6 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -4,12 +4,12 @@ package main import ( "context" "fmt" + "net" "net/http" "os" "path/filepath" "time" - appsv1 "k8s.io/api/apps/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" @@ -27,11 +27,21 @@ import ( // 2. Expose the deployment func main() { + log.Info("🔬 beginning e2e tests") + err := createKind() + if err != nil { + log.Fatal(err) + } + defer deleteKind() + //return + _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") _, ignoreDeployments := os.LookupEnv("IGNORE_DEPLOY") _, ignoreLeaderFailover := os.LookupEnv("IGNORE_LEADER") _, ignoreLeaderActive := os.LookupEnv("IGNORE_ACTIVE") _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") + _, ignoreEgress := os.LookupEnv("IGNORE_EGRESS") + nodeTolerate := os.Getenv("NODE_TOLERATE") d := "kube-vip-deploy" @@ -47,14 +57,29 @@ func main() { } log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + deploy := deployment{} + err = deploy.createKVDs(ctx, clientset) + if err != nil { + log.Fatal(err) + } + if !ignoreSimple { // Simple Deployment test log.Infof("🧪 ---> simple deployment <---") - err = createDeployment(ctx, d, nodeTolerate, 2, clientset) + deploy := deployment{ + name: d, + nodeAffinity: nodeTolerate, + replicas: 2, + server: true, + } + err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } - _, err = createService(ctx, s, clientset, false) + svc := service{ + name: s, + } + _, _, err = svc.createService(ctx, clientset) if err != nil { log.Error(err) } @@ -74,13 +99,24 @@ func main() { if !ignoreDeployments { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments <---") - - err = createDeployment(ctx, l, nodeTolerate, 2, clientset) + deploy := deployment{ + name: l, + nodeAffinity: nodeTolerate, + replicas: 2, + server: true, + } + err = deploy.createDeployment(ctx, clientset) + if err != nil { + log.Fatal(err) + } if err != nil { log.Fatal(err) } for i := 1; i < 5; i++ { - _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, false) + svc := service{ + name: fmt.Sprintf("%s-%d", s, i), + } + _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } @@ -102,11 +138,22 @@ func main() { // Failover tests log.Infof("🧪 ---> leader failover deployment (local policy) <---") - err = createDeployment(ctx, d, nodeTolerate, 2, clientset) + deploy := deployment{ + name: d, + nodeAffinity: nodeTolerate, + replicas: 2, + server: true, + } + err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } - leader, err := createService(ctx, s, clientset, true) + svc := service{ + name: s, + egress: false, + policyLocal: true, + } + leader, _, err := svc.createService(ctx, clientset) if err != nil { log.Error(err) } @@ -132,12 +179,21 @@ func main() { if !ignoreLeaderActive { // pod Failover tests log.Infof("🧪 ---> active pod failover deployment (local policy) <---") - - err = createDeployment(ctx, d, nodeTolerate, 1, clientset) + deploy := deployment{ + name: d, + nodeAffinity: nodeTolerate, + replicas: 1, + server: true, + } + err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } - leader, err := createService(ctx, s, clientset, true) + svc := service{ + name: s, + policyLocal: true, + } + leader, _, err := svc.createService(ctx, clientset) if err != nil { log.Error(err) } @@ -162,13 +218,22 @@ func main() { if !ignoreLocalDeploy { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments (local policy) <---") - - err = createDeployment(ctx, l, nodeTolerate, 2, clientset) + deploy := deployment{ + name: l, + nodeAffinity: nodeTolerate, + replicas: 2, + server: true, + } + err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } for i := 1; i < 5; i++ { - _, err = createService(ctx, fmt.Sprintf("%s-%d", s, i), clientset, true) + svc := service{ + policyLocal: true, + name: fmt.Sprintf("%s-%d", s, i), + } + _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } @@ -186,138 +251,66 @@ func main() { log.Fatal(err) } } -} -func createDeployment(ctx context.Context, name, nodeName string, replica int, clientset *kubernetes.Clientset) error { - replicas := int32(replica) - deployment := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "kube-vip", - }, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app": "kube-vip", - }, - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "kube-vip-web", - Image: "nginx:1.14.2", - Ports: []v1.ContainerPort{ - { - Name: "http", - Protocol: v1.ProtocolTCP, - ContainerPort: 80, - }, - }, - }, - }, - }, - }, - }, - } - - if nodeName != "" { - deployment.Spec.Template.Spec.NodeName = nodeName - } - result, err := clientset.AppsV1().Deployments(v1.NamespaceDefault).Create(ctx, deployment, metav1.CreateOptions{}) - if err != nil { - return err - } - - log.Infof("📝 created deployment [%s]", result.GetObjectMeta().GetName()) - return nil -} - -func createService(ctx context.Context, name string, clientset *kubernetes.Clientset, localTraffic bool) (string, error) { - service := &v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: "default", - Labels: map[string]string{ - "app": "kube-vip", - }, - // Annotations: map[string]string{//kube-vip.io/egress: "true" - // "kube-vip.io/egress":"true", - // }, - }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{ - { - Port: 80, - Protocol: v1.ProtocolTCP, - }, - }, - Selector: map[string]string{ - "app": "kube-vip", - }, - ClusterIP: "", - Type: v1.ServiceTypeLoadBalancer, - // ExternalTrafficPolicy: v1.ServiceExternalTrafficPolicyTypeLocal, - }, - } - if localTraffic { - service.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal - } - log.Infof("🌍 creating service [%s]", service.Name) - _, err := clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, service, metav1.CreateOptions{}) - if err != nil { - log.Fatal(err) - } - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return clientset.CoreV1().Services(v1.NamespaceDefault).Watch(ctx, metav1.ListOptions{}) - }, - }) - if err != nil { - log.Fatal(err) - } - ch := rw.ResultChan() + if !ignoreEgress { + // pod Failover tests + log.Infof("🧪 ---> egress IP re-write (local policy) <---") + var egress string + var found bool + go func() { + found = tcpServer(&egress) + }() + + deploy := deployment{ + name: d, + nodeAffinity: nodeTolerate, + replicas: 1, + client: true, + } + deploy.address = GetLocalIP() + if deploy.address == "" { + log.Fatalf("Unable to detect local IP address") + } else { + log.Infof("📠 found local address [%s]", deploy.address) + } + err = deploy.createDeployment(ctx, clientset) + if err != nil { + log.Fatal(err) + } + svc := service{ + policyLocal: true, + name: s, + egress: true, + } - ready := false - testAddress := "" - currentLeader := "" - // Used for tracking an active endpoint / pod - for event := range ch { + _, egress, err := svc.createService(ctx, clientset) + if err != nil { + log.Fatal(err) + } - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - svc, ok := event.Object.(*v1.Service) - if !ok { - log.Fatalf("unable to parse Kubernetes services from API watcher") - } - if svc.Name == name { - if len(svc.Status.LoadBalancer.Ingress) != 0 { - log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) - ready = true - testAddress = svc.Status.LoadBalancer.Ingress[0].IP - currentLeader = svc.Annotations["kube-vip.io/vipHost"] - } + for i := 1; i < 5; i++ { + if found { + log.Infof("🕵️ egress has correct IP address") + break } - default: + time.Sleep(time.Second * 1) + } + if !found { + log.Errorf("%s %s", egress) } - if ready { - break + log.Warnf("🧹 deleting Service [%s]", s) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + log.Warnf("🧹 deleting deployment [%s]", d) + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) } } - err = httpTest(testAddress) - if err == nil { - return currentLeader, nil - } - return "", fmt.Errorf("web retrieval timeout ") } func httpTest(address string) error { @@ -503,3 +496,61 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber } return nil } + +func tcpServer(egressAddress *string) bool { + listen, err := net.Listen("tcp", ":12345") + if err != nil { + log.Error(err) + } + // close listener + go func() { + time.Sleep(time.Second * 10) + listen.Close() + }() + for { + conn, err := listen.Accept() + if err != nil { + return false + //log.Fatal(err) + } else { + remoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) + log.Infof("📞 incoming from [%s]", remoteAddress) + if remoteAddress == *egressAddress { + return true + } + } + go handleRequest(conn) + } +} + +func handleRequest(conn net.Conn) { + // incoming request + buffer := make([]byte, 1024) + _, err := conn.Read(buffer) + if err != nil { + log.Error(err) + } + // write data to response + time := time.Now().Format(time.ANSIC) + responseStr := fmt.Sprintf("Your message is: %v. Received time: %v", string(buffer[:]), time) + conn.Write([]byte(responseStr)) + + // close conn + conn.Close() +} + +func GetLocalIP() string { + addrs, err := net.InterfaceAddrs() + if err != nil { + return "" + } + for _, address := range addrs { + // check the address type and if it is not a loopback the display it + if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + return ipnet.IP.String() + } + } + } + return "" +} From 606f3e30d50d8d9662ce004eb5165e775501dbf7 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Sun, 19 Feb 2023 16:02:42 +0000 Subject: [PATCH 340/542] Update ci.yaml --- .github/workflows/ci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2373ca18..aa55e729 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,5 +24,7 @@ jobs: run: make dockerx86Action - name: Manifest generate run: ./testing/testing.sh - - name: e2e tests + - name: e2e controlplan e run: DOCKERTAG=action make e2e-tests + - name: e2e services + run: DOCKERTAG=action make service-tests From 7802027f6799c0954aa1324a340a89255620149a Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 19 Feb 2023 16:09:25 +0000 Subject: [PATCH 341/542] lint fixes Signed-off-by: Dan Finneran --- testing/e2e/services/kubernetes.go | 4 ++-- testing/e2e/services/services.go | 27 +++++++++++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/testing/e2e/services/kubernetes.go b/testing/e2e/services/kubernetes.go index 5c0497c6..82fa1b76 100644 --- a/testing/e2e/services/kubernetes.go +++ b/testing/e2e/services/kubernetes.go @@ -21,7 +21,7 @@ type service struct { name string egress bool // enable egress policyLocal bool // set the policy to local pods - testHttp bool + testHTTP bool } type deployment struct { @@ -271,7 +271,7 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien break } } - if s.testHttp { + if s.testHTTP { err = httpTest(testAddress) if err != nil { return "", "", fmt.Errorf("web retrieval timeout ") diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index be2cd0d6..bb61a5dc 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -32,7 +32,12 @@ func main() { if err != nil { log.Fatal(err) } - defer deleteKind() + defer func() { + err := deleteKind() + if err != nil { + log.Fatal(err) + } + }() //return _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") @@ -498,7 +503,7 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber } func tcpServer(egressAddress *string) bool { - listen, err := net.Listen("tcp", ":12345") + listen, err := net.Listen("tcp", ":12345") //nolint if err != nil { log.Error(err) } @@ -512,13 +517,13 @@ func tcpServer(egressAddress *string) bool { if err != nil { return false //log.Fatal(err) - } else { - remoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) - log.Infof("📞 incoming from [%s]", remoteAddress) - if remoteAddress == *egressAddress { - return true - } } + remoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) + log.Infof("📞 incoming from [%s]", remoteAddress) + if remoteAddress == *egressAddress { + return true + } + go handleRequest(conn) } } @@ -533,8 +538,10 @@ func handleRequest(conn net.Conn) { // write data to response time := time.Now().Format(time.ANSIC) responseStr := fmt.Sprintf("Your message is: %v. Received time: %v", string(buffer[:]), time) - conn.Write([]byte(responseStr)) - + _, err = conn.Write([]byte(responseStr)) + if err != nil { + log.Error(err) + } // close conn conn.Close() } From 790d0b52913ada845697d0e34b5cf96ef37c82c7 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 19 Feb 2023 16:27:27 +0000 Subject: [PATCH 342/542] lint fix Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index bb61a5dc..be0de29e 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -288,7 +288,7 @@ func main() { egress: true, } - _, egress, err := svc.createService(ctx, clientset) + ldr, egress, err := svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } @@ -302,7 +302,7 @@ func main() { } if !found { - log.Errorf("%s %s", egress) + log.Errorf("%s %s", ldr, egress) } log.Warnf("🧹 deleting Service [%s]", s) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) From aed43b2defda017a0403805bd6e5b37e33d7680b Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 19 Feb 2023 16:39:08 +0000 Subject: [PATCH 343/542] final fix to makefile Signed-off-by: Dan Finneran --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 75d710b9..3df22983 100644 --- a/Makefile +++ b/Makefile @@ -114,4 +114,4 @@ e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -tags=e2e -v -p testing/e2e service-tests: - E2E_IMAGE_PATH=plndr/kube-vip:dev go run ./testing/e2e/services + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services From 23fda78b45fe6cf1abe3ced489e3ef8fe8e6e464 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 20 Feb 2023 08:41:38 +0000 Subject: [PATCH 344/542] Update ci.yaml removes random manifest generate --- .github/workflows/ci.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index aa55e729..65379a6a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,9 +22,7 @@ jobs: run: make check - name: test docker build run: make dockerx86Action - - name: Manifest generate - run: ./testing/testing.sh - - name: e2e controlplan e + - name: e2e controlplane run: DOCKERTAG=action make e2e-tests - name: e2e services run: DOCKERTAG=action make service-tests From 0c1449798544952ef45e8ad7cfe4469440e8327a Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 20 Feb 2023 09:33:36 +0000 Subject: [PATCH 345/542] Update anchore-syft.yml --- .github/workflows/anchore-syft.yml | 37 +++++++++--------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index a6758d32..3711de4f 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -14,33 +14,18 @@ name: Anchore Syft SBOM scan on: - push: - branches: [ "main" ] - -permissions: - contents: write + release: + types: [published] jobs: - Anchore-Build-Scan: - permissions: - contents: write # required to upload to the Dependency submission API - runs-on: ubuntu-latest - steps: - - name: Checkout the code - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Build the Docker image - run: docker buildx build . --file Dockerfile --load --tag localbuild/testimage:latest - - name: Scan the image and upload dependency results - uses: anchore/sbom-action@bb716408e75840bbb01e839347cd213767269d4a - with: - image: "localbuild/testimage:latest" - artifact-name: image.spdx.json - dependency-snapshot: true - license-check: + sbom: runs-on: ubuntu-latest - name: License Check steps: - - uses: actions/checkout@v3 - - uses: yusufpapurcu/go-license-checker@v0.9 + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.ref_name }} + - name: Anchore SBOM Action + uses: anchore/sbom-action@v0.12.0 + with: + format: cyclonedx-json From 3971c7de0bf407399b0532a2a1fdf783064bf526 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 20 Feb 2023 15:51:33 +0000 Subject: [PATCH 346/542] Tidies actions. Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 2 ++ .github/workflows/main.yaml | 15 +++++++++-- .github/workflows/mainiptables.yaml | 41 ----------------------------- 3 files changed, 15 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/mainiptables.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 65379a6a..3850738d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,6 +23,8 @@ jobs: - name: test docker build run: make dockerx86Action - name: e2e controlplane + if: ${{ github.event.label.name == 'comments welcome' }} run: DOCKERTAG=action make e2e-tests - name: e2e services + if: ${{ github.event.label.name == 'comments welcome' }} run: DOCKERTAG=action make service-tests diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 512aaf26..a8231a24 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -5,7 +5,7 @@ on: - cron: '25 0 * * *' jobs: - docker: + nightly build: runs-on: ubuntu-latest steps: - name: Checkout @@ -25,7 +25,7 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push main branch + - name: Build standard version id: docker_build uses: docker/build-push-action@v2 with: @@ -35,5 +35,16 @@ jobs: tags: >- plndr/kube-vip:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} + - name: Build iptables version + id: docker_build + uses: docker/build-push-action@v2 + with: + context: . + file: Dockerfile_iptables + platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x + push: ${{ github.event_name != 'pull_request' }} + tags: >- + plndr/kube-vip-iptables:${{ github.ref_name }}, + ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }} - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/mainiptables.yaml b/.github/workflows/mainiptables.yaml deleted file mode 100644 index 240f130b..00000000 --- a/.github/workflows/mainiptables.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Build and publish main iptables based image regularly - -on: - schedule: - - cron: '25 0 * * *' - workflow_dispatch: - -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Login to Github Packages - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push main branch - id: docker_build - uses: docker/build-push-action@v2 - with: - context: . - file: Dockerfile_iptables - platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x - push: ${{ github.event_name != 'pull_request' }} - tags: >- - plndr/kube-vip-iptables:${{ github.ref_name }}, - ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }} - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} From 18d11ea2522092f264d3278ce0a13398386b6d7f Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 20 Feb 2023 15:53:10 +0000 Subject: [PATCH 347/542] Set correct labels. Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3850738d..8c79df12 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,8 +23,8 @@ jobs: - name: test docker build run: make dockerx86Action - name: e2e controlplane - if: ${{ github.event.label.name == 'comments welcome' }} + if: ${{ github.event.label.name == 'control plane' }} run: DOCKERTAG=action make e2e-tests - name: e2e services - if: ${{ github.event.label.name == 'comments welcome' }} + if: ${{ github.event.label.name == 'services' }} run: DOCKERTAG=action make service-tests From 53d33d79f4ed9a0ddfd0e8d83ffcc15ff0199479 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 20 Feb 2023 17:36:39 +0000 Subject: [PATCH 348/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3df22983..aaadefdd 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.9 +VERSION := v0.5.10 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) From a92c536de25683f93161819c6630b62538166f16 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 21 Feb 2023 08:56:40 +0000 Subject: [PATCH 349/542] Update main.yaml --- .github/workflows/main.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a8231a24..5279eee0 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -5,7 +5,7 @@ on: - cron: '25 0 * * *' jobs: - nightly build: + nightly_build: runs-on: ubuntu-latest steps: - name: Checkout @@ -36,7 +36,7 @@ jobs: plndr/kube-vip:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} - name: Build iptables version - id: docker_build + id: docker_build_iptables uses: docker/build-push-action@v2 with: context: . @@ -47,4 +47,4 @@ jobs: plndr/kube-vip-iptables:${{ github.ref_name }}, ghcr.io/kube-vip/kube-vip-iptables:${{ github.ref_name }} - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file + run: echo ${{ steps.docker_build.outputs.digest }} From a691b3f12815783422d3652ccd872aeab1523d4b Mon Sep 17 00:00:00 2001 From: ocobleseqx Date: Thu, 23 Feb 2023 16:19:22 +0100 Subject: [PATCH 350/542] check for new equinix ccm annotations Signed-off-by: ocobleseqx --- docs/hybrid/daemonset/index.md | 18 ++++- docs/usage/EquinixMetal/index.md | 18 ++++- pkg/manager/manager_bgp.go | 2 +- pkg/manager/watch_annotations.go | 129 +++++++++++-------------------- 4 files changed, 80 insertions(+), 87 deletions(-) diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 0f8130ac..bc1b71bd 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -153,7 +153,23 @@ kube-vip manifest daemonset \ ### Troubleshooting -If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node: +If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node. +As of Equinix Metal's CCM v3.3.0, the annotations format was changed. This means, you should expect either of the following: + +1. Equinix Metal's CCM v3.3.0 onwards: + +``` +kubectl describe node k8s.bgp02 +... +Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock + node.alpha.kubernetes.io/ttl: 0 + metal.equinix.com/bgp-peers-0-node-asn: 65000 + metal.equinix.com/bgp-peers-0-peer-asn: 65530 + metal.equinix.com/bgp-peers-0-peer-ip: x.x.x.x + metal.equinix.com/bgp-peers-0-src-ip: x.x.x.x +``` + +2. Equinix Metal's CCM before v3.0.0: ``` kubectl describe node k8s.bgp02 diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md index 90c02325..4263d1cc 100644 --- a/docs/usage/EquinixMetal/index.md +++ b/docs/usage/EquinixMetal/index.md @@ -123,7 +123,23 @@ kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name= ## Troubleshooting -If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node: +If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node. +As of Equinix Metal's CCM v3.3.0, the annotations format was changed. This means, you should expect either of the following: + +1. Equinix Metal's CCM v3.3.0 onwards: + +``` +kubectl describe node k8s.bgp02 +... +Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock + node.alpha.kubernetes.io/ttl: 0 + metal.equinix.com/bgp-peers-0-node-asn: 65000 + metal.equinix.com/bgp-peers-0-peer-asn: 65530 + metal.equinix.com/bgp-peers-0-peer-ip: x.x.x.x + metal.equinix.com/bgp-peers-0-src-ip: x.x.x.x +``` + +2. Equinix Metal's CCM before v3.0.0: ``` kubectl describe node k8s.bgp02 diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index ad1c5c7a..c2a80414 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -37,7 +37,7 @@ func (sm *Manager) startBGP() error { log.Error(err) } - // We're using Packet with BGP, popuplate the Peer information from the API + // We're using Packet with BGP, populate the Peer information from the API if sm.config.EnableBGP { log.Infoln("Looking up the BGP configuration from packet") err = equinixmetal.BGPLookup(packetClient, sm.config) diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index d79ffada..dfe23b57 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "fmt" "os" + "regexp" "strconv" "strings" @@ -141,11 +142,26 @@ func (sm *Manager) annotationsWatcher() error { // parseNodeAnnotations parses the annotations on the node and updates the configuration // returning an error if the annotations are not valid or missing; and nil if everything is OK // to continue +// +// The regex expression for each annotation ensures (at least in terms of annotations) backwards +// compatibility with the Equinix Metal annotation format changed in +// https://github.com/equinix/cloud-provider-equinix-metal/releases/tag/v3.3.0 +// +// "metal.equinix.com/`" --> "metal.equinix.com/bgp-peers-{{n}}-`" +// * `` is the relevant information, such as `node-asn` or `peer-ip` +// * `{{n}}` is the number of the peer, always starting with `0` +// * kube-vip is only designed to manage one peer, just look for {{n}} == 0 func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { bgpConfig := bgp.Config{} bgpPeer := bgp.Peer{} - nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] + nodeASN := "" + for k, v := range node.Annotations { + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?node-asn", prefix)) + if regex.Match([]byte(k)) { + nodeASN = v + } + } if nodeASN == "" { return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") } @@ -157,7 +173,13 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er bgpConfig.AS = uint32(u64) - srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] + srcIP := "" + for k, v := range node.Annotations { + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?src-ip", prefix)) + if regex.Match([]byte(k)) { + srcIP = v + } + } if srcIP == "" { return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") } @@ -166,7 +188,13 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er // Also set the BGP peering to the sourceIP bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP - peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] + peerASN := "" + for k, v := range node.Annotations { + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?peer-asn", prefix)) + if regex.Match([]byte(k)) { + peerASN = v + } + } if peerASN == "" { return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") } @@ -178,8 +206,13 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er bgpPeer.AS = uint32(u64) - peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] - + peerIPString := "" + for k, v := range node.Annotations { + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?peer-ip", prefix)) + if regex.Match([]byte(k)) { + peerIPString = v + } + } peerIPs := strings.Split(peerIPString, ",") for _, peerIP := range peerIPs { @@ -188,7 +221,13 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er if ipAddr != "" { bgpPeer.Address = ipAddr // Check if we're also expecting a password for this peer - base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] + base64BGPPassword := "" + for k, v := range node.Annotations { + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?bgp-pass", prefix)) + if regex.Match([]byte(k)) { + base64BGPPassword = v + } + } if base64BGPPassword != "" { // Decode base64 encoded string decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) @@ -207,81 +246,3 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er return bgpConfig, bgpPeer, nil } - -// New annotation structure - -// Node, or local, ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-node-asn -// Peer ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-asn -// Peer IP, default annotation metal.equinix.com/bgp-peers-{{n}}-peer-ip -// Source IP to use when communicating with peer, default annotation metal.equinix.com/bgp-peers-{{n}}-src-ip -// BGP password for peer, default annotation metal.equinix.com/bgp-peers-{{n}}-bgp-pass - -// parseNodeAnnotations parses the annotations on the node and updates the configuration -// returning an error if the annotations are not valid or missing; and nil if everything is OK -// to continue -// func parseNewBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { -// bgpConfig := bgp.Config{} -// bgpPeer := bgp.Peer{} - -// nodeASN := node.Annotations[fmt.Sprintf("%s/node-asn", prefix)] -// if nodeASN == "" { -// return bgpConfig, bgpPeer, fmt.Errorf("node-asn value missing or empty") -// } - -// u64, err := strconv.ParseUint(nodeASN, 10, 32) -// if err != nil { -// return bgpConfig, bgpPeer, err -// } - -// bgpConfig.AS = uint32(u64) - -// srcIP := node.Annotations[fmt.Sprintf("%s/src-ip", prefix)] -// if srcIP == "" { -// return bgpConfig, bgpPeer, fmt.Errorf("src-ip value missing or empty") -// } - -// // Set the routerID (Unique ID for BGP) to the source IP -// // Also set the BGP peering to the sourceIP -// bgpConfig.RouterID, bgpConfig.SourceIP = srcIP, srcIP - -// peerASN := node.Annotations[fmt.Sprintf("%s/peer-asn", prefix)] -// if peerASN == "" { -// return bgpConfig, bgpPeer, fmt.Errorf("peer-asn value missing or empty") -// } - -// u64, err = strconv.ParseUint(peerASN, 10, 32) -// if err != nil { -// return bgpConfig, bgpPeer, err -// } - -// bgpPeer.AS = uint32(u64) - -// peerIPString := node.Annotations[fmt.Sprintf("%s/peer-ip", prefix)] - -// peerIPs := strings.Split(peerIPString, ",") - -// for _, peerIP := range peerIPs { -// ipAddr := strings.TrimSpace(peerIP) - -// if ipAddr != "" { -// bgpPeer.Address = ipAddr -// // Check if we're also expecting a password for this peer -// base64BGPPassword := node.Annotations[fmt.Sprintf("%s/bgp-pass", prefix)] -// if base64BGPPassword != "" { -// // Decode base64 encoded string -// decodedPassword, err := base64.StdEncoding.DecodeString(base64BGPPassword) -// if err != nil { -// return bgpConfig, bgpPeer, err -// } -// // Set the password for each peer -// bgpPeer.Password = string(decodedPassword) -// } -// bgpConfig.Peers = append(bgpConfig.Peers, bgpPeer) -// } -// } - -// log.Debugf("BGPConfig: %v\n", bgpConfig) -// log.Debugf("BGPPeerConfig: %v\n", bgpPeer) - -// return bgpConfig, bgpPeer, nil -// } From 0320d256f34a68d304f95cafc95ba274945add97 Mon Sep 17 00:00:00 2001 From: ocobleseqx Date: Fri, 24 Feb 2023 13:33:16 +0100 Subject: [PATCH 351/542] replace packet with equinix metal in comments and logs Signed-off-by: ocobleseqx --- cmd/kube-vip.go | 2 +- pkg/cluster/clusterLeaderElection.go | 18 ++++++------------ pkg/cluster/service.go | 8 ++++---- pkg/equinixmetal/bgp.go | 2 +- pkg/equinixmetal/eip.go | 8 +++----- pkg/kubevip/config_environment.go | 7 +++---- pkg/kubevip/config_generator.go | 5 +---- pkg/manager/manager_bgp.go | 8 ++++---- pkg/service/manager_bgp.go | 5 ++--- 9 files changed, 25 insertions(+), 38 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 2db5d4c6..1b981f02 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -314,7 +314,7 @@ var kubeVipManager = &cobra.Command{ configMap = envConfigMap } - // If Packet is enabled and there is a provider configuration passed + // If Equinix Metal is enabled and there is a provider configuration passed if initConfig.EnableMetal { if providerConfig != "" { providerAPI, providerProject, err := equinixmetal.GetPacketConfig(providerConfig) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 0a7c6096..b5f36722 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -74,7 +74,6 @@ func NewManager(path string, inCluster bool, port int) (*Manager, error) { // StartCluster - Begins a running instance of the Leader Election cluster func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer *bgp.Server) error { - id, err := os.Hostname() if err != nil { return err @@ -141,7 +140,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * } }() - // If Packet is enabled then we can begin our preparation work + // If Equinix Metal is enabled then we can begin our preparation work var packetClient *packngo.Client if c.EnableMetal { if c.ProviderConfig != "" { @@ -160,9 +159,9 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * log.Error(err) } - // We're using Packet with BGP, popuplate the Peer information from the API + // 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 packet") + log.Infoln("Looking up the BGP configuration from Equinix Metal") err = equinixmetal.BGPLookup(packetClient, c) if err != nil { log.Error(err) @@ -199,7 +198,6 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * if err != nil { log.Errorf("Error starting the VIP service on the leader [%s]", err) } - }, OnStoppedLeading: func() { // we can do cleanup here @@ -260,7 +258,7 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro }() ch := rw.ResultChan() - //defer rw.Stop() + // defer rw.Stop() for event := range ch { // We need to inspect the event and get ResourceVersion out of it @@ -270,9 +268,8 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro if !ok { return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } - //Find the node IP address (this isn't foolproof) + // Find the node IP address (this isn't foolproof) for x := range node.Status.Addresses { - if node.Status.Addresses[x].Type == v1.NodeInternalIP { err = lb.AddBackend(node.Status.Addresses[x].Address, port) if err != nil { @@ -286,9 +283,8 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } - //Find the node IP address (this isn't foolproof) + // Find the node IP address (this isn't foolproof) for x := range node.Status.Addresses { - if node.Status.Addresses[x].Type == v1.NodeInternalIP { err = lb.RemoveBackend(node.Status.Addresses[x].Address, port) if err != nil { @@ -309,7 +305,6 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro statusErr, ok := errObject.(*apierrors.StatusError) if !ok { log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - } status := statusErr.ErrStatus @@ -320,5 +315,4 @@ func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) erro log.Infoln("Exiting Node watcher") return nil - } diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index a95a38b4..be179a93 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -52,10 +52,10 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co } if c.EnableMetal { - // We're not using Packet with BGP + // We're not using Equinix Metal with BGP if !c.EnableBGP { // Attempt to attach the EIP in the standard manner - log.Debugf("Attaching the Packet EIP through the API to this host") + log.Debugf("Attaching the Equinix Metal EIP through the API to this host") err = equinixmetal.AttachEIP(packetClient, c, id) if err != nil { log.Error(err) @@ -101,7 +101,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co } if c.EnableARP { - //ctxArp, cancelArp = context.WithCancel(context.Background()) + // ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() @@ -191,7 +191,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } } if c.EnableARP { - //ctxArp, cancelArp = context.WithCancel(context.Background()) + // ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() diff --git a/pkg/equinixmetal/bgp.go b/pkg/equinixmetal/bgp.go index 49dfb936..f229a196 100644 --- a/pkg/equinixmetal/bgp.go +++ b/pkg/equinixmetal/bgp.go @@ -22,7 +22,7 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error { thisDevice = findSelf(c, k.MetalProjectID) } if thisDevice == nil { - return fmt.Errorf("Unable to find local/this device in packet API") + return fmt.Errorf("Unable to find local/this device in Equinix Metal API") } fmt.Printf("Querying BGP settings for [%s]", thisDevice.Hostname) diff --git a/pkg/equinixmetal/eip.go b/pkg/equinixmetal/eip.go index 031c982a..ca079094 100644 --- a/pkg/equinixmetal/eip.go +++ b/pkg/equinixmetal/eip.go @@ -9,9 +9,8 @@ import ( log "github.com/sirupsen/logrus" ) -// AttachEIP will use the packet APIs to move an EIP and attach to a host +// AttachEIP will use the Equinix Metal APIs to move an EIP and attach to a host func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { - // Use MetalProjectID if it is defined projID := k.MetalProjectID @@ -33,7 +32,6 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { ips, _, _ := c.ProjectIPs.List(projID, &packngo.ListOptions{}) 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) @@ -48,10 +46,10 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { } } - // Lookup this server through the packet API + // Lookup this server through the Equinix Metal API thisDevice := findSelf(c, projID) if thisDevice == nil { - return fmt.Errorf("unable to find local/this device in packet API") + return fmt.Errorf("unable to find local/this device in Equinix Metal API") } // Assign the EIP to this device diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 0e0b150c..ced295be 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -10,7 +10,6 @@ import ( // ParseEnvironment - will popultate the configuration from environment variables func ParseEnvironment(c *Config) error { - // Ensure that logging is set through the environment variables env := os.Getenv(vipLogLevel) // Set default value @@ -345,7 +344,7 @@ func ParseEnvironment(c *Config) error { c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig) } - // Enable the Packet API calls + // Enable the Equinix Metal API calls env = os.Getenv(vipPacket) if env != "" { b, err := strconv.ParseBool(env) @@ -355,14 +354,14 @@ func ParseEnvironment(c *Config) error { c.EnableMetal = b } - // Find the Packet project name + // Find the Equinix Metal project name env = os.Getenv(vipPacketProject) if env != "" { // TODO - parse address net.Host() c.MetalProject = env } - // Find the Packet project ID + // Find the Equinix Metal project ID env = os.Getenv(vipPacketProjectID) if env != "" { // TODO - parse address net.Host() diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 82c9aa53..f126d4e5 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -191,7 +191,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, provider...) } - // If Packet is enabled then add it to the manifest + // If Equinix Metal is enabled then add it to the manifest if c.EnableMetal { packet := []corev1.EnvVar{ { @@ -343,7 +343,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod if c.PrometheusHTTPServer != "" { prometheus := []corev1.EnvVar{ - { Name: prometheusServer, Value: c.PrometheusHTTPServer, @@ -434,7 +433,6 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } return newManifest - } // GeneratePodManifestFromConfig will take a kube-vip config and generate a manifest @@ -446,7 +444,6 @@ func GeneratePodManifestFromConfig(c *Config, imageVersion string, inCluster boo // GenerateDaemonsetManifestFromConfig will take a kube-vip config and generate a manifest func GenerateDaemonsetManifestFromConfig(c *Config, imageVersion string, inCluster, taint bool) string { - // Determine where the pod should be deployed var namespace string if c.ServiceNamespace != "" { diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index c2a80414..03c235cd 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -15,10 +15,10 @@ import ( // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) startBGP() error { var cpCluster *cluster.Cluster - //var ns string + // var ns string var err error - // If Packet is enabled then we can begin our preparation work + // If Equinix Metal is enabled then we can begin our preparation work var packetClient *packngo.Client if sm.config.EnableMetal { if sm.config.ProviderConfig != "" { @@ -37,9 +37,9 @@ func (sm *Manager) startBGP() error { log.Error(err) } - // We're using Packet with BGP, populate the Peer information from the API + // 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 packet") + log.Infoln("Looking up the BGP configuration from Equinix Metal") err = equinixmetal.BGPLookup(packetClient, sm.config) if err != nil { log.Error(err) diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index a46fce1f..7f8987da 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -14,8 +14,7 @@ import ( // Start will begin the Manager, which will start services and watch the configmap func (sm *Manager) startBGP() error { - - // If Packet is enabled then we can begin our preparation work + // If Equinix Metal is enabled then we can begin our preparation work var packetClient *packngo.Client var err error if sm.config.EnableMetal { @@ -24,7 +23,7 @@ func (sm *Manager) startBGP() error { log.Error(err) } - // We're using Packet with BGP, popuplate the Peer information from the API + // 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 packet") err = equinixmetal.BGPLookup(packetClient, sm.config) From 9c6b87c43cd067104ff8be9fd5ed055f045c1c58 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 27 Feb 2023 09:44:42 +0000 Subject: [PATCH 352/542] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 57d9cde0..1d521f8b 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,7 @@ All of these would require a separate level of configuration and in some infrast ## Troubleshooting and Feedback Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/). + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=kube-vip/kube-vip&type=Date)](https://star-history.com/#kube-vip/kube-vip&Date) From 61d5deb0b94b34f1179b01acbf50651467a72543 Mon Sep 17 00:00:00 2001 From: Tyler Schultz Date: Wed, 1 Mar 2023 00:46:10 +0000 Subject: [PATCH 353/542] Readd VIP if address has dadfailed flag Remove the address from in the interface case that a duplicate address is detected. Without this change, kube-vip will take no corrective action, and the address will remain in dadfailed state. Removing and re adding the address causes duplicate address detection to happen again, hopefully successfully the next time. We suspect dadfailed happens when a new leader is elected and the old leader is too slow or fails to delete the IP address. Co-authored-by: Aidan Obley Co-authored-by: Christian Ang Signed-off-by: Tyler Schultz --- pkg/cluster/service.go | 100 +++++++++++++++++++---------------------- pkg/vip/address.go | 27 +++++++++++ 2 files changed, 74 insertions(+), 53 deletions(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index a95a38b4..613c60de 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -104,9 +104,10 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co //ctxArp, cancelArp = context.WithCancel(context.Background()) ipString := cluster.Network.IP() + isIPv6 := vip.IsIPv6(ipString) var ndp *vip.NdpResponder - if vip.IsIPv6(ipString) { + if isIPv6 { ndp, err = vip.NewNDPResponder(c.Interface) if err != nil { log.Fatalf("failed to create new NDP Responder") @@ -123,32 +124,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co case <-ctx.Done(): // if cancel() execute return default: - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } - - if vip.IsIPv4(ipString) { - // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address - err := vip.ARPSendGratuitous(ipString, c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } else { - // Gratuitous NDP, will broadcast new MAC <-> IPv6 address - err := ndp.SendGratuitous(ipString) - if err != nil { - log.Warnf("%v", err) - } - } + cluster.ensureIPAndSendGratuitous(c.Interface, ndp) } time.Sleep(3 * time.Second) } @@ -213,32 +189,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser case <-ctx.Done(): // if cancel() execute return default: - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, c.Interface) - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } - } - - if vip.IsIPv4(ipString) { - // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address - err := vip.ARPSendGratuitous(ipString, c.Interface) - if err != nil { - log.Warnf("%v", err) - } - } else { - // Gratuitous NDP, will broadcast new MAC <-> IPv6 address - err := ndp.SendGratuitous(ipString) - if err != nil { - log.Warnf("%v", err) - } - } + cluster.ensureIPAndSendGratuitous(c.Interface, ndp) } if c.ArpBroadcastRate < 500 { log.Errorf("arp broadcast rate is [%d], this shouldn't be lower that 300ms (defaulting to 3000)", c.ArpBroadcastRate) @@ -281,3 +232,46 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } }() } + +// ensureIPAndSendGratuitous - adds IP to the interface if missing, and send +// either a gratuitous ARP or gratuitous NDP. Re-adds the interface if it is IPv6 +// and in a dadfailed state. +func (cluster *Cluster) ensureIPAndSendGratuitous(iface string, ndp *vip.NdpResponder) { + ipString := cluster.Network.IP() + isIPv6 := vip.IsIPv6(ipString) + // Check if IP is dadfailed + if cluster.Network.IsDADFAIL() { + log.Warnf("IP address is in dadfailed state, removing [%s] from interface [%s]", ipString, iface) + err := cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) + } + } + + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network.IsSet() + if err != nil { + log.Warnf("%v", err) + } + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, iface) + err = cluster.Network.AddIP() + if err != nil { + log.Warnf("%v", err) + } + } + + if isIPv6 { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address + err := vip.ARPSendGratuitous(ipString, iface) + if err != nil { + log.Warnf("%v", err) + } + } +} diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 6d586236..97b1fcc6 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -22,6 +22,7 @@ type Network interface { IP() string SetIP(ip string) error Interface() string + IsDADFAIL() bool IsDNS() bool IsDDNS() bool DDNSHostName() string @@ -160,6 +161,32 @@ func (configurator *network) DeleteIP() error { return nil } +// IsDADFAIL - Returns true if the address is IPv6 and has DADFAILED flag +func (configurator *network) IsDADFAIL() bool { + if configurator.address == nil || !IsIPv6(configurator.address.IP.String()) { + return false + } + + // Get all the address + addresses, err := netlink.AddrList(configurator.link, netlink.FAMILY_V6) + if err != nil { + return false + } + + // Find the VIP and check if it is DADFAILED + for _, address := range addresses { + if address.IP.Equal(configurator.address.IP) && addressHasDADFAILEDFlag(address) { + return true + } + } + + return false +} + +func addressHasDADFAILEDFlag(address netlink.Addr) bool { + return address.Flags&unix.IFA_F_DADFAILED != 0 +} + // IsSet - Check to see if VIP is set func (configurator *network) IsSet() (result bool, err error) { var addresses []netlink.Addr From 798b9c4b8f2551d99986db6a048d5a53cdc7f679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Sun, 5 Mar 2023 12:37:50 +0100 Subject: [PATCH 354/542] go.mod: Bump dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also replace github.com/ghodss/yaml with sigs.k8s.io/yaml (maintained fork). Signed-off-by: Manuel Rüger --- go.mod | 93 +++++----- go.sum | 297 +++++++++++++++++++------------- pkg/kubevip/config_generator.go | 2 +- pkg/kubevip/config_manager.go | 2 +- 4 files changed, 228 insertions(+), 166 deletions(-) diff --git a/go.mod b/go.mod index 20d43182..d4f2b392 100644 --- a/go.mod +++ b/go.mod @@ -6,56 +6,55 @@ replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-2022042 require ( github.com/cloudflare/ipvs v0.8.0 + github.com/coreos/go-iptables v0.6.0 github.com/davecgh/go-spew v1.1.1 - github.com/florianl/go-conntrack v0.3.0 - github.com/ghodss/yaml v1.0.0 + github.com/florianl/go-conntrack v0.4.0 github.com/golang/protobuf v1.5.2 github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.0 - github.com/onsi/ginkgo v1.14.2 - github.com/onsi/gomega v1.21.1 - github.com/osrg/gobgp/v3 v3.7.0 - github.com/packethost/packngo v0.28.0 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.27.2 + github.com/osrg/gobgp/v3 v3.12.0 + github.com/packethost/packngo v0.29.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.13.0 + github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.6.0 - github.com/stretchr/testify v1.8.0 - github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 - golang.org/x/net v0.7.0 - golang.org/x/sys v0.5.0 - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 - k8s.io/api v0.25.2 - k8s.io/apimachinery v0.25.2 - k8s.io/client-go v0.25.2 - k8s.io/klog/v2 v2.70.1 - sigs.k8s.io/kind v0.16.0 + github.com/spf13/cobra v1.6.1 + github.com/stretchr/testify v1.8.2 + github.com/vishvananda/netlink v1.2.1-beta.2 + golang.org/x/net v0.8.0 + golang.org/x/sys v0.6.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde + k8s.io/api v0.26.2 + k8s.io/apimachinery v0.26.2 + k8s.io/client-go v0.26.2 + k8s.io/klog/v2 v2.80.1 + sigs.k8s.io/kind v0.17.0 + sigs.k8s.io/yaml v1.3.0 ) require ( - github.com/BurntSushi/toml v1.0.0 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/BurntSushi/toml v1.2.1 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/coreos/go-iptables v0.6.0 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect @@ -64,53 +63,53 @@ require ( github.com/josharian/native v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect - github.com/magiconair/properties v1.8.5 // indirect + github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc // indirect github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect github.com/mdlayher/genetlink v1.2.0 // indirect - github.com/mdlayher/netlink v1.6.0 // indirect + github.com/mdlayher/netlink v1.6.2 // indirect github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect github.com/mdlayher/socket v0.2.3 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.10.1 // indirect - github.com/subosito/gotenv v1.2.0 // indirect + github.com/spf13/viper v1.14.0 // indirect + github.com/subosito/gotenv v1.4.1 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect - golang.org/x/term v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect + golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect - google.golang.org/grpc v1.45.0 // indirect + google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e // indirect + google.golang.org/grpc v1.51.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect - k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect + k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 8abfaaa1..7f86b6c8 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -13,6 +14,9 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -30,16 +34,14 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -47,13 +49,11 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -61,16 +61,13 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/ipvs v0.8.0 h1:2cl7WMwQI6pklBcwrzdusAqHuPThu/VBdAFNl5r/D5w= github.com/cloudflare/ipvs v0.8.0/go.mod h1:rL2uv7wRPwNsyRig+6EJybJVLVIuw7+L6dc8DPyn+84= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -88,28 +85,26 @@ github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -github.com/florianl/go-conntrack v0.3.0 h1:DUY84Mce+/lE9dJi2EWvGYacQtX2X96J9aVWV99l8UE= -github.com/florianl/go-conntrack v0.3.0/go.mod h1:Q+Um4J/nWUXSbnyzQRMOP4eweSeEQ2G8sfCO5gMz6Pw= +github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= +github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -121,20 +116,21 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -190,6 +186,7 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -197,14 +194,20 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 h1:StGYqyAyFXHsJAZgFD4xLzfCrLOaHd86ZhX/5pZY/4I= github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3/go.mod h1:DwyLjKGwSxRt84j0FEB58tAFgjuEDEu20dyJG2canEI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -215,6 +218,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -237,6 +241,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= +github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -260,12 +265,13 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= @@ -280,6 +286,7 @@ github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/s github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= +github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= @@ -295,20 +302,24 @@ github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnN github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= -github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= +github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= +github.com/mdlayher/netlink v1.6.2 h1:D2zGSkvYsJ6NreeED3JiVTu1lj2sIYATqSaZlhPzUgQ= +github.com/mdlayher/netlink v1.6.2/go.mod h1:O1HXX2sIWSMJ3Qn1BYZk1yZM+7iMki/uYGGiwGyq/iU= github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= +github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= +github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -327,24 +338,27 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.21.1 h1:OB/euWYIExnPBohllTicTHmGTrMaqJ67nIu80j0/uEM= -github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= -github.com/osrg/gobgp/v3 v3.7.0 h1:h+Liq90TsxNKTB/443V8b1o/pwOm94yIsm+gP0RHwOo= -github.com/osrg/gobgp/v3 v3.7.0/go.mod h1:fKQPuk7+4qMiDT5viZTXT/aSEn8yYDkEs5p3NjmU2bw= -github.com/packethost/packngo v0.28.0 h1:3KSmYGgVzVxgH/oYCA+45L1OnPIKU/kWu6uEduB/7qY= -github.com/packethost/packngo v0.28.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY= +github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI= +github.com/osrg/gobgp/v3 v3.12.0 h1:coxnxOntqE1tKMM3a4ftBGe5ft/I5rklxlezISpBXx4= +github.com/osrg/gobgp/v3 v3.12.0/go.mod h1:rAPmqyijW79JIOkGu0BpLUCNdY769l7H+TlOKi5/5KY= +github.com/packethost/packngo v0.29.0 h1:gRIhciVZQ/zLNrIdIdbOUyB/Tw5IgoaXyhP4bvE+D2s= +github.com/packethost/packngo v0.29.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -352,13 +366,14 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= @@ -372,8 +387,8 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -382,25 +397,24 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= -github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -408,15 +422,16 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA= -github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= @@ -425,22 +440,24 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -463,6 +480,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -471,6 +489,10 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -507,27 +529,37 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -539,8 +571,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -579,57 +612,67 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= +golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -672,15 +715,25 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0= -golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3 h1:ARxNdT6I+00ZyY5yRT/ZECkQti4iGrMZX9dvG/ao/LY= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220916014741-473347a5e6e3/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4= +golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c h1:Okh6a1xpnJslG9Mn84pId1Mn+Q8cvpo4HCeeFWHo0cA= +golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c/go.mod h1:enML0deDxY1ux+B6ANGiwtg0yAJi1rctkTpcHNAVPyg= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde h1:ybF7AMzIUikL9x4LgwEmzhXtzRpKNqngme1VGDWz+Nk= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -697,6 +750,9 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -728,16 +784,22 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e h1:S9GbmC1iCgvbLyAokVCwiO6tVIrU9Y7c5oMx1V/ki/Y= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -750,11 +812,12 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -767,26 +830,25 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -804,26 +866,27 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.25.2 h1:v6G8RyFcwf0HR5jQGIAYlvtRNrxMJQG1xJzaSeVnIS8= -k8s.io/api v0.25.2/go.mod h1:qP1Rn4sCVFwx/xIhe+we2cwBLTXNcheRyYXwajonhy0= -k8s.io/apimachinery v0.25.2 h1:WbxfAjCx+AeN8Ilp9joWnyJ6xu9OMeS/fsfjK/5zaQs= -k8s.io/apimachinery v0.25.2/go.mod h1:hqqA1X0bsgsxI6dXsJ4HnNTBOmJNxyPp8dw3u2fSHwA= -k8s.io/client-go v0.25.2 h1:SUPp9p5CwM0yXGQrwYurw9LWz+YtMwhWd0GqOsSiefo= -k8s.io/client-go v0.25.2/go.mod h1:i7cNU7N+yGQmJkewcRD2+Vuj4iz7b30kI8OcL3horQ4= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= -k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= -k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= -k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= +k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= +k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= +k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kind v0.16.0 h1:GFXyyxtPnHFKqXr3ZG8/X0+0K9sl69lejStlPn2WQyM= -sigs.k8s.io/kind v0.16.0/go.mod h1:cKTqagdRyUQmihhBOd+7p43DpOPRn9rHsUC08K1Jbsk= +sigs.k8s.io/kind v0.17.0 h1:CScmGz/wX66puA06Gj8OZb76Wmk7JIjgWf5JDvY7msM= +sigs.k8s.io/kind v0.17.0/go.mod h1:Qqp8AiwOlMZmJWs37Hgs31xcbiYXjtXlRBSftcnZXQk= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index f126d4e5..dad95941 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -4,10 +4,10 @@ import ( "fmt" "strconv" - "github.com/ghodss/yaml" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" ) // generatePodSpec will take a kube-vip config and generate a Pod spec diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 423423ca..82814ca3 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -6,9 +6,9 @@ import ( "strconv" "strings" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "sigs.k8s.io/yaml" ) // ParseBackendConfig - From a9932ec1482418c52a7201eadffc95967e28f7a0 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Mon, 6 Mar 2023 15:50:45 -0800 Subject: [PATCH 355/542] Deprecate loadbalancerIP Add new annotation kube-vip.io/loadbalancerIPs to specify the loadbalancer ip for service Now ip address fetched from loadbalancer service are first fetched from annotation, then fallback to service spec Unit test Signed-off-by: lubronzhan --- docs/architecture/index.md | 10 ++-- docs/hybrid/daemonset/index.md | 10 ++-- docs/hybrid/services/index.md | 24 +++++----- docs/hybrid/static/index.md | 12 ++--- docs/install_daemonset/index.md | 2 +- docs/install_static/index.md | 2 +- docs/usage/on-prem/index.md | 19 +++++--- pkg/manager/instance.go | 28 +++++------ pkg/manager/services.go | 39 ++++++++-------- pkg/manager/watch_services.go | 5 +- pkg/service/services.go | 5 +- pkg/service/util.go | 15 ++++++ pkg/service/util_test.go | 82 +++++++++++++++++++++++++++++++++ pkg/service/watcher.go | 2 +- 14 files changed, 181 insertions(+), 74 deletions(-) create mode 100644 pkg/service/util.go create mode 100644 pkg/service/util_test.go diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 962a573a..6a7f9fe7 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -36,17 +36,17 @@ Below we can see that the failover is typically done within a few seconds as the 64 bytes from 192.168.0.75: icmp_seq=147 ttl=64 time=0.240 ms 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 +4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 148 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 +4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 149 92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 +4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 Request timeout for icmp_seq 150 64 bytes from 192.168.0.75: icmp_seq=151 ttl=64 time=0.245 ms @@ -71,8 +71,8 @@ This section details the flow of events in order for `kube-vip` to advertise a K 2. Within the Kubernetes cluster, a Service object is created with the `spec.type` set to `LoadBalancer`. 3. A controller (typically a [Cloud Controller](/usage/cloud-provider)) has a loop that "watches" for Services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this Service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address, it will update the Service field `spec.loadBalancerIP` with the IP address. -6. `kube-vip` Pods implement a "watcher" for Services that have a `svc.Spec.loadBalancerIP` address attached. +5. Once the controller has an IP address, it will update the Service field `spec.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release +6. `kube-vip` Pods implement a "watcher" for Services that have a `spec.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `svc.Spec.loadBalancerIP`. 7. When a new Service appears, `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the Service network. 8. Finally, `kube-vip` will update the Service status so that the API reflects the object is ready. This is done by updating the `status.loadBalancer.ingress` with the VIP address. diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index bc1b71bd..0d040673 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -1,13 +1,13 @@ # Kube-Vip as a daemonset -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. **Note about Daemonsets** -The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. +The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. -If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. +If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. @@ -43,7 +43,7 @@ The easiest method to generate a manifest is using the container itself, below w ### BGP Example -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. **Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. @@ -136,7 +136,7 @@ spec: ## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) -The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. +The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. **NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index 56a0665a..71597d5d 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -1,4 +1,4 @@ -# Kube-vip services +# Kube-vip services We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. @@ -10,14 +10,14 @@ This section details the flow of events in order for `kube-vip` to advertise a K 2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` 3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address it will update the service `svc.Spec.LoadBalancerIP` with it's new IP address. -6. The `kube-vip` pods also implement a "watcher" for services that have a `svc.Spec.LoadBalancerIP` address attached. +5. Once the controller has an IP address, it will update the Service field `spec.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release +6. `kube-vip` Pods implement a "watcher" for Services that have a `spec.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `svc.Spec.loadBalancerIP`. 7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. 8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. ## CCM -We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. +We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. ## Using the Kube-vip Cloud Provider @@ -48,7 +48,7 @@ or kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 ``` -Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific +Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific ## The Detailed guide @@ -61,7 +61,7 @@ Creating services of `type: LoadBalancer` in *any namespace* will now take addre $ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml ``` -The following output should appear when the manifest is applied: +The following output should appear when the manifest is applied: ``` serviceaccount/kube-vip-cloud-controller created @@ -161,9 +161,9 @@ spec: ### Using DHCP for Load Balancers (experimental) With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a - Kubernetes service on the network. + Kubernetes service on the network. -In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the +In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! ``` @@ -194,7 +194,7 @@ Using UPNP we can create a matching port on the `` all #### Enable UPNP -Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. +Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. **Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) @@ -226,7 +226,7 @@ $ curl externalIP:32380 Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! ``` -# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 +# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 +-------+---------------+--------+----------------------+ | ID | ADDRESS | PUBLIC | CREATED | +-------+---------------+--------+----------------------+ @@ -238,7 +238,7 @@ kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name= ## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) -Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. +Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. **NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. @@ -255,7 +255,7 @@ kube-vip manifest daemonset \ --inCluster | k apply -f - ``` -### Using the existing CCM secret +### Using the existing CCM secret Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index d07f3356..586f1b71 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -1,8 +1,8 @@ # Kube-vip as a Static Pod -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. -The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. +The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. ## Generating a Manifest @@ -43,7 +43,7 @@ kube-vip manifest pod \ ### BGP -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. +This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. **Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. @@ -85,7 +85,7 @@ kube-vip manifest pod \ #### Creating a manifest using the metadata -We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. +We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. ``` kube-vip manifest pod \ @@ -117,7 +117,7 @@ Due to an oddity with `kubeadm` we can't have our `kube-vip` manifest present ** ``` sudo kubeadm join $VIP:6443 \ - --token w5atsr.blahblahblah + --token w5atsr.blahblahblah --control-plane \ --certificate-key abc123 ``` @@ -126,4 +126,4 @@ sudo kubeadm join $VIP:6443 \ ## Services -At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. +At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 9777add8..31de07b9 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -10,7 +10,7 @@ Unlike running `kube-vip` as a [static Pod](/install_static) there are a few mor ## Kube-Vip as HA, Load Balancer, or both -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Create the RBAC settings diff --git a/docs/install_static/index.md b/docs/install_static/index.md index f2e83b59..95e5a24d 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -17,7 +17,7 @@ The sequence of events for building a highly available Kubernetes cluster with ` ## Kube-Vip as HA, Load Balancer, or both -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Generating a Manifest diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index afafe84c..8d563c4e 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -44,6 +44,7 @@ To manage the IP address ranges for Services of type `LoadBalancer`, the `kube-v - IP ranges [start address - end address] - Multiple pools by CIDR per Namespace - Multiple IP ranges per Namespace (handles overlapping ranges) +- Setting of static addresses through service.spec.annotations `kube-vip.io/loadbalancerIPs` - Setting of static addresses through --load-balancer-ip=x.x.x.x (`kubectl expose` command) To control which IP address range is used for which Service, the following rules are applied: @@ -92,18 +93,15 @@ spec: type: LoadBalancer ``` -We can also expose a specific address by specifying it imperatively on the command line: +We can also expose a specific address by specifying it imperatively in the Service definition: -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` - -or including it in the Service definition: ``` apiVersion: v1 kind: Service metadata: + annotations: + "kube-vip.io/loadbalancerIPs": "1.1.1.1" name: nginx spec: ports: @@ -113,9 +111,16 @@ spec: selector: app: nginx type: LoadBalancer - loadBalancerIP: "1.1.1.1" ``` +Or set it through command line. + +``` +kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 +``` + +Since k8s 1.24, loadbalancerIP field [is deprecated](https://github.com/kubernetes/kubernetes/pull/107235). It's recommended to use the annotations instead of command line or `service.spec.loadBalancerIP` to specify the ip. + ### Using DHCP for Load Balancers (experimental) With `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load balancer address that can be used to access a Kubernetes service on the network. diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 89d7a8c1..986859b3 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -6,13 +6,13 @@ import ( "time" "github.com/insomniacslk/dhcp/dhcpv4/nclient4" + "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" + "github.com/kube-vip/kube-vip/pkg/service" "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" - - "github.com/kube-vip/kube-vip/pkg/cluster" ) const dhcpTimeout = 10 * time.Second @@ -41,9 +41,9 @@ type Instance struct { serviceSnapshot *v1.Service } -func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) { - instanceAddress := service.Spec.LoadBalancerIP - instanceUID := string(service.UID) +func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { + instanceAddress := service.FetchServiceAddress(svc) + instanceUID := string(svc.UID) // Detect if we're using a specific interface for services var serviceInterface string @@ -71,20 +71,20 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) instance := &Instance{ UID: instanceUID, Vip: instanceAddress, - serviceSnapshot: service, + serviceSnapshot: svc, } - if len(service.Spec.Ports) > 0 { - instance.Type = string(service.Spec.Ports[0].Protocol) - instance.Port = service.Spec.Ports[0].Port + if len(svc.Spec.Ports) > 0 { + instance.Type = string(svc.Spec.Ports[0].Protocol) + instance.Port = svc.Spec.Ports[0].Port } - if service.Annotations != nil { - instance.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] - instance.dhcpInterfaceIP = service.Annotations[requestedIP] + if svc.Annotations != nil { + instance.dhcpInterfaceHwaddr = svc.Annotations[hwAddrKey] + instance.dhcpInterfaceIP = svc.Annotations[requestedIP] } // Generate Load Balancer config newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", service.Name), + Name: fmt.Sprintf("%s-load-balancer", svc.Name), Port: int(instance.Port), Type: instance.Type, BindToVip: true, @@ -113,7 +113,7 @@ func NewInstance(service *v1.Service, config *kubevip.Config) (*Instance, error) c, err := cluster.InitCluster(instance.vipConfig, false) if err != nil { - log.Errorf("Failed to add Service %s/%s", service.Namespace, service.Name) + log.Errorf("Failed to add Service %s/%s", svc.Namespace, svc.Name) return nil, err } instance.cluster = c diff --git a/pkg/manager/services.go b/pkg/manager/services.go index f07fbd6c..d2b77c2f 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/kube-vip/kube-vip/pkg/service" "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" @@ -27,15 +28,15 @@ const ( flushContrack = "kube-vip.io/flush-conntrack" ) -func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sync.WaitGroup) error { +func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() log.Debugf("[STARTING] Service Sync") // Iterate through the synchronising services foundInstance := false - newServiceAddress := service.Spec.LoadBalancerIP - newServiceUID := string(service.UID) + newServiceAddress := service.FetchServiceAddress(svc) + newServiceUID := string(svc.UID) for x := range sm.serviceInstances { if sm.serviceInstances[x].UID == newServiceUID { @@ -43,8 +44,8 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy // 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" || !sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0" || - !sm.serviceInstances[x].isDHCP && len(service.Status.LoadBalancer.Ingress) > 0 && - newServiceAddress != service.Status.LoadBalancer.Ingress[0].IP { + !sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && + newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP { if err := sm.deleteService(newServiceUID); err != nil { return err } @@ -56,7 +57,7 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy // This instance wasn't found, we need to add it to the manager if !foundInstance && newServiceAddress != "" { - if err := sm.addService(service); err != nil { + if err := sm.addService(svc); err != nil { return err } } @@ -64,10 +65,10 @@ func (sm *Manager) syncServices(ctx context.Context, service *v1.Service, wg *sy return nil } -func (sm *Manager) addService(service *v1.Service) error { +func (sm *Manager) addService(svc *v1.Service) error { startTime := time.Now() - newService, err := NewInstance(service, sm.config) + newService, err := NewInstance(svc, sm.config) if err != nil { return err } @@ -88,33 +89,35 @@ func (sm *Manager) addService(service *v1.Service) error { return err } + serviceIP := service.FetchServiceAddress(svc) + // Check if we need to flush any conntrack connections (due to some dangling conntrack connections) - if service.Annotations[flushContrack] == "true" { - log.Debugf("Flushing conntrack rules for service [%s]", service.Name) - err = vip.DeleteExistingSessions(service.Spec.LoadBalancerIP, false) + if svc.Annotations[flushContrack] == "true" { + log.Debugf("Flushing conntrack rules for service [%s]", svc.Name) + err = vip.DeleteExistingSessions(serviceIP, false) if err != nil { log.Errorf("Error flushing any remaining egress connections [%s]", err) } - err = vip.DeleteExistingSessions(service.Spec.LoadBalancerIP, true) + err = vip.DeleteExistingSessions(serviceIP, true) if err != nil { log.Errorf("Error flushing any remaining ingress connections [%s]", err) } } // Check if egress is enabled on the service, if so we'll need to configure some rules - if service.Annotations[egress] == "true" { - log.Debugf("Enabling egress for the service [%s]", service.Name) - if service.Annotations[endpoint] != "" { + if svc.Annotations[egress] == "true" { + log.Debugf("Enabling egress for the service [%s]", svc.Name) + if svc.Annotations[endpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(service.Spec.LoadBalancerIP, service.Annotations[endpoint], service.Annotations[egressDestinationPorts]) + err = sm.configureEgress(serviceIP, svc.Annotations[endpoint], svc.Annotations[egressDestinationPorts]) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { - err = sm.updateServiceEndpointAnnotation(service.Annotations[endpoint], service) + err = sm.updateServiceEndpointAnnotation(svc.Annotations[endpoint], svc) if err != nil { log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) } @@ -166,7 +169,7 @@ func (sm *Manager) deleteService(uid string) error { if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) + err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], service.FetchServiceAddress(sm.serviceInstances[x].serviceSnapshot), sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) if err != nil { log.Errorf("%v", err) } diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 4a004bcd..79905d31 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -7,6 +7,7 @@ import ( "sync" "github.com/davecgh/go-spew/spew" + "github.com/kube-vip/kube-vip/pkg/service" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" @@ -101,7 +102,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } // We only care about LoadBalancer services that have been allocated an address - if svc.Spec.LoadBalancerIP == "" { + if service.FetchServiceAddress(svc) == "" { break } @@ -124,7 +125,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - log.Debugf("service [%s] has been added/modified with addresses [%s] and is active [%t]", svc.Name, svc.Spec.LoadBalancerIP, activeService[string(svc.UID)]) + log.Debugf("service [%s] has been added/modified with addresses [%s] and is active [%t]", svc.Name, service.FetchServiceAddress(svc), activeService[string(svc.UID)]) // Scenarios: // 1. diff --git a/pkg/service/services.go b/pkg/service/services.go index 3bcb19f7..7e788ac1 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -14,8 +14,9 @@ import ( ) const ( - hwAddrKey = "kube-vip.io/hwaddr" - requestedIP = "kube-vip.io/requestedIP" + hwAddrKey = "kube-vip.io/hwaddr" + requestedIP = "kube-vip.io/requestedIP" + loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" ) func (sm *Manager) stopService(uid string) error { diff --git a/pkg/service/util.go b/pkg/service/util.go new file mode 100644 index 00000000..7cd8b069 --- /dev/null +++ b/pkg/service/util.go @@ -0,0 +1,15 @@ +package service + +import ( + v1 "k8s.io/api/core/v1" +) + +// it will first fetch from annotations kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP +func FetchServiceAddress(s *v1.Service) string { + if s.Annotations != nil { + if v, ok := s.Annotations[loadbalancerIPAnnotation]; ok { + return v + } + } + return s.Spec.LoadBalancerIP +} diff --git a/pkg/service/util_test.go b/pkg/service/util_test.go new file mode 100644 index 00000000..ec8c440a --- /dev/null +++ b/pkg/service/util_test.go @@ -0,0 +1,82 @@ +package service + +import ( + "testing" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func Test_FetchServiceAddress(t *testing.T) { + + tests := []struct { + name string + svc v1.Service + expectedLBIP string + }{ + { + name: "service with both annotation and spec.loadbalancerIP, get ip from annotations", + svc: v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "name", + Annotations: map[string]string{ + "kube-vip.io/loadbalancerIPs": "192.168.1.1", + }, + }, + Spec: v1.ServiceSpec{ + LoadBalancerIP: "192.168.1.2", + }, + }, + expectedLBIP: "192.168.1.1", + }, + { + name: "service with only annotations", + svc: v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "name", + Annotations: map[string]string{ + "kube-vip.io/loadbalancerIPs": "192.168.1.1", + }, + }, + Spec: v1.ServiceSpec{}, + }, + expectedLBIP: "192.168.1.1", + }, + { + name: "service with only spec.loadbalancerIp", + svc: v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "name", + }, + Spec: v1.ServiceSpec{ + LoadBalancerIP: "192.168.1.2", + }, + }, + expectedLBIP: "192.168.1.2", + }, + { + name: "service without spec.loadbalancerIp and annotations", + svc: v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "name", + }, + Spec: v1.ServiceSpec{}, + }, + expectedLBIP: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ip := FetchServiceAddress(&tt.svc) + if ip != tt.expectedLBIP { + t.Errorf("got ip '%s', expected: '%s'", ip, tt.expectedLBIP) + return + } + }) + } +} diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index 4944249b..cc22aff9 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -47,7 +47,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context) error { if !ok { return fmt.Errorf("Unable to parse Kubernetes services from API watcher") } - if svc.Spec.LoadBalancerIP == "" { + if FetchServiceAddress(svc) == "" { log.Infof("Service [%s] has been added/modified, it has no assigned external addresses", svc.Name) } else { log.Infof("Service [%s] has been added/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) From 332546dd13b1ac873bc0065b001daef49c79a1a2 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Mon, 6 Mar 2023 16:00:31 -0800 Subject: [PATCH 356/542] Update readme Signed-off-by: lubronzhan --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d521f8b..e80d016f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # kube-vip -High Availability and Load-Balancing +High Availability and Load-Balancing ![](https://github.com/kube-vip/kube-vip/raw/main/kube-vip.png) @@ -32,7 +32,7 @@ Kube-Vip was originally created to provide a HA solution for the Kubernetes cont - Service LoadBalancer address pools per namespace or global - Service LoadBalancer address via (existing network DHCP) - Service LoadBalancer address exposure to gateway via UPNP -- ... manifest generation, vendor API integrations and many nore... +- ... manifest generation, vendor API integrations and many nore... ## Why? @@ -59,6 +59,12 @@ All of these would require a separate level of configuration and in some infrast Please raise issues on the GitHub repository and as mentioned check the documentation at [https://kube-vip.io](https://kube-vip.io/). +## Contributing + +Thanks for taking the time to join our community and start contributing! We welcome pull requests. Feel free to dig through the [issues](https://github.com/kube-vip/kube-vip/issues) and jump in. + +:warning: This project has issue compiling on MacOS, please compile it on linux distribution + ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=kube-vip/kube-vip&type=Date)](https://star-history.com/#kube-vip/kube-vip&Date) From cc63a133035f0f4162a5a8b3d10d7bef0ae89cb2 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Thu, 9 Mar 2023 00:04:50 -0800 Subject: [PATCH 357/542] Fix the doc link Signed-off-by: lubronzhan --- docs/usage/k3s/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md index a6febbfb..280c2178 100644 --- a/docs/usage/k3s/index.md +++ b/docs/usage/k3s/index.md @@ -11,9 +11,9 @@ In order to make ARP work on Equinix Metal, follow the [metal-gateway](https://m This step is optional but recommended if a K3s installation previously existed. ``` -rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ +rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ ip addr flush dev lo; \ -ip addr add 127.0.0.1/8 dev lo; +ip addr add 127.0.0.1/8 dev lo; ``` ## Step 1: Create Manifests Folder @@ -36,7 +36,7 @@ curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manif ## Step 3: Generate a Kube-Vip DaemonSet Manifest -Refer to the [DaemonSet manifest generation documentation](/installation/daemonset/#generating-a-manifest) for the process to complete this step. +Refer to the [DaemonSet manifest generation documentation](/docs/install_daemonset/index.md#generating-a-manifest) for the process to complete this step. Either store this generated manifest separately in the `/var/lib/rancher/k3s/server/manifests/` directory, or append to the existing RBAC manifest called `kube-vip-rbac.yaml`. As a general best practice, it is a cleaner approach to place all related resources into a single YAML file. From ae25e6bcf3200fd3beedf4b494edc91d1c655055 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Mon, 3 Apr 2023 17:18:00 +0000 Subject: [PATCH 358/542] Adds ability to specifc iptables or nftables Signed-off-by: Dan Finneran --- cmd/kube-vip-start.go | 8 - go.mod | 1 - go.sum | 2 - pkg/iptables/iptables.go | 721 +++++++++++++++++++++++++++++ pkg/iptables/lock.go | 84 ++++ pkg/kubevip/config_environment.go | 10 + pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_manager.go | 111 ----- pkg/kubevip/config_types.go | 3 + pkg/manager/manager_arp.go | 2 +- pkg/manager/service_egress.go | 6 +- pkg/manager/services.go | 2 +- pkg/vip/egress.go | 6 +- testing/e2e/services/kubernetes.go | 4 + testing/e2e/services/services.go | 17 +- 15 files changed, 844 insertions(+), 136 deletions(-) create mode 100644 pkg/iptables/iptables.go create mode 100644 pkg/iptables/lock.go diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 762587b1..055a94eb 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -59,14 +59,6 @@ var kubeVipStart = &cobra.Command{ // If a configuration file is loaded, then it will overwrite flags - if configPath != "" { - c, err := kubevip.OpenConfig(configPath) - if err != nil { - log.Fatalf("%v", err) - } - startConfig = *c - } - // parse environment variables, these will overwrite anything loaded or flags err = kubevip.ParseEnvironment(&startConfig) if err != nil { diff --git a/go.mod b/go.mod index 0a054066..e9c97d8c 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/coreos/go-iptables v0.6.0 github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect diff --git a/go.sum b/go.sum index 2613d480..c7d51c49 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,6 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go new file mode 100644 index 00000000..45a25905 --- /dev/null +++ b/pkg/iptables/iptables.go @@ -0,0 +1,721 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package iptables + +import ( + "bytes" + "fmt" + "io" + "net" + "os/exec" + "regexp" + "strconv" + "strings" + "syscall" +) + +// Adds the output of stderr to exec.ExitError +type Error struct { + exec.ExitError + cmd exec.Cmd + msg string + exitStatus *int //for overriding +} + +func (e *Error) ExitStatus() int { + if e.exitStatus != nil { + return *e.exitStatus + } + return e.Sys().(syscall.WaitStatus).ExitStatus() +} + +func (e *Error) Error() string { + return fmt.Sprintf("running %v: exit status %v: %v", e.cmd.Args, e.ExitStatus(), e.msg) +} + +// IsNotExist returns true if the error is due to the chain or rule not existing +func (e *Error) IsNotExist() bool { + if e.ExitStatus() != 1 { + return false + } + msgNoRuleExist := "Bad rule (does a matching rule exist in that chain?).\n" + msgNoChainExist := "No chain/target/match by that name.\n" + return strings.Contains(e.msg, msgNoRuleExist) || strings.Contains(e.msg, msgNoChainExist) +} + +// Protocol to differentiate between IPv4 and IPv6 +type Protocol byte + +const ( + ProtocolIPv4 Protocol = iota + ProtocolIPv6 +) + +type IPTables struct { + path string + proto Protocol + hasCheck bool + hasWait bool + waitSupportSecond bool + hasRandomFully bool + v1 int + v2 int + v3 int + mode string // the underlying iptables operating mode, e.g. nf_tables + timeout int // time to wait for the iptables lock, default waits forever + + nftables bool +} + +// Stat represents a structured statistic entry. +type Stat struct { + Packets uint64 `json:"pkts"` + Bytes uint64 `json:"bytes"` + Target string `json:"target"` + Protocol string `json:"prot"` + Opt string `json:"opt"` + Input string `json:"in"` + Output string `json:"out"` + Source *net.IPNet `json:"source"` + Destination *net.IPNet `json:"destination"` + Options string `json:"options"` +} + +type option func(*IPTables) + +func IPFamily(proto Protocol) option { + return func(ipt *IPTables) { + ipt.proto = proto + } +} + +func Timeout(timeout int) option { + return func(ipt *IPTables) { + ipt.timeout = timeout + } +} + +func EnableNFTables(enable bool) option { + return func(ipt *IPTables) { + ipt.nftables = enable + } +} + +// New creates a new IPTables configured with the options passed as parameter. +// For backwards compatibility, by default always uses IPv4 and timeout 0. +// i.e. you can create an IPv6 IPTables using a timeout of 5 seconds passing +// the IPFamily and Timeout options as follow: +// +// ip6t := New(IPFamily(ProtocolIPv6), Timeout(5)) +func New(opts ...option) (*IPTables, error) { + + ipt := &IPTables{ + proto: ProtocolIPv4, + timeout: 0, + } + + for _, opt := range opts { + opt(ipt) + } + + path, err := exec.LookPath(getIptablesCommand(ipt.proto, ipt.nftables)) + if err != nil { + return nil, err + } + ipt.path = path + + vstring, err := getIptablesVersionString(path) + if err != nil { + return nil, fmt.Errorf("could not get iptables version: %v", err) + } + v1, v2, v3, mode, err := extractIptablesVersion(vstring) + if err != nil { + return nil, fmt.Errorf("failed to extract iptables version from [%s]: %v", vstring, err) + } + ipt.v1 = v1 + ipt.v2 = v2 + ipt.v3 = v3 + ipt.mode = mode + + checkPresent, waitPresent, waitSupportSecond, randomFullyPresent := getIptablesCommandSupport(v1, v2, v3) + ipt.hasCheck = checkPresent + ipt.hasWait = waitPresent + ipt.waitSupportSecond = waitSupportSecond + ipt.hasRandomFully = randomFullyPresent + + return ipt, nil +} + +// New creates a new IPTables for the given proto. +// The proto will determine which command is used, either "iptables" or "ip6tables". +func NewWithProtocol(proto Protocol) (*IPTables, error) { + return New(IPFamily(proto), Timeout(0)) +} + +// Proto returns the protocol used by this IPTables. +func (ipt *IPTables) Proto() Protocol { + return ipt.proto +} + +// Exists checks if given rulespec in specified table/chain exists +func (ipt *IPTables) Exists(table, chain string, rulespec ...string) (bool, error) { + if !ipt.hasCheck { + return ipt.existsForOldIptables(table, chain, rulespec) + + } + cmd := append([]string{"-t", table, "-C", chain}, rulespec...) + err := ipt.run(cmd...) + eerr, eok := err.(*Error) + switch { + case err == nil: + return true, nil + case eok && eerr.ExitStatus() == 1: + return false, nil + default: + return false, err + } +} + +// Insert inserts rulespec to specified table/chain (in specified pos) +func (ipt *IPTables) Insert(table, chain string, pos int, rulespec ...string) error { + cmd := append([]string{"-t", table, "-I", chain, strconv.Itoa(pos)}, rulespec...) + return ipt.run(cmd...) +} + +// InsertUnique acts like Insert except that it won't insert a duplicate (no matter the position in the chain) +func (ipt *IPTables) InsertUnique(table, chain string, pos int, rulespec ...string) error { + exists, err := ipt.Exists(table, chain, rulespec...) + if err != nil { + return err + } + + if !exists { + return ipt.Insert(table, chain, pos, rulespec...) + } + + return nil +} + +// Append appends rulespec to specified table/chain +func (ipt *IPTables) Append(table, chain string, rulespec ...string) error { + cmd := append([]string{"-t", table, "-A", chain}, rulespec...) + return ipt.run(cmd...) +} + +// AppendUnique acts like Append except that it won't add a duplicate +func (ipt *IPTables) AppendUnique(table, chain string, rulespec ...string) error { + exists, err := ipt.Exists(table, chain, rulespec...) + if err != nil { + return err + } + + if !exists { + return ipt.Append(table, chain, rulespec...) + } + + return nil +} + +// Delete removes rulespec in specified table/chain +func (ipt *IPTables) Delete(table, chain string, rulespec ...string) error { + cmd := append([]string{"-t", table, "-D", chain}, rulespec...) + return ipt.run(cmd...) +} + +func (ipt *IPTables) DeleteIfExists(table, chain string, rulespec ...string) error { + exists, err := ipt.Exists(table, chain, rulespec...) + if err == nil && exists { + err = ipt.Delete(table, chain, rulespec...) + } + return err +} + +// List rules in specified table/chain +func (ipt *IPTables) ListById(table, chain string, id int) (string, error) { + args := []string{"-t", table, "-S", chain, strconv.Itoa(id)} + rule, err := ipt.executeList(args) + if err != nil { + return "", err + } + return rule[0], nil +} + +// List rules in specified table/chain +func (ipt *IPTables) List(table, chain string) ([]string, error) { + args := []string{"-t", table, "-S", chain} + return ipt.executeList(args) +} + +// List rules (with counters) in specified table/chain +func (ipt *IPTables) ListWithCounters(table, chain string) ([]string, error) { + args := []string{"-t", table, "-v", "-S", chain} + return ipt.executeList(args) +} + +// ListChains returns a slice containing the name of each chain in the specified table. +func (ipt *IPTables) ListChains(table string) ([]string, error) { + args := []string{"-t", table, "-S"} + + result, err := ipt.executeList(args) + if err != nil { + return nil, err + } + + // Iterate over rules to find all default (-P) and user-specified (-N) chains. + // Chains definition always come before rules. + // Format is the following: + // -P OUTPUT ACCEPT + // -N Custom + var chains []string + for _, val := range result { + if strings.HasPrefix(val, "-P") || strings.HasPrefix(val, "-N") { + chains = append(chains, strings.Fields(val)[1]) + } else { + break + } + } + return chains, nil +} + +// '-S' is fine with non existing rule index as long as the chain exists +// therefore pass index 1 to reduce overhead for large chains +func (ipt *IPTables) ChainExists(table, chain string) (bool, error) { + err := ipt.run("-t", table, "-S", chain, "1") + eerr, eok := err.(*Error) + switch { + case err == nil: + return true, nil + case eok && eerr.ExitStatus() == 1: + return false, nil + default: + return false, err + } +} + +// Stats lists rules including the byte and packet counts +func (ipt *IPTables) Stats(table, chain string) ([][]string, error) { + args := []string{"-t", table, "-L", chain, "-n", "-v", "-x"} + lines, err := ipt.executeList(args) + if err != nil { + return nil, err + } + + appendSubnet := func(addr string) string { + if strings.IndexByte(addr, byte('/')) < 0 { + if strings.IndexByte(addr, '.') < 0 { + return addr + "/128" + } + return addr + "/32" + } + return addr + } + + ipv6 := ipt.proto == ProtocolIPv6 + + rows := [][]string{} + for i, line := range lines { + // Skip over chain name and field header + if i < 2 { + continue + } + + // Fields: + // 0=pkts 1=bytes 2=target 3=prot 4=opt 5=in 6=out 7=source 8=destination 9=options + line = strings.TrimSpace(line) + fields := strings.Fields(line) + + // The ip6tables verbose output cannot be naively split due to the default "opt" + // field containing 2 single spaces. + if ipv6 { + // Check if field 6 is "opt" or "source" address + dest := fields[6] + ip, _, _ := net.ParseCIDR(dest) + if ip == nil { + ip = net.ParseIP(dest) + } + + // If we detected a CIDR or IP, the "opt" field is empty.. insert it. + if ip != nil { + f := []string{} + f = append(f, fields[:4]...) + f = append(f, " ") // Empty "opt" field for ip6tables + f = append(f, fields[4:]...) + fields = f + } + } + + // Adjust "source" and "destination" to include netmask, to match regular + // List output + fields[7] = appendSubnet(fields[7]) + fields[8] = appendSubnet(fields[8]) + + // Combine "options" fields 9... into a single space-delimited field. + options := fields[9:] + fields = fields[:9] + fields = append(fields, strings.Join(options, " ")) + rows = append(rows, fields) + } + return rows, nil +} + +// ParseStat parses a single statistic row into a Stat struct. The input should +// be a string slice that is returned from calling the Stat method. +func (ipt *IPTables) ParseStat(stat []string) (parsed Stat, err error) { + // For forward-compatibility, expect at least 10 fields in the stat + if len(stat) < 10 { + return parsed, fmt.Errorf("stat contained fewer fields than expected") + } + + // Convert the fields that are not plain strings + parsed.Packets, err = strconv.ParseUint(stat[0], 0, 64) + if err != nil { + return parsed, fmt.Errorf(err.Error(), "could not parse packets") + } + parsed.Bytes, err = strconv.ParseUint(stat[1], 0, 64) + if err != nil { + return parsed, fmt.Errorf(err.Error(), "could not parse bytes") + } + _, parsed.Source, err = net.ParseCIDR(stat[7]) + if err != nil { + return parsed, fmt.Errorf(err.Error(), "could not parse source") + } + _, parsed.Destination, err = net.ParseCIDR(stat[8]) + if err != nil { + return parsed, fmt.Errorf(err.Error(), "could not parse destination") + } + + // Put the fields that are strings + parsed.Target = stat[2] + parsed.Protocol = stat[3] + parsed.Opt = stat[4] + parsed.Input = stat[5] + parsed.Output = stat[6] + parsed.Options = stat[9] + + return parsed, nil +} + +// StructuredStats returns statistics as structured data which may be further +// parsed and marshaled. +func (ipt *IPTables) StructuredStats(table, chain string) ([]Stat, error) { + rawStats, err := ipt.Stats(table, chain) + if err != nil { + return nil, err + } + + structStats := []Stat{} + for _, rawStat := range rawStats { + stat, err := ipt.ParseStat(rawStat) + if err != nil { + return nil, err + } + structStats = append(structStats, stat) + } + + return structStats, nil +} + +func (ipt *IPTables) executeList(args []string) ([]string, error) { + var stdout bytes.Buffer + if err := ipt.runWithOutput(args, &stdout); err != nil { + return nil, err + } + + rules := strings.Split(stdout.String(), "\n") + + // strip trailing newline + if len(rules) > 0 && rules[len(rules)-1] == "" { + rules = rules[:len(rules)-1] + } + + for i, rule := range rules { + rules[i] = filterRuleOutput(rule) + } + + return rules, nil +} + +// NewChain creates a new chain in the specified table. +// If the chain already exists, it will result in an error. +func (ipt *IPTables) NewChain(table, chain string) error { + return ipt.run("-t", table, "-N", chain) +} + +const existsErr = 1 + +// ClearChain flushed (deletes all rules) in the specified table/chain. +// If the chain does not exist, a new one will be created +func (ipt *IPTables) ClearChain(table, chain string) error { + err := ipt.NewChain(table, chain) + + eerr, eok := err.(*Error) + switch { + case err == nil: + return nil + case eok && eerr.ExitStatus() == existsErr: + // chain already exists. Flush (clear) it. + return ipt.run("-t", table, "-F", chain) + default: + return err + } +} + +// RenameChain renames the old chain to the new one. +func (ipt *IPTables) RenameChain(table, oldChain, newChain string) error { + return ipt.run("-t", table, "-E", oldChain, newChain) +} + +// DeleteChain deletes the chain in the specified table. +// The chain must be empty +func (ipt *IPTables) DeleteChain(table, chain string) error { + return ipt.run("-t", table, "-X", chain) +} + +func (ipt *IPTables) ClearAndDeleteChain(table, chain string) error { + exists, err := ipt.ChainExists(table, chain) + if err != nil || !exists { + return err + } + err = ipt.run("-t", table, "-F", chain) + if err == nil { + err = ipt.run("-t", table, "-X", chain) + } + return err +} + +func (ipt *IPTables) ClearAll() error { + return ipt.run("-F") +} + +func (ipt *IPTables) DeleteAll() error { + return ipt.run("-X") +} + +// ChangePolicy changes policy on chain to target +func (ipt *IPTables) ChangePolicy(table, chain, target string) error { + return ipt.run("-t", table, "-P", chain, target) +} + +// Check if the underlying iptables command supports the --random-fully flag +func (ipt *IPTables) HasRandomFully() bool { + return ipt.hasRandomFully +} + +// Return version components of the underlying iptables command +func (ipt *IPTables) GetIptablesVersion() (int, int, int) { + return ipt.v1, ipt.v2, ipt.v3 +} + +// run runs an iptables command with the given arguments, ignoring +// any stdout output +func (ipt *IPTables) run(args ...string) error { + return ipt.runWithOutput(args, nil) +} + +// runWithOutput runs an iptables command with the given arguments, +// writing any stdout output to the given writer +func (ipt *IPTables) runWithOutput(args []string, stdout io.Writer) error { + args = append([]string{ipt.path}, args...) + if ipt.hasWait { + args = append(args, "--wait") + if ipt.timeout != 0 && ipt.waitSupportSecond { + args = append(args, strconv.Itoa(ipt.timeout)) + } + } else { + fmu, err := newXtablesFileLock() + if err != nil { + return err + } + ul, err := fmu.tryLock() + if err != nil { + syscall.Close(fmu.fd) + return err + } + defer func() { + _ = ul.Unlock() + }() + } + + var stderr bytes.Buffer + cmd := exec.Cmd{ + Path: ipt.path, + Args: args, + Stdout: stdout, + Stderr: &stderr, + } + + if err := cmd.Run(); err != nil { + switch e := err.(type) { + case *exec.ExitError: + return &Error{*e, cmd, stderr.String(), nil} + default: + return err + } + } + + return nil +} + +// getIptablesCommand returns the correct command for the given protocol, either "iptables" or "ip6tables". +func getIptablesCommand(proto Protocol, nftables bool) string { + if proto == ProtocolIPv6 { + if nftables { + return "ip6tables-nft" + } + return "ip6tables-legacy" + } else { + if nftables { + return "iptables-nft" + } + return "iptables-legacy" + } +} + +// Checks if iptables has the "-C" and "--wait" flag +func getIptablesCommandSupport(v1 int, v2 int, v3 int) (bool, bool, bool, bool) { + return iptablesHasCheckCommand(v1, v2, v3), iptablesHasWaitCommand(v1, v2, v3), iptablesWaitSupportSecond(v1, v2, v3), iptablesHasRandomFully(v1, v2, v3) +} + +// getIptablesVersion returns the first three components of the iptables version +// and the operating mode (e.g. nf_tables or legacy) +// e.g. "iptables v1.3.66" would return (1, 3, 66, legacy, nil) +func extractIptablesVersion(str string) (int, int, int, string, error) { + versionMatcher := regexp.MustCompile(`v([0-9]+)\.([0-9]+)\.([0-9]+)(?:\s+\((\w+))?`) + result := versionMatcher.FindStringSubmatch(str) + if result == nil { + return 0, 0, 0, "", fmt.Errorf("no iptables version found in string: %s", str) + } + + v1, err := strconv.Atoi(result[1]) + if err != nil { + return 0, 0, 0, "", err + } + + v2, err := strconv.Atoi(result[2]) + if err != nil { + return 0, 0, 0, "", err + } + + v3, err := strconv.Atoi(result[3]) + if err != nil { + return 0, 0, 0, "", err + } + + mode := "legacy" + if result[4] != "" { + mode = result[4] + } + return v1, v2, v3, mode, nil +} + +// Runs "iptables --version" to get the version string +func getIptablesVersionString(path string) (string, error) { + cmd := exec.Command(path, "--version") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return "", err + } + return out.String(), nil +} + +// Checks if an iptables version is after 1.4.11, when --check was added +func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool { + if v1 > 1 { + return true + } + if v1 == 1 && v2 > 4 { + return true + } + if v1 == 1 && v2 == 4 && v3 >= 11 { + return true + } + return false +} + +// Checks if an iptables version is after 1.4.20, when --wait was added +func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool { + if v1 > 1 { + return true + } + if v1 == 1 && v2 > 4 { + return true + } + if v1 == 1 && v2 == 4 && v3 >= 20 { + return true + } + return false +} + +// Checks if an iptablse version is after 1.6.0, when --wait support second +func iptablesWaitSupportSecond(v1 int, v2 int, v3 int) bool { + if v1 > 1 { + return true + } + if v1 == 1 && v2 >= 6 { + return true + } + return false +} + +// Checks if an iptables version is after 1.6.2, when --random-fully was added +func iptablesHasRandomFully(v1 int, v2 int, v3 int) bool { + if v1 > 1 { + return true + } + if v1 == 1 && v2 > 6 { + return true + } + if v1 == 1 && v2 == 6 && v3 >= 2 { + return true + } + return false +} + +// Checks if a rule specification exists for a table +func (ipt *IPTables) existsForOldIptables(table, chain string, rulespec []string) (bool, error) { + rs := strings.Join(append([]string{"-A", chain}, rulespec...), " ") + args := []string{"-t", table, "-S"} + var stdout bytes.Buffer + err := ipt.runWithOutput(args, &stdout) + if err != nil { + return false, err + } + return strings.Contains(stdout.String(), rs), nil +} + +// counterRegex is the regex used to detect nftables counter format +var counterRegex = regexp.MustCompile(`^\[([0-9]+):([0-9]+)\] `) + +// filterRuleOutput works around some inconsistencies in output. +// For example, when iptables is in legacy vs. nftables mode, it produces +// different results. +func filterRuleOutput(rule string) string { + out := rule + + // work around an output difference in nftables mode where counters + // are output in iptables-save format, rather than iptables -S format + // The string begins with "[0:0]" + // + // Fixes #49 + if groups := counterRegex.FindStringSubmatch(out); groups != nil { + // drop the brackets + out = out[len(groups[0]):] + out = fmt.Sprintf("%s -c %s %s", out, groups[1], groups[2]) + } + + return out +} diff --git a/pkg/iptables/lock.go b/pkg/iptables/lock.go new file mode 100644 index 00000000..a88e92b4 --- /dev/null +++ b/pkg/iptables/lock.go @@ -0,0 +1,84 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package iptables + +import ( + "os" + "sync" + "syscall" +) + +const ( + // In earlier versions of iptables, the xtables lock was implemented + // via a Unix socket, but now flock is used via this lockfile: + // http://git.netfilter.org/iptables/commit/?id=aa562a660d1555b13cffbac1e744033e91f82707 + // Note the LSB-conforming "/run" directory does not exist on old + // distributions, so assume "/var" is symlinked + xtablesLockFilePath = "/var/run/xtables.lock" + + defaultFilePerm = 0600 +) + +type Unlocker interface { + Unlock() error +} + +type nopUnlocker struct{} + +func (_ nopUnlocker) Unlock() error { return nil } + +type fileLock struct { + // mu is used to protect against concurrent invocations from within this process + mu sync.Mutex + fd int +} + +// tryLock takes an exclusive lock on the xtables lock file without blocking. +// This is best-effort only: if the exclusive lock would block (i.e. because +// another process already holds it), no error is returned. Otherwise, any +// error encountered during the locking operation is returned. +// The returned Unlocker should be used to release the lock when the caller is +// done invoking iptables commands. +func (l *fileLock) tryLock() (Unlocker, error) { + l.mu.Lock() + err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB) + switch err { + case syscall.EWOULDBLOCK: + l.mu.Unlock() + return nopUnlocker{}, nil + case nil: + return l, nil + default: + l.mu.Unlock() + return nil, err + } +} + +// Unlock closes the underlying file, which implicitly unlocks it as well. It +// also unlocks the associated mutex. +func (l *fileLock) Unlock() error { + defer l.mu.Unlock() + return syscall.Close(l.fd) +} + +// newXtablesFileLock opens a new lock on the xtables lockfile without +// acquiring the lock +func newXtablesFileLock() (*fileLock, error) { + fd, err := syscall.Open(xtablesLockFilePath, os.O_CREATE, defaultFilePerm) + if err != nil { + return nil, err + } + return &fileLock{fd: fd}, nil +} diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 0e0b150c..e75a07ff 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -412,5 +412,15 @@ func ParseEnvironment(c *Config) error { c.EgressServiceCidr = env } + // if this is set then we're enabling nftables + env = os.Getenv(egressWithNftables) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EgressWithNftables = b + } + return nil } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 3d775315..0afe883b 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -42,6 +42,9 @@ const ( //egressServiceCidr - defines the cidr that egress will ignore egressServiceCidr = "egress_servicecidr" + //egressWithNftables - enables using nftables over iptables + egressWithNftables = "egress_withnftables" + ///////////////////////////////////// // TO DO: // Determine how to tidy this mess up diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 423423ca..be605298 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -2,122 +2,11 @@ package kubevip import ( "fmt" - "os" - "strconv" - "strings" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" ) -// ParseBackendConfig - -func ParseBackendConfig(ep string) (*BackEnd, error) { - endpoint := strings.Split(ep, ":") - if len(endpoint) != 2 { - return nil, fmt.Errorf("ensure a backend is in in the format address:port, e.g. 10.0.0.1:8080") - } - p, err := strconv.Atoi(endpoint[1]) - if err != nil { - return nil, err - } - return &BackEnd{Address: endpoint[0], Port: p}, nil -} - -// OpenConfig will attempt to read a file and parse it's contents into a configuration -func OpenConfig(path string) (*Config, error) { - if path == "" { - return nil, fmt.Errorf("path cannot be blank") - } - - log.Infof("Reading configuration from [%s]", path) - - // Check the actual path from the string - if _, err := os.Stat(path); !os.IsNotExist(err) { - // Attempt to read the data - configData, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - // If data is read successfully parse the yaml - var c Config - err = yaml.Unmarshal(configData, &c) - if err != nil { - return nil, err - } - return &c, nil - - } - return nil, fmt.Errorf("error reading [%s]", path) -} - -// PrintConfig - will print out an instance of the kubevip config -func (c *Config) PrintConfig() { - b, _ := yaml.Marshal(c) - - fmt.Print(string(b)) -} - -// SampleConfig will create an example configuration and write it to the specified [path] -func SampleConfig() { - - // Generate Sample configuration - c := &Config{ - - // Virtual IP address - VIP: "192.168.0.100", - // Interface to bind to - Interface: "eth0", - // Load Balancer Configuration - LoadBalancers: []LoadBalancer{ - { - Name: "Kubernetes Control Plane", - Type: "http", - Port: 6443, - BindToVip: true, - Backends: []BackEnd{ - { - Address: "192.168.0.100", - Port: 6443, - }, - { - Address: "192.168.0.101", - Port: 6443, - }, - { - Address: "192.168.0.102", - Port: 6443, - }, - }, - }, - }, - } - b, _ := yaml.Marshal(c) - - fmt.Print(string(b)) -} - -// WriteConfig will write the current configuration to a specified [path] -func (c *Config) WriteConfig(path string) error { - f, err := os.Create(path) - if err != nil { - return err - } - defer f.Close() - - b, err := yaml.Marshal(c) - if err != nil { - return err - } - bytesWritten, err := f.Write(b) - if err != nil { - return err - } - log.Debugf("wrote %d bytes\n", bytesWritten) - return nil -} - func (c *Config) CheckInterface() error { if c.Interface != "" { if err := isValidInterface(c.Interface); err != nil { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index d91ffda7..ad5cb7f4 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -129,6 +129,9 @@ type Config struct { // EgressServiceCidr, this contains the service cidr range to ignore EgressServiceCidr string + + // EgressWithNftables, this will use the iptables-nftables OVER iptables + EgressWithNftables bool } // LeaderElection defines all of the settings for Kubernetes LeaderElection diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 3a034b0f..f76d8e78 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -102,7 +102,7 @@ func (sm *Manager) startARP() error { // This will tidy any dangling kube-vip iptables rules if os.Getenv("EGRESS_CLEAN") != "" { - i, err := vip.CreateIptablesClient() + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) if err != nil { log.Warnf("[egress] Unable to clean any dangling egress rules [%v]", err) } else { diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index b2e9ea29..8f15bf33 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -64,7 +64,7 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts string) error serviceCidr = defaultServiceCIDR } - i, err := vip.CreateIptablesClient() + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } @@ -157,8 +157,8 @@ func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) return } -func TeardownEgress(podIP, vipIP, destinationPorts string) error { - i, err := vip.CreateIptablesClient() +func (sm *Manager) TeardownEgress(podIP, vipIP, destinationPorts string) error { + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index f07fbd6c..b5922ddd 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -166,7 +166,7 @@ func (sm *Manager) deleteService(uid string) error { if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) + err := sm.TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) if err != nil { log.Errorf("%v", err) } diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index d0eebff8..003891de 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - iptables "github.com/coreos/go-iptables/iptables" + iptables "github.com/kube-vip/kube-vip/pkg/iptables" log "github.com/sirupsen/logrus" ct "github.com/florianl/go-conntrack" @@ -32,10 +32,10 @@ type Egress struct { ipTablesClient *iptables.IPTables } -func CreateIptablesClient() (*Egress, error) { +func CreateIptablesClient(nftables bool) (*Egress, error) { e := new(Egress) var err error - e.ipTablesClient, err = iptables.New() + e.ipTablesClient, err = iptables.New(iptables.EnableNFTables(nftables)) return e, err } diff --git a/testing/e2e/services/kubernetes.go b/testing/e2e/services/kubernetes.go index 82fa1b76..65182819 100644 --- a/testing/e2e/services/kubernetes.go +++ b/testing/e2e/services/kubernetes.go @@ -87,6 +87,10 @@ func (d *deployment) createKVDs(ctx context.Context, clientset *kubernetes.Clien Name: "vip_loglevel", Value: "5", }, + { + Name: "egress_withnftables", + Value: "true", + }, }, Image: "plndr/kube-vip:dev", Name: "kube-vip", diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index be0de29e..ba5c5e36 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -32,12 +32,7 @@ func main() { if err != nil { log.Fatal(err) } - defer func() { - err := deleteKind() - if err != nil { - log.Fatal(err) - } - }() + //return _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") @@ -46,6 +41,16 @@ func main() { _, ignoreLeaderActive := os.LookupEnv("IGNORE_ACTIVE") _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") _, ignoreEgress := os.LookupEnv("IGNORE_EGRESS") + _, retainCluster := os.LookupEnv("RETAIN_CLUSTER") + + if !retainCluster { + defer func() { + err := deleteKind() + if err != nil { + log.Fatal(err) + } + }() + } nodeTolerate := os.Getenv("NODE_TOLERATE") From e604e4fe269d2546f56cb8a62b6bb0b7363ccc58 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 4 Apr 2023 08:45:56 +0000 Subject: [PATCH 359/542] lint fixes Signed-off-by: Dan Finneran --- pkg/iptables/iptables.go | 22 +++++++++++----------- pkg/iptables/lock.go | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go index 45a25905..cf33f68f 100644 --- a/pkg/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -93,21 +93,21 @@ type Stat struct { Options string `json:"options"` } -type option func(*IPTables) +type Option func(*IPTables) -func IPFamily(proto Protocol) option { +func IPFamily(proto Protocol) Option { return func(ipt *IPTables) { ipt.proto = proto } } -func Timeout(timeout int) option { +func Timeout(timeout int) Option { return func(ipt *IPTables) { ipt.timeout = timeout } } -func EnableNFTables(enable bool) option { +func EnableNFTables(enable bool) Option { return func(ipt *IPTables) { ipt.nftables = enable } @@ -119,7 +119,7 @@ func EnableNFTables(enable bool) option { // the IPFamily and Timeout options as follow: // // ip6t := New(IPFamily(ProtocolIPv6), Timeout(5)) -func New(opts ...option) (*IPTables, error) { +func New(opts ...Option) (*IPTables, error) { ipt := &IPTables{ proto: ProtocolIPv4, @@ -575,12 +575,12 @@ func getIptablesCommand(proto Protocol, nftables bool) string { return "ip6tables-nft" } return "ip6tables-legacy" - } else { - if nftables { - return "iptables-nft" - } - return "iptables-legacy" } + + if nftables { + return "iptables-nft" + } + return "iptables-legacy" } // Checks if iptables has the "-C" and "--wait" flag @@ -647,7 +647,7 @@ func iptablesHasCheckCommand(v1 int, v2 int, v3 int) bool { } // Checks if an iptables version is after 1.4.20, when --wait was added -func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool { +func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool { //nolint if v1 > 1 { return true } diff --git a/pkg/iptables/lock.go b/pkg/iptables/lock.go index a88e92b4..11c08aac 100644 --- a/pkg/iptables/lock.go +++ b/pkg/iptables/lock.go @@ -37,7 +37,7 @@ type Unlocker interface { type nopUnlocker struct{} -func (_ nopUnlocker) Unlock() error { return nil } +func (n nopUnlocker) Unlock() error { return nil } type fileLock struct { // mu is used to protect against concurrent invocations from within this process From 9e88b0003f52f26c90ce95bcedc533d7acffa22d Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 4 Apr 2023 13:44:03 +0000 Subject: [PATCH 360/542] Further linting fixes Signed-off-by: Dan Finneran --- pkg/iptables/iptables.go | 2 +- pkg/kubevip/config_manager.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go index cf33f68f..047a0acd 100644 --- a/pkg/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -243,7 +243,7 @@ func (ipt *IPTables) DeleteIfExists(table, chain string, rulespec ...string) err } // List rules in specified table/chain -func (ipt *IPTables) ListById(table, chain string, id int) (string, error) { +func (ipt *IPTables) ListByID(table, chain string, id int) (string, error) { args := []string{"-t", table, "-S", chain, strconv.Itoa(id)} rule, err := ipt.executeList(args) if err != nil { diff --git a/pkg/kubevip/config_manager.go b/pkg/kubevip/config_manager.go index 989ac72d..be605298 100644 --- a/pkg/kubevip/config_manager.go +++ b/pkg/kubevip/config_manager.go @@ -5,7 +5,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" - "sigs.k8s.io/yaml" ) func (c *Config) CheckInterface() error { From 9119597b94ddba30373d26e778b9360ace404e74 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 4 Apr 2023 13:52:45 +0000 Subject: [PATCH 361/542] final fixes Signed-off-by: Dan Finneran --- go.mod | 1 - go.sum | 5 ----- pkg/iptables/iptables.go | 4 ++-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index d4f2b392..9b51b997 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-2022042 require ( github.com/cloudflare/ipvs v0.8.0 - github.com/coreos/go-iptables v0.6.0 github.com/davecgh/go-spew v1.1.1 github.com/florianl/go-conntrack v0.4.0 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index a4615d68..d0d84085 100644 --- a/go.sum +++ b/go.sum @@ -68,11 +68,6 @@ github.com/cloudflare/ipvs v0.8.0/go.mod h1:rL2uv7wRPwNsyRig+6EJybJVLVIuw7+L6dc8 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go index 047a0acd..9419a29c 100644 --- a/pkg/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -585,7 +585,7 @@ func getIptablesCommand(proto Protocol, nftables bool) string { // Checks if iptables has the "-C" and "--wait" flag func getIptablesCommandSupport(v1 int, v2 int, v3 int) (bool, bool, bool, bool) { - return iptablesHasCheckCommand(v1, v2, v3), iptablesHasWaitCommand(v1, v2, v3), iptablesWaitSupportSecond(v1, v2, v3), iptablesHasRandomFully(v1, v2, v3) + return iptablesHasCheckCommand(v1, v2, v3), iptablesHasWaitCommand(v1, v2, v3), iptablesWaitSupportSecond(v1, v2), iptablesHasRandomFully(v1, v2, v3) } // getIptablesVersion returns the first three components of the iptables version @@ -661,7 +661,7 @@ func iptablesHasWaitCommand(v1 int, v2 int, v3 int) bool { //nolint } // Checks if an iptablse version is after 1.6.0, when --wait support second -func iptablesWaitSupportSecond(v1 int, v2 int, v3 int) bool { +func iptablesWaitSupportSecond(v1 int, v2 int) bool { if v1 > 1 { return true } From 8febca00ee3c82328b59d1347aa41a3c7dabcec2 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 4 Apr 2023 15:02:33 +0100 Subject: [PATCH 362/542] Update ci.yaml --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8c79df12..b58cb546 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,5 +26,5 @@ jobs: if: ${{ github.event.label.name == 'control plane' }} run: DOCKERTAG=action make e2e-tests - name: e2e services - if: ${{ github.event.label.name == 'services' }} + if: contains(github.event.pull_request.labels.*.name, 'services') run: DOCKERTAG=action make service-tests From aa7eabd4fbf9c89265fff5bff59924e41d6c6ee6 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Tue, 4 Apr 2023 22:28:00 -0700 Subject: [PATCH 363/542] Update makefile to accept variable to update version Signed-off-by: lubronzhan --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index aaadefdd..3e5c508a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.10 +VERSION ?= v0.5.11 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) @@ -55,7 +55,7 @@ dockerx86Dev: dockerx86Iptables: @-rm ./kube-vip - @docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --push -t $(REPOSITORY)/$(TARGET):dev . + @docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --push -t $(REPOSITORY)/$(TARGET):dev . @echo New single x86 Architecture Docker image created dockerx86: @@ -94,7 +94,7 @@ check: test -z $(shell gofmt -l main.go | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" golangci-lint run go vet ./... - + run: install @$(TARGET) From eac9d2b8bec0cbb0cf3f2eb469eed106b6771643 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 14 Apr 2023 08:13:27 +0000 Subject: [PATCH 364/542] Adds nftables as an option, and fixes a panic Signed-off-by: Dan Finneran --- Makefile | 2 +- pkg/cluster/cluster.go | 7 +++- pkg/vip/egress.go | 35 +++++++++++++++----- testing/e2e/services/kind.go | 57 +++++++++++++++++++------------- testing/e2e/services/services.go | 14 +++++--- 5 files changed, 77 insertions(+), 38 deletions(-) diff --git a/Makefile b/Makefile index aaadefdd..5b923f63 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.10 +VERSION := v0.5.12 BUILD := `git rev-parse HEAD` # Operating System Default (LINUX) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 90198821..55190049 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -1,6 +1,8 @@ package cluster import ( + "sync" + "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -9,6 +11,7 @@ import ( type Cluster struct { stop chan bool completed chan bool + once sync.Once Network vip.Network } @@ -51,7 +54,9 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { func (cluster *Cluster) Stop() { // Close the stop chanel, which will shut down the VIP (if needed) if cluster.stop != nil { - close(cluster.stop) + cluster.once.Do(func() { // Ensure that the close channel can only ever be called once + close(cluster.stop) + }) } // Wait until the completed channel is closed, signallign all shutdown tasks completed diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 003891de..5105b928 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -33,6 +33,7 @@ type Egress struct { } func CreateIptablesClient(nftables bool) (*Egress, error) { + log.Infof("[egress] Creating an iptables client, nftables mode [%t]", nftables) e := new(Egress) var err error e.ipTablesClient, err = iptables.New(iptables.EnableNFTables(nftables)) @@ -53,6 +54,8 @@ func (e *Egress) DeleteManglePrerouting(name string) error { } func (e *Egress) DeleteMangleMarking(podIP, name string) error { + log.Infof("[egress] Stopping marking packets on network [%s]", podIP) + exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) if !exists { @@ -62,6 +65,8 @@ func (e *Egress) DeleteMangleMarking(podIP, name string) error { } func (e *Egress) DeleteSourceNat(podIP, vip string) error { + log.Infof("[egress] Removing source nat from [%s] => [%s]", podIP, vip) + exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) if !exists { @@ -71,6 +76,7 @@ func (e *Egress) DeleteSourceNat(podIP, vip string) error { } func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto string) error { + log.Infof("[egress] Adding source nat from [%s] => [%s]", podIP, vip) 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", Comment) @@ -215,18 +221,31 @@ func (e *Egress) CleanIPtables() error { log.Errorf("[egress] Error removing rule [%v]", err) } } - - mangleRules, err := e.ipTablesClient.List("mangle", MangleChainName) + exists, err := e.CheckMangleChain(MangleChainName) if err != nil { - return err + log.Debugf("[egress] No Mangle chain exists [%v]", err) } - foundNatRules = findRules(mangleRules) - log.Warnf("[egress] Cleaning [%d] dangling prerouting mangle rules", len(foundNatRules)) - for x := range foundNatRules { - err = e.ipTablesClient.Delete("mangle", MangleChainName, foundNatRules[x][2:]...) + if exists { + mangleRules, err := e.ipTablesClient.List("mangle", MangleChainName) if err != nil { - log.Errorf("[egress] Error removing rule [%v]", err) + return err + } + foundNatRules = findRules(mangleRules) + log.Warnf("[egress] Cleaning [%d] dangling prerouting mangle rules", 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) + } } + // For unknown reasons RHEL and the nftables wrapper sometimes leave dangling rules + // So we shall nuke them from orbit (just to be sure) + err = e.ipTablesClient.ClearChain("mangle", MangleChainName) + if err != nil { + log.Errorf("[egress] Error removing flushing table [%v]", err) + } + } else { + log.Warnf("No existing mangle chain [%s] exists", MangleChainName) } return nil } diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index 5deb03d2..f7ae5f97 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -38,33 +38,44 @@ func createKind() error { imagePath := os.Getenv("E2E_IMAGE_PATH") provider = cluster.NewProvider(cluster.ProviderWithLogger(cmd.NewLogger()), cluster.ProviderWithDocker()) - err := provider.Create("services", cluster.CreateWithV1Alpha4Config(&clusterConfig)) + clusters, err := provider.List() if err != nil { - log.Error(err) - return deleteKind() - - } - loadImageCmd := load.NewCommand(cmd.NewLogger(), cmd.StandardIOStreams()) - loadImageCmd.SetArgs([]string{"--name", "services", imagePath}) - err = loadImageCmd.Execute() - if err != nil { - log.Error(err) - return deleteKind() + return err } - cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") - if _, err := cmd.CombinedOutput(); err != nil { - log.Fatal(err) + found := false + for x := range clusters { + if clusters[x] == "services" { + log.Infof("Cluster already exists") + found = true + } } - cmd = exec.Command("kubectl", "create", "-f", "https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml") - if _, err := cmd.CombinedOutput(); err != nil { - return deleteKind() - } - cmd = exec.Command("kubectl", "create", "-f", "https://kube-vip.io/manifests/rbac.yaml") - if _, err := cmd.CombinedOutput(); err != nil { - return deleteKind() + if !found { + err := provider.Create("services", cluster.CreateWithV1Alpha4Config(&clusterConfig)) + if err != nil { + return err + + } + loadImageCmd := load.NewCommand(cmd.NewLogger(), cmd.StandardIOStreams()) + loadImageCmd.SetArgs([]string{"--name", "services", imagePath}) + err = loadImageCmd.Execute() + if err != nil { + return err + } + cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") + if _, err := cmd.CombinedOutput(); err != nil { + return err + } + cmd = exec.Command("kubectl", "create", "-f", "https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml") + if _, err := cmd.CombinedOutput(); err != nil { + return err + } + cmd = exec.Command("kubectl", "create", "-f", "https://kube-vip.io/manifests/rbac.yaml") + if _, err := cmd.CombinedOutput(); err != nil { + return err + } + log.Infof("💤 sleeping for a few seconds to let controllers start") + time.Sleep(time.Second * 5) } - log.Infof("💤 sleeping for a few seconds to let controllers start") - time.Sleep(time.Second * 5) return nil } diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index ba5c5e36..e0e406a7 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -28,10 +28,6 @@ import ( func main() { log.Info("🔬 beginning e2e tests") - err := createKind() - if err != nil { - log.Fatal(err) - } //return @@ -42,14 +38,22 @@ func main() { _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") _, ignoreEgress := os.LookupEnv("IGNORE_EGRESS") _, retainCluster := os.LookupEnv("RETAIN_CLUSTER") + err := createKind() if !retainCluster { + if err != nil { + log.Fatal(err) + } defer func() { err := deleteKind() if err != nil { log.Fatal(err) } }() + } else { + if err != nil { + log.Warn(err) + } } nodeTolerate := os.Getenv("NODE_TOLERATE") @@ -70,7 +74,7 @@ func main() { deploy := deployment{} err = deploy.createKVDs(ctx, clientset) if err != nil { - log.Fatal(err) + log.Error(err) } if !ignoreSimple { From e8319a64644971a733bf4be1ff0aa3e3e4441276 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 14 Apr 2023 08:29:51 +0000 Subject: [PATCH 365/542] dont lint old files Signed-off-by: Dan Finneran --- pkg/service/manager.go | 2 ++ pkg/service/manager_arp.go | 1 + pkg/service/manager_bgp.go | 2 ++ pkg/service/prom.go | 2 ++ pkg/service/services.go | 2 ++ pkg/service/services_dhcp.go | 2 ++ pkg/service/util.go | 2 ++ pkg/service/util_test.go | 2 ++ pkg/service/watcher.go | 2 ++ 9 files changed, 17 insertions(+) diff --git a/pkg/service/manager.go b/pkg/service/manager.go index 18f62758..dd492150 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go index 9e342c2f..b8e3e098 100644 --- a/pkg/service/manager_arp.go +++ b/pkg/service/manager_arp.go @@ -1,3 +1,4 @@ +//nolint:unparam package service import ( diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 7f8987da..34166932 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/prom.go b/pkg/service/prom.go index 6e41287a..6ae6c38c 100644 --- a/pkg/service/prom.go +++ b/pkg/service/prom.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import "github.com/prometheus/client_golang/prometheus" diff --git a/pkg/service/services.go b/pkg/service/services.go index 7e788ac1..77097d5b 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go index 3766c485..5959a557 100644 --- a/pkg/service/services_dhcp.go +++ b/pkg/service/services_dhcp.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/util.go b/pkg/service/util.go index 7cd8b069..8e3d6386 100644 --- a/pkg/service/util.go +++ b/pkg/service/util.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/util_test.go b/pkg/service/util_test.go index ec8c440a..d120da81 100644 --- a/pkg/service/util_test.go +++ b/pkg/service/util_test.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go index cc22aff9..03a54d53 100644 --- a/pkg/service/watcher.go +++ b/pkg/service/watcher.go @@ -1,3 +1,5 @@ +//nolint:unparam + package service import ( From f1eef8f07d58194ef5d097205d26901881424e42 Mon Sep 17 00:00:00 2001 From: W1zzardTPU Date: Sun, 23 Apr 2023 20:36:59 +0200 Subject: [PATCH 366/542] Add support for lbClassName --- cmd/kube-vip.go | 1 + pkg/kubevip/config_environment.go | 6 ++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_types.go | 3 +++ pkg/manager/watch_services.go | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1b981f02..c297cc1a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -129,6 +129,7 @@ func init() { // Extended behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServicesElection, "servicesElection", false, "Enable leader election per kubernetes service") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassOnly, "lbClassOnly", false, "Enable load balancing only for services with LoadBalancerClass \"kube-vip.io/kube-vip-class\"") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerClassName, "lbClassName", "kube-vip.io/kube-vip-class", "Name of load balancer class for kube-VIP, defaults to \"kube-vip.io/kube-vip-class\"") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index dc7e07aa..1c8e81b3 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -162,6 +162,12 @@ func ParseEnvironment(c *Config) error { c.LoadBalancerClassOnly = b } + // Load-balancer class name + env = os.Getenv(lbClassName) + if env != "" { + c.LoadBalancerClassName = env + } + // Find the namespace that the control plane should use (for leaderElection lock) env = os.Getenv(svcNamespace) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 0afe883b..ef1cc52d 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -133,6 +133,9 @@ const ( //lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only lbClassOnly = "lb_class_only" + //lbClassName enables load-balancer for a specific class only + lbClassName = "lb_class_name" + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index ad5cb7f4..0e085e83 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -36,6 +36,9 @@ type Config struct { // LoadBalancerClassOnly, will enable load balancing only for services with LoadBalancerClass set to "kube-vip.io/kube-vip-class" LoadBalancerClassOnly bool `yaml:"lbClassOnly"` + // LoadBalancerClassName, will limit the load balancing services to services with LoadBalancerClass set to this value + LoadBalancerClassName string `yaml:"lbClassName"` + // ArpBroadcastRate, defines how often kube-vip will update the network about updates to the network ArpBroadcastRate int64 `yaml:"arpBroadcastRate"` diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 79905d31..744a320e 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -109,7 +109,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Check the loadBalancer class 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 != "kube-vip.io/kube-vip-class" { + if *svc.Spec.LoadBalancerClass != sm.config.LoadBalancerClassName { log.Infof("service [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass) break } From b33da242e886b224859cb94c1cccac317f48a336 Mon Sep 17 00:00:00 2001 From: Christophe Jauffret Date: Sat, 29 Apr 2023 08:10:08 +0200 Subject: [PATCH 367/542] fix LB annotations Signed-off-by: Christophe Jauffret --- docs/architecture/index.md | 4 ++-- docs/hybrid/daemonset/index.md | 2 +- docs/hybrid/services/index.md | 8 ++++---- docs/hybrid/static/index.md | 2 +- docs/install_daemonset/index.md | 2 +- docs/install_static/index.md | 2 +- docs/usage/on-prem/index.md | 2 +- pkg/manager/services.go | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/architecture/index.md b/docs/architecture/index.md index 6a7f9fe7..360bfbbc 100644 --- a/docs/architecture/index.md +++ b/docs/architecture/index.md @@ -71,8 +71,8 @@ This section details the flow of events in order for `kube-vip` to advertise a K 2. Within the Kubernetes cluster, a Service object is created with the `spec.type` set to `LoadBalancer`. 3. A controller (typically a [Cloud Controller](/usage/cloud-provider)) has a loop that "watches" for Services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this Service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address, it will update the Service field `spec.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release -6. `kube-vip` Pods implement a "watcher" for Services that have a `spec.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `svc.Spec.loadBalancerIP`. +5. Once the controller has an IP address, it will update the Service field `metadata.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release +6. `kube-vip` Pods implement a "watcher" for Services that have a `metadata.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `spec.loadBalancerIP`. 7. When a new Service appears, `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the Service network. 8. Finally, `kube-vip` will update the Service status so that the API reflects the object is ready. This is done by updating the `status.loadBalancer.ingress` with the VIP address. diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md index 0d040673..46139e5b 100644 --- a/docs/hybrid/daemonset/index.md +++ b/docs/hybrid/daemonset/index.md @@ -1,6 +1,6 @@ # Kube-Vip as a daemonset -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. **Note about Daemonsets** diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md index 71597d5d..ee3ebc92 100644 --- a/docs/hybrid/services/index.md +++ b/docs/hybrid/services/index.md @@ -7,13 +7,13 @@ We've designed `kube-vip` to be as de-coupled or agnostic from other components This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: 1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `svc.Spec.Type = LoadBalancer` +2. Within the Kubernetes cluster a service object is created with the `spec.Type = LoadBalancer` 3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. 4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address, it will update the Service field `spec.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release -6. `kube-vip` Pods implement a "watcher" for Services that have a `spec.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `svc.Spec.loadBalancerIP`. +5. Once the controller has an IP address, it will update the Service field `metadata.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release +6. `kube-vip` Pods implement a "watcher" for Services that have a `metadata.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `spec.loadBalancerIP`. 7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. -8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `svc.Status.LoadBalancer.Ingress` with the VIP address. +8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `status.LoadBalancer.Ingress` with the VIP address. ## CCM diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md index 586f1b71..5e193ece 100644 --- a/docs/hybrid/static/index.md +++ b/docs/hybrid/static/index.md @@ -1,6 +1,6 @@ # Kube-vip as a Static Pod -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. +In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md index 31de07b9..95687ef4 100644 --- a/docs/install_daemonset/index.md +++ b/docs/install_daemonset/index.md @@ -10,7 +10,7 @@ Unlike running `kube-vip` as a [static Pod](/install_static) there are a few mor ## Kube-Vip as HA, Load Balancer, or both -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Create the RBAC settings diff --git a/docs/install_static/index.md b/docs/install_static/index.md index 95e5a24d..ad01c7f7 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -17,7 +17,7 @@ The sequence of events for building a highly available Kubernetes cluster with ` ## Kube-Vip as HA, Load Balancer, or both -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.spec.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. +The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. ## Generating a Manifest diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index 8d563c4e..08b57d33 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -44,7 +44,7 @@ To manage the IP address ranges for Services of type `LoadBalancer`, the `kube-v - IP ranges [start address - end address] - Multiple pools by CIDR per Namespace - Multiple IP ranges per Namespace (handles overlapping ranges) -- Setting of static addresses through service.spec.annotations `kube-vip.io/loadbalancerIPs` +- Setting of static addresses through service.metadata.annotations `kube-vip.io/loadbalancerIPs` - Setting of static addresses through --load-balancer-ip=x.x.x.x (`kubectl expose` command) To control which IP address range is used for which Service, the following rules are applied: diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9de6a0c9..8310da17 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -73,7 +73,7 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - log.Infof("[service] adding VIP [%s] for [%s/%s] ", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + log.Infof("[service] adding VIP [%s] for [%s/%s]", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) From 7fcf0f1b6505e6f5b0b92d4efd89b58ebd75db4d Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Sun, 30 Apr 2023 15:54:06 -0400 Subject: [PATCH 368/542] Use correct address family for ipvs destinations When IPv6 addresses are present in node.Status.Addresses, the IPVSLoadBalancer parses the addresses and attempts to add them as an IPv4 destinations. This results in useless entries in the service table that only hold the last 32 bits of address. This change does two things: - uses the appropriate address family when creating the service - ignores backend addresses that use a different address family than the service This avoids the immediate problem of using the wrong address family for IPv6 destinations and the useless entries in the service table. Signed-off-by: Matthew Sykes --- pkg/loadbalancer/ipvs.go | 42 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index a9640185..e8f709bb 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -39,7 +39,6 @@ type IPVSLoadBalancer struct { } func NewIPVSLB(address string, port int, forwardingMethod string) (*IPVSLoadBalancer, error) { - // Create IPVS client c, err := ipvs.New() if err != nil { @@ -53,12 +52,14 @@ func NewIPVSLB(address string, port int, forwardingMethod string) (*IPVSLoadBala } log.Infof("IPVS Loadbalancer enabled for %d.%d.%d", i.Version[0], i.Version[1], i.Version[2]) + ip, family := ipAndFamily(address) + // Generate out API Server LoadBalancer instance svc := ipvs.Service{ - Family: ipvs.INET, + Family: family, Protocol: ipvs.TCP, Port: uint16(port), - Address: ipvs.NewIP(net.ParseIP(address)), + Address: ip, Scheduler: ROUNDROBIN, } @@ -95,11 +96,9 @@ func (lb *IPVSLoadBalancer) RemoveIPVSLB() error { return fmt.Errorf("error removing existing IPVS service: %v", err) } return nil - } func (lb *IPVSLoadBalancer) AddBackend(address string, port int) 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") { @@ -125,13 +124,21 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { log.Errorf("Unable to create an IPVS service, ensure IPVS kernel modules are loaded") log.Fatalf("IPVS service error: %v", err) } - log.Infof("Created Load-Balancer services on [%s:%d]", lb.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port) + log.Infof("Created Load-Balancer services on [%s:%d]", lb.addrString(), lb.Port) + } + + ip, family := ipAndFamily(address) + + // Ignore backends that use a different address family. + // Looks like different families could be supported in tunnel mode... + if family != lb.loadBalancerService.Family { + return nil } dst := ipvs.Destination{ - Address: ipvs.NewIP(net.ParseIP(address)), + Address: ip, Port: uint16(port), - Family: ipvs.INET, + Family: family, Weight: 1, FwdMethod: lb.forwardingMethod, } @@ -146,16 +153,17 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) 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.loadBalancerService.Address.Net(ipvs.INET).String(), lb.Port, address, port) + log.Infof("Added backend for [%s:%d] on [%s:%d]", lb.addrString(), lb.Port, address, port) return nil } func (lb *IPVSLoadBalancer) RemoveBackend(address string, port int) error { + ip, family := ipAndFamily(address) dst := ipvs.Destination{ - Address: ipvs.NewIP(net.ParseIP(address)), + Address: ip, Port: uint16(port), - Family: ipvs.INET, + Family: family, Weight: 1, } err := lb.client.RemoveDestination(lb.loadBalancerService, dst) @@ -164,3 +172,15 @@ func (lb *IPVSLoadBalancer) RemoveBackend(address string, port int) error { } return nil } + +func (lb *IPVSLoadBalancer) addrString() string { + return lb.loadBalancerService.Address.Net(lb.loadBalancerService.Family).String() +} + +func ipAndFamily(address string) (ipvs.IP, ipvs.AddressFamily) { + ipAddr := net.ParseIP(address) + if ipAddr.To4() == nil { + return ipvs.NewIP(ipAddr), ipvs.INET6 + } + return ipvs.NewIP(ipAddr), ipvs.INET +} From 37364882fdebfb700f8926c7eb616e5c52618396 Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Wed, 3 May 2023 08:27:52 -0400 Subject: [PATCH 369/542] Ignore different family on IPVS delete Signed-off-by: Matthew Sykes --- pkg/loadbalancer/ipvs.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index e8f709bb..b0b15cb6 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -160,6 +160,10 @@ func (lb *IPVSLoadBalancer) AddBackend(address string, port int) error { func (lb *IPVSLoadBalancer) RemoveBackend(address string, port int) error { ip, family := ipAndFamily(address) + if family != lb.loadBalancerService.Family { + return nil + } + dst := ipvs.Destination{ Address: ip, Port: uint16(port), From e6e4d1cf0850a645cc051549376c18f2dc17035c Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 5 May 2023 16:51:03 +0000 Subject: [PATCH 370/542] This ensures rule cleaning only happens in a NS Signed-off-by: Dan Finneran --- pkg/manager/manager_arp.go | 2 +- pkg/manager/service_egress.go | 8 ++--- pkg/manager/services.go | 4 +-- pkg/vip/egress.go | 60 +++++++++++++++++++---------------- pkg/vip/egress_test.go | 10 +++--- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index f76d8e78..610d2fc9 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -102,7 +102,7 @@ func (sm *Manager) startARP() error { // This will tidy any dangling kube-vip iptables rules if os.Getenv("EGRESS_CLEAN") != "" { - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, sm.config.ServiceNamespace) if err != nil { log.Warnf("[egress] Unable to clean any dangling egress rules [%v]", err) } else { diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index 8f15bf33..c0c0dfdb 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -43,7 +43,7 @@ func (sm *Manager) iptablesCheck() error { return nil } -func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts string) error { +func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, namespace string) error { // serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() // if err != nil { // serviceCIDR = "10.96.0.0/12" @@ -64,7 +64,7 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts string) error serviceCidr = defaultServiceCIDR } - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } @@ -157,8 +157,8 @@ func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) return } -func (sm *Manager) TeardownEgress(podIP, vipIP, destinationPorts string) error { - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables) +func (sm *Manager) TeardownEgress(podIP, vipIP, destinationPorts, namespace string) error { + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9de6a0c9..d675bb12 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -113,7 +113,7 @@ func (sm *Manager) addService(svc *v1.Service) error { if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(serviceIP, svc.Annotations[endpoint], svc.Annotations[egressDestinationPorts]) + err = sm.configureEgress(serviceIP, svc.Annotations[endpoint], svc.Annotations[egressDestinationPorts], svc.Namespace) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { @@ -169,7 +169,7 @@ func (sm *Manager) deleteService(uid string) error { if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := sm.TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts]) + err := sm.TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts], sm.serviceInstances[x].serviceSnapshot.Namespace) if err != nil { log.Errorf("%v", err) } diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 5105b928..36138194 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -30,13 +30,15 @@ const Comment = "a3ViZS12aXAK=kube-vip" type Egress struct { ipTablesClient *iptables.IPTables + comment string } -func CreateIptablesClient(nftables bool) (*Egress, error) { +func CreateIptablesClient(nftables bool, namespace string) (*Egress, error) { log.Infof("[egress] Creating an iptables client, nftables mode [%t]", nftables) e := new(Egress) var err error e.ipTablesClient, err = iptables.New(iptables.EnableNFTables(nftables)) + e.comment = Comment + "-" + namespace return e, err } @@ -56,34 +58,34 @@ func (e *Egress) DeleteManglePrerouting(name string) error { func (e *Egress) DeleteMangleMarking(podIP, name string) error { log.Infof("[egress] Stopping marking packets on network [%s]", podIP) - exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) + exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment) if !exists { return fmt.Errorf("unable to find source Mangle rule for [%s]", podIP) } - return e.ipTablesClient.Delete("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Delete("mangle", name, "-s", podIP, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment) } func (e *Egress) DeleteSourceNat(podIP, vip string) error { log.Infof("[egress] Removing source nat from [%s] => [%s]", podIP, vip) - exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) + exists, _ := e.ipTablesClient.Exists("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment) if !exists { return fmt.Errorf("unable to find source Nat rule for [%s]", podIP) } - return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment) } func (e *Egress) DeleteSourceNatForDestinationPort(podIP, vip, port, proto string) error { log.Infof("[egress] Adding source nat from [%s] => [%s]", podIP, vip) - 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", Comment) + 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) if !exists { return fmt.Errorf("unable to find source Nat rule for [%s], with destination port [%s]", podIP, port) } - return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", e.comment) } func (e *Egress) CreateMangleChain(name string) error { @@ -95,59 +97,59 @@ func (e *Egress) CreateMangleChain(name string) error { } func (e *Egress) AppendReturnRulesForDestinationSubnet(name, subnet string) error { log.Infof("[egress] Adding jump for subnet [%s] to RETURN to previous chain/rules", subnet) - exists, _ := e.ipTablesClient.Exists("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", Comment) + 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", Comment) + return e.ipTablesClient.Append("mangle", name, "-d", subnet, "-j", "RETURN", "-m", "comment", "--comment", e.comment) } return nil } func (e *Egress) AppendReturnRulesForMarking(name, subnet string) error { log.Infof("[egress] Marking packets on network [%s]", subnet) - exists, _ := e.ipTablesClient.Exists("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", Comment) + 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", Comment) + return e.ipTablesClient.Append("mangle", name, "-s", subnet, "-j", "MARK", "--set-mark", "64/64", "-m", "comment", "--comment", e.comment) } return nil } func (e *Egress) InsertMangeTableIntoPrerouting(name string) error { log.Infof("[egress] Adding jump from mangle prerouting to [%s]", name) - if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", Comment); err != nil { + if exists, err := e.ipTablesClient.Exists("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", e.comment); err != nil { return err } else if exists { - if err2 := e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", Comment); err2 != nil { + if err2 := e.ipTablesClient.Delete("mangle", "PREROUTING", "-j", name, "-m", "comment", "--comment", e.comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name, "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Insert("mangle", "PREROUTING", 1, "-j", name, "-m", "comment", "--comment", e.comment) } func (e *Egress) InsertSourceNat(vip, podIP string) error { log.Infof("[egress] Adding source nat from [%s] => [%s]", podIP, 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", Comment); err != nil { + 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 { - if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment); err2 != nil { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-m", "comment", "--comment", e.comment) } 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) - if exists, err := 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", Comment); err != nil { + if exists, err := 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); err != nil { return err } else if exists { - if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment); err2 != nil { + if err2 := e.ipTablesClient.Delete("nat", "POSTROUTING", "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", e.comment); err2 != nil { return err2 } } - return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", Comment) + return e.ipTablesClient.Insert("nat", "POSTROUTING", 1, "-s", podIP+"/32", "-m", "mark", "--mark", "64/64", "-j", "SNAT", "--to-source", vip, "-p", proto, "--dport", port, "-m", "comment", "--comment", e.comment) } func DeleteExistingSessions(sessionIP string, destination bool) error { @@ -213,7 +215,7 @@ func (e *Egress) CleanIPtables() error { if err != nil { return err } - foundNatRules := findRules(natRules) + foundNatRules := e.findRules(natRules) log.Warnf("[egress] Cleaning [%d] dangling postrouting nat rules", len(foundNatRules)) for x := range foundNatRules { err = e.ipTablesClient.Delete("nat", "POSTROUTING", foundNatRules[x][2:]...) @@ -230,7 +232,7 @@ func (e *Egress) CleanIPtables() error { if err != nil { return err } - foundNatRules = findRules(mangleRules) + foundNatRules = e.findRules(mangleRules) log.Warnf("[egress] Cleaning [%d] dangling prerouting mangle rules", len(foundNatRules)) for x := range foundNatRules { err = e.ipTablesClient.Delete("mangle", MangleChainName, foundNatRules[x][2:]...) @@ -238,25 +240,27 @@ func (e *Egress) CleanIPtables() error { log.Errorf("[egress] Error removing rule [%v]", err) } } + // For unknown reasons RHEL and the nftables wrapper sometimes leave dangling rules // So we shall nuke them from orbit (just to be sure) - err = e.ipTablesClient.ClearChain("mangle", MangleChainName) - if err != nil { - log.Errorf("[egress] Error removing flushing table [%v]", err) - } + + // err = e.ipTablesClient.ClearChain("mangle", MangleChainName) + // if err != nil { + // log.Errorf("[egress] Error removing flushing table [%v]", err) + // } } else { log.Warnf("No existing mangle chain [%s] exists", MangleChainName) } return nil } -func findRules(rules []string) [][]string { +func (e *Egress) findRules(rules []string) [][]string { var foundRules [][]string for i := range rules { r := strings.Split(rules[i], " ") for x := range r { - if r[x] == "\""+Comment+"\"" { + if r[x] == "\""+e.comment+"\"" { // Remove the quotes around the comment r[x] = strings.Trim(r[x], "\"") foundRules = append(foundRules, r) diff --git a/pkg/vip/egress_test.go b/pkg/vip/egress_test.go index ce90f88a..8466e437 100644 --- a/pkg/vip/egress_test.go +++ b/pkg/vip/egress_test.go @@ -7,6 +7,7 @@ import ( ) func Test_findRules(t *testing.T) { + e := Egress{comment: Comment + "-" + "default"} type args struct { rules []string } @@ -15,20 +16,19 @@ func Test_findRules(t *testing.T) { args args want [][]string }{ - { "test", args{[]string{ "-A PREROUTING -m comment --comment \"cali:6gwbT8clXdHdC1b1\" -j cali-PREROUTING", - fmt.Sprintf("-A KUBE-VIP-EGRESS -s 172.17.88.190/32 -m comment --comment \"%s\" -j MARK --set-xmark 0x40/0x40", Comment), - fmt.Sprintf("-A POSTROUTING -m comment --comment \"%s\" -j RETURN", Comment), + fmt.Sprintf("-A KUBE-VIP-EGRESS -s 172.17.88.190/32 -m comment --comment \"%s\" -j MARK --set-xmark 0x40/0x40", e.comment), + fmt.Sprintf("-A POSTROUTING -m comment --comment \"%s\" -j RETURN", e.comment), }}, - [][]string{{"-A", "KUBE-VIP-EGRESS", "-s", "172.17.88.190/32", "-m", "comment", "--comment", Comment, "-j", "MARK", "--set-xmark", "0x40/0x40"}, {"-A", "POSTROUTING", "-m", "comment", "--comment", Comment, "-j", "RETURN"}}, + [][]string{{"-A", "KUBE-VIP-EGRESS", "-s", "172.17.88.190/32", "-m", "comment", "--comment", e.comment, "-j", "MARK", "--set-xmark", "0x40/0x40"}, {"-A", "POSTROUTING", "-m", "comment", "--comment", e.comment, "-j", "RETURN"}}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := findRules(tt.args.rules); !reflect.DeepEqual(got, tt.want) { + if got := e.findRules(tt.args.rules); !reflect.DeepEqual(got, tt.want) { t.Errorf("findRules() = \n%v, want \n%v", got, tt.want) } }) From 1474fcf36988fa8b25aaea6e056ebd47273d184d Mon Sep 17 00:00:00 2001 From: Canwu Yao Date: Sun, 7 May 2023 11:59:57 +0800 Subject: [PATCH 371/542] Support changing load balancer IP Signed-off-by: Canwu Yao --- pkg/manager/watch_services.go | 114 ++++++++++++++++------------------ 1 file changed, 55 insertions(+), 59 deletions(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 744a320e..e803d8eb 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -7,7 +7,6 @@ import ( "sync" "github.com/davecgh/go-spew/spew" - "github.com/kube-vip/kube-vip/pkg/service" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" @@ -16,6 +15,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" + + "github.com/kube-vip/kube-vip/pkg/service" ) // TODO: Fix the naming of these contexts @@ -125,54 +126,51 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - log.Debugf("service [%s] has been added/modified with addresses [%s] and is active [%t]", svc.Name, service.FetchServiceAddress(svc), activeService[string(svc.UID)]) + log.Debugf("service [%s] has been added/modified with addresses [%s]", svc.Name, service.FetchServiceAddress(svc)) // Scenarios: // 1. - if !activeService[string(svc.UID)] { - wg.Add(1) - activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) - // Background the services election - if sm.config.EnableServicesElection { - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Start an endpoint watcher if we're not watching it already - if !watchedService[string(svc.UID)] { - // background the endpoint watcher - go func() { - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Add Endpoint watcher - wg.Add(1) - err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) - if err != nil { - log.Error(err) - } - wg.Done() - } - }() - // We're now watching this service - watchedService[string(svc.UID)] = true - } - } else { - // Increment the waitGroup before the service Func is called (Done is completed in there) - wg.Add(1) + wg.Add(1) + activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) + // Background the services election + if sm.config.EnableServicesElection { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Start an endpoint watcher if we're not watching it already + if !watchedService[string(svc.UID)] { + // background the endpoint watcher go func() { - err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) - if err != nil { - log.Error(err) + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Add Endpoint watcher + wg.Add(1) + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() } - wg.Done() }() + // We're now watching this service + watchedService[string(svc.UID)] = true } } else { // Increment the waitGroup before the service Func is called (Done is completed in there) wg.Add(1) - err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) - if err != nil { - log.Error(err) - } - wg.Done() + go func() { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() + }() } - activeService[string(svc.UID)] = true + } else { + // Increment the waitGroup before the service Func is called (Done is completed in there) + wg.Add(1) + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() } case watch.Deleted: svc, ok := event.Object.(*v1.Service) @@ -180,29 +178,27 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context return fmt.Errorf("unable to parse Kubernetes services from API watcher") } - if activeService[string(svc.UID)] { - // We only care about LoadBalancer services - if svc.Spec.Type != v1.ServiceTypeLoadBalancer { - break - } - - // We can ignore this service - if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) - break - } - // If this is an active service then and additional leaderElection will handle stopping - err := sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } - // Calls the cancel function of the context - activeServiceLoadBalancerCancel[string(svc.UID)]() - activeService[string(svc.UID)] = false - watchedService[string(svc.UID)] = false + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } - log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) + // We can ignore this service + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } + // If this is an active service then and additional leaderElection will handle stopping + err := sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) } + // Calls the cancel function of the context + activeServiceLoadBalancerCancel[string(svc.UID)]() + activeService[string(svc.UID)] = false + watchedService[string(svc.UID)] = false + + log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used case watch.Error: From 640743a2de49553c581fca8f8eb89013f9ecafb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Badst=C3=BCbner?= Date: Thu, 4 May 2023 10:25:37 +0200 Subject: [PATCH 372/542] feat(bgp-server): add peer state change callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Badstübner --- cmd/kube-vip-start.go | 2 +- pkg/bgp/server.go | 5 ++++- pkg/cluster/clusterLeaderElection.go | 2 +- pkg/manager/manager_bgp.go | 3 ++- pkg/service/manager_bgp.go | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 055a94eb..94124e53 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -89,7 +89,7 @@ var kubeVipStart = &cobra.Command{ if startConfig.EnableBGP { log.Info("Starting the BGP server to advertise VIP routes to VGP peers") - bgpServer, err = bgp.NewBGPServer(&startConfig.BGPConfig) + bgpServer, err = bgp.NewBGPServer(&startConfig.BGPConfig, nil) if err != nil { log.Fatalf("%v", err) } diff --git a/pkg/bgp/server.go b/pkg/bgp/server.go index dd1cbd0d..faafaf0b 100644 --- a/pkg/bgp/server.go +++ b/pkg/bgp/server.go @@ -11,7 +11,7 @@ import ( ) // NewBGPServer takes a configuration and returns a running BGP server instance -func NewBGPServer(c *Config) (b *Server, err error) { +func NewBGPServer(c *Config, peerStateChangeCallback func(*api.WatchEventResponse_PeerEvent)) (b *Server, err error) { if c.AS == 0 { return nil, fmt.Errorf("You need to provide AS") } @@ -43,6 +43,9 @@ func NewBGPServer(c *Config) (b *Server, err error) { 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.Println(p) + if peerStateChangeCallback != nil { + peerStateChangeCallback(p) + } } }); err != nil { return diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index b5f36722..4a9d501d 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -172,7 +172,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * if c.EnableBGP { // Lets start BGP log.Info("Starting the BGP server to advertise VIP routes to VGP peers") - bgpServer, err = bgp.NewBGPServer(&c.BGPConfig) + bgpServer, err = bgp.NewBGPServer(&c.BGPConfig, nil) if err != nil { log.Error(err) } diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 03c235cd..72e63cd4 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -8,6 +8,7 @@ import ( "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" log "github.com/sirupsen/logrus" ) @@ -48,7 +49,7 @@ func (sm *Manager) startBGP() error { } log.Info("Starting the BGP server to advertise VIP routes to BGP peers") - sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, func(p *api.WatchEventResponse_PeerEvent) {}) if err != nil { return err } diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go index 34166932..0f417d20 100644 --- a/pkg/service/manager_bgp.go +++ b/pkg/service/manager_bgp.go @@ -36,7 +36,7 @@ func (sm *Manager) startBGP() error { } log.Info("Starting the BGP server to advertise VIP routes to VGP peers") - sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, nil) if err != nil { return err } From 386d1514c23778f4d023026ac363a3c1d1d560b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Badst=C3=BCbner?= Date: Thu, 4 May 2023 10:28:12 +0200 Subject: [PATCH 373/542] feat(metrics): add bgp_session_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Badstübner --- pkg/manager/manager.go | 10 ++++++++++ pkg/manager/prom.go | 2 +- pkg/service/manager.go | 4 ++++ pkg/service/prom.go | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 9375bfd9..d9998bf6 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -49,6 +49,10 @@ type Manager struct { // from the service watcher countServiceWatchEvent *prometheus.CounterVec + // This is a prometheus gauge indicating the state of the sessions. + // 1 means "ESTABLISHED", 0 means "NOT ESTABLISHED" + bgpSessionInfoGauge *prometheus.GaugeVec + // This mutex is to protect calls from various goroutines mutex sync.Mutex } @@ -100,6 +104,12 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { Name: "all_services_events", Help: "Count all events fired by the service watcher categorised by event type", }, []string{"type"}), + bgpSessionInfoGauge: prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "kube_vip", + Subsystem: "manager", + Name: "bgp_session_info", + Help: "Display state of session by setting metric for label value with current state to 1", + }, []string{"state", "peer"}), }, nil } diff --git a/pkg/manager/prom.go b/pkg/manager/prom.go index 3020484a..9683411a 100644 --- a/pkg/manager/prom.go +++ b/pkg/manager/prom.go @@ -4,5 +4,5 @@ import "github.com/prometheus/client_golang/prometheus" // PrometheusCollector defines a service watch event counter. func (sm *Manager) PrometheusCollector() []prometheus.Collector { - return []prometheus.Collector{sm.countServiceWatchEvent} + return []prometheus.Collector{sm.countServiceWatchEvent, sm.bgpSessionInfoGauge} } diff --git a/pkg/service/manager.go b/pkg/service/manager.go index dd492150..aa4387f2 100644 --- a/pkg/service/manager.go +++ b/pkg/service/manager.go @@ -42,6 +42,10 @@ type Manager struct { // This is a prometheus counter used to count the number of events received // from the service watcher countServiceWatchEvent *prometheus.CounterVec + + // This is a prometheus gauge indicating the state of the sessions. + // 1 means "ESTABLISHED", 0 means "NOT ESTABLISHED" + bgpSessionInfoGauge *prometheus.GaugeVec } // Instance defines an instance of everything needed to manage a vip diff --git a/pkg/service/prom.go b/pkg/service/prom.go index 6ae6c38c..8ed38954 100644 --- a/pkg/service/prom.go +++ b/pkg/service/prom.go @@ -6,5 +6,5 @@ import "github.com/prometheus/client_golang/prometheus" // PrometheusCollector - required for statistics // TODO - improve monitoring func (sm *Manager) PrometheusCollector() []prometheus.Collector { - return []prometheus.Collector{sm.countServiceWatchEvent} + return []prometheus.Collector{sm.countServiceWatchEvent, sm.bgpSessionInfoGauge} } From 68e6a940a21b317cb775334f1fb68aa720235c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Badst=C3=BCbner?= Date: Mon, 8 May 2023 10:02:59 +0200 Subject: [PATCH 374/542] feat(metrics): implement bgp_session_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Badstübner --- pkg/manager/manager_bgp.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 72e63cd4..297c4678 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -2,6 +2,7 @@ package manager import ( "context" + "fmt" "os" "syscall" @@ -10,6 +11,7 @@ import ( "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" ) @@ -49,7 +51,21 @@ func (sm *Manager) startBGP() error { } log.Info("Starting the BGP server to advertise VIP routes to BGP peers") - sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, func(p *api.WatchEventResponse_PeerEvent) {}) + sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, func(p *api.WatchEventResponse_PeerEvent) { + for stateName, stateValue := range api.PeerState_SessionState_value { + metricValue := 0.0 + if stateValue == int32(p.GetPeer().GetState().GetSessionState().Number()) { + metricValue = 1 + } + ipaddr := p.GetPeer().GetState().GetNeighborAddress() + port := uint64(179) + + sm.bgpSessionInfoGauge.With(prometheus.Labels{ + "state": stateName, + "peer": fmt.Sprintf("%s:%d", ipaddr, port), + }).Set(metricValue) + } + }) if err != nil { return err } From 4a2e72e8118bbb42bd76f3fa929723d93a0124b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Badst=C3=BCbner?= Date: Mon, 8 May 2023 10:10:00 +0200 Subject: [PATCH 375/542] refactor(metrics): better memory efficiency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Badstübner --- pkg/manager/manager_bgp.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 297c4678..353ec993 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -52,17 +52,19 @@ func (sm *Manager) startBGP() error { log.Info("Starting the BGP server to advertise VIP routes to BGP peers") sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, func(p *api.WatchEventResponse_PeerEvent) { + ipaddr := p.GetPeer().GetState().GetNeighborAddress() + port := uint64(179) + peerDescription := fmt.Sprintf("%s:%d", ipaddr, port) + for stateName, stateValue := range api.PeerState_SessionState_value { metricValue := 0.0 if stateValue == int32(p.GetPeer().GetState().GetSessionState().Number()) { metricValue = 1 } - ipaddr := p.GetPeer().GetState().GetNeighborAddress() - port := uint64(179) sm.bgpSessionInfoGauge.With(prometheus.Labels{ "state": stateName, - "peer": fmt.Sprintf("%s:%d", ipaddr, port), + "peer": peerDescription, }).Set(metricValue) } }) From 17eee86f2cc413273e3b815650820ae64c9ef219 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 8 May 2023 15:15:40 +0100 Subject: [PATCH 376/542] Update main.yaml Allow on-request builds. --- .github/workflows/main.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 5279eee0..7b75ff58 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -3,6 +3,8 @@ name: Build and publish main image regularly on: schedule: - cron: '25 0 * * *' + workflow_dispatch: + jobs: nightly_build: From f2f73c00d00313b2fcd382adcf7525f1e38dd0ac Mon Sep 17 00:00:00 2001 From: Canwu Yao Date: Sun, 7 May 2023 12:01:10 +0800 Subject: [PATCH 377/542] Set iptables rules to limit traffic ports Signed-off-by: Canwu Yao --- cmd/kube-vip.go | 1 + pkg/cluster/cluster.go | 4 + pkg/iptables/iptables.go | 16 +++ pkg/kubevip/config_environment.go | 11 +- pkg/kubevip/config_envvar.go | 5 +- pkg/kubevip/config_generator.go | 9 ++ pkg/kubevip/config_types.go | 5 +- pkg/manager/instance.go | 30 +++--- pkg/manager/services.go | 33 +++++- pkg/service/services.go | 18 ++-- pkg/vip/address.go | 167 +++++++++++++++++++++++++++++- pkg/vip/dhcp.go | 2 + 12 files changed, 271 insertions(+), 30 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index c297cc1a..de7584b5 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -130,6 +130,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServicesElection, "servicesElection", false, "Enable leader election per kubernetes service") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassOnly, "lbClassOnly", false, "Enable load balancing only for services with LoadBalancerClass \"kube-vip.io/kube-vip-class\"") kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerClassName, "lbClassName", "kube-vip.io/kube-vip-class", "Name of load balancer class for kube-VIP, defaults to \"kube-vip.io/kube-vip-class\"") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 55190049..574f77ef 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -3,6 +3,8 @@ package cluster import ( "sync" + log "github.com/sirupsen/logrus" + "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -32,6 +34,8 @@ func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) { Network: network, } + log.Debugf("init enable service security: %t", c.EnableServiceSecurity) + return newCluster, nil } diff --git a/pkg/iptables/iptables.go b/pkg/iptables/iptables.go index 9419a29c..adb1ca05 100644 --- a/pkg/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -63,6 +63,11 @@ const ( ProtocolIPv6 ) +const ( + TableFilter = "filter" + ChainInput = "INPUT" +) + type IPTables struct { path string proto Protocol @@ -719,3 +724,14 @@ func filterRuleOutput(rule string) string { return out } + +func GetIPTablesRuleSpecification(rule, specification string) string { + parts := strings.Split(rule, " ") + for i, part := range parts { + if part == specification && i+1 < len(parts) { + return parts[i+1] + } + } + + return "" +} diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 1c8e81b3..5c7c8a9a 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -167,7 +167,7 @@ func ParseEnvironment(c *Config) error { if env != "" { c.LoadBalancerClassName = env } - + // Find the namespace that the control plane should use (for leaderElection lock) env = os.Getenv(svcNamespace) if env != "" { @@ -400,6 +400,15 @@ func ParseEnvironment(c *Config) error { c.LoadBalancerForwardingMethod = env } + env = os.Getenv(EnableServiceSecurity) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableServiceSecurity = b + } + // Find Prometheus configuration env = os.Getenv(prometheusServer) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index ef1cc52d..e21f01a3 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -135,7 +135,7 @@ const ( //lbClassName enables load-balancer for a specific class only lbClassName = "lb_class_name" - + //lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" @@ -145,6 +145,9 @@ const ( //lbForwardingMethod defines the forwarding method of load-balancer lbForwardingMethod = "lb_fwdmethod" + // EnableServiceSecurity defines if the load-balancer should only allow traffic to service ports + EnableServiceSecurity = "enable_service_security" + //prometheusServer defines the address prometheus listens on prometheusServer = "prometheus_server" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index dad95941..b6a54395 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -127,6 +127,15 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } newEnvironment = append(newEnvironment, lbClassOnlyVar...) } + if c.EnableServiceSecurity { + EnableServiceSecurityVar := []corev1.EnvVar{ + { + Name: EnableServiceSecurity, + Value: strconv.FormatBool(c.EnableServiceSecurity), + }, + } + newEnvironment = append(newEnvironment, EnableServiceSecurityVar...) + } } // If Leader election is enabled then add the configuration to the manifest diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 0e085e83..be842419 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -38,7 +38,10 @@ type Config struct { // LoadBalancerClassName, will limit the load balancing services to services with LoadBalancerClass set to this value LoadBalancerClassName string `yaml:"lbClassName"` - + + // EnableServiceSecurity, will enable the use of iptables to secure services + EnableServiceSecurity bool `yaml:"EnableServiceSecurity"` + // ArpBroadcastRate, defines how often kube-vip will update the network about updates to the network ArpBroadcastRate int64 `yaml:"arpBroadcastRate"` diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 986859b3..b5192a5d 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -6,13 +6,14 @@ import ( "time" "github.com/insomniacslk/dhcp/dhcpv4/nclient4" + log "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" + v1 "k8s.io/api/core/v1" + "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/service" "github.com/kube-vip/kube-vip/pkg/vip" - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - v1 "k8s.io/api/core/v1" ) const dhcpTimeout = 10 * time.Second @@ -55,16 +56,17 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { // Generate new Virtual IP configuration newVip := &kubevip.Config{ - VIP: instanceAddress, //TODO support more than one vip? - Interface: serviceInterface, - SingleNode: true, - EnableARP: config.EnableARP, - EnableBGP: config.EnableBGP, - VIPCIDR: config.VIPCIDR, - VIPSubnet: config.VIPSubnet, - EnableRoutingTable: config.EnableRoutingTable, - RoutingTableID: config.RoutingTableID, - ArpBroadcastRate: config.ArpBroadcastRate, + VIP: instanceAddress, //TODO support more than one vip? + Interface: serviceInterface, + SingleNode: true, + EnableARP: config.EnableARP, + EnableBGP: config.EnableBGP, + VIPCIDR: config.VIPCIDR, + VIPSubnet: config.VIPSubnet, + EnableRoutingTable: config.EnableRoutingTable, + RoutingTableID: config.RoutingTableID, + ArpBroadcastRate: config.ArpBroadcastRate, + EnableServiceSecurity: config.EnableServiceSecurity, } // Create new service @@ -77,6 +79,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { instance.Type = string(svc.Spec.Ports[0].Protocol) instance.Port = svc.Spec.Ports[0].Port } + if svc.Annotations != nil { instance.dhcpInterfaceHwaddr = svc.Annotations[hwAddrKey] instance.dhcpInterfaceIP = svc.Annotations[requestedIP] @@ -116,6 +119,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { log.Errorf("Failed to add Service %s/%s", svc.Namespace, svc.Name) return nil, err } + c.Network.SetServicePorts(svc) instance.cluster = c return instance, nil diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9de6a0c9..e2247f84 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -8,13 +8,14 @@ import ( "sync" "time" - "github.com/kube-vip/kube-vip/pkg/service" - "github.com/kube-vip/kube-vip/pkg/vip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" + + "github.com/kube-vip/kube-vip/pkg/service" + "github.com/kube-vip/kube-vip/pkg/vip" ) const ( @@ -45,7 +46,8 @@ func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.W if sm.serviceInstances[x].isDHCP && newServiceAddress != "0.0.0.0" || !sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0" || !sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && - newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP { + newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP || + len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc) { if err := sm.deleteService(newServiceUID); err != nil { return err } @@ -65,6 +67,19 @@ func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.W return nil } +func comparePortsAndPortStatuses(svc *v1.Service) bool { + portsStatus := svc.Status.LoadBalancer.Ingress[0].Ports + if len(portsStatus) != len(svc.Spec.Ports) { + return false + } + for i, portSpec := range svc.Spec.Ports { + if portsStatus[i].Port != portSpec.Port || portsStatus[i].Protocol != portSpec.Protocol { + return false + } + } + return true +} + func (sm *Manager) addService(svc *v1.Service) error { startTime := time.Now() @@ -241,7 +256,17 @@ func (sm *Manager) updateStatus(i *Instance) error { return err } - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: i.vipConfig.VIP}} + ports := make([]v1.PortStatus, 0, len(i.serviceSnapshot.Spec.Ports)) + for _, port := range i.serviceSnapshot.Spec.Ports { + ports = append(ports, v1.PortStatus{ + Port: port.Port, + Protocol: port.Protocol, + }) + } + updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{ + IP: i.vipConfig.VIP, + Ports: ports, + }} _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) if err != nil { log.Errorf("Error updating Service %s/%s Status: %v", i.serviceSnapshot.Namespace, i.serviceSnapshot.Name, err) diff --git a/pkg/service/services.go b/pkg/service/services.go index 77097d5b..8acfeb4e 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -7,12 +7,13 @@ import ( "fmt" "strings" - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/kubevip" ) const ( @@ -91,12 +92,13 @@ func (sm *Manager) syncServices(service *v1.Service) error { // Generate new Virtual IP configuration newVip := kubevip.Config{ - VIP: newServiceAddress, //TODO support more than one vip? - Interface: sm.config.Interface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, + VIP: newServiceAddress, //TODO support more than one vip? + Interface: sm.config.Interface, + SingleNode: true, + EnableARP: sm.config.EnableARP, + EnableBGP: sm.config.EnableBGP, + VIPCIDR: sm.config.VIPCIDR, + EnableServiceSecurity: sm.config.EnableServiceSecurity, } // This instance wasn't found, we need to add it to the manager diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 97b1fcc6..245cae4e 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -1,15 +1,24 @@ package vip import ( + "fmt" + "os" + "strconv" + "strings" "sync" "github.com/pkg/errors" + log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" + v1 "k8s.io/api/core/v1" + + "github.com/kube-vip/kube-vip/pkg/iptables" ) const ( defaultValidLft = 60 + iptablesComment = "%s kube-vip load balancer IP" ) // Network is an interface that enable managing operations for a given IP @@ -21,6 +30,7 @@ type Network interface { IsSet() (bool, error) IP() string SetIP(ip string) error + SetServicePorts(service *v1.Service) Interface() string IsDADFAIL() bool IsDNS() bool @@ -33,8 +43,10 @@ type Network interface { type network struct { mu sync.Mutex - address *netlink.Addr - link netlink.Link + address *netlink.Addr + link netlink.Link + ports []v1.ServicePort + serviceName string dnsName string isDDNS bool @@ -139,6 +151,141 @@ func (configurator *network) AddIP() error { if err := netlink.AddrReplace(configurator.link, configurator.address); err != nil { return errors.Wrap(err, "could not add ip") } + + if os.Getenv("enable_service_security") == "true" { + if err := configurator.addIptablesRulesToLimitTrafficPorts(); err != nil { + return errors.Wrap(err, "could not add iptables rules to limit traffic ports") + } + } + + return nil +} + +func (configurator *network) addIptablesRulesToLimitTrafficPorts() error { + ipt, err := iptables.New() + if err != nil { + return errors.Wrap(err, "could not create iptables client") + } + + vip := configurator.address.IP.String() + comment := fmt.Sprintf(iptablesComment, configurator.serviceName) + 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) + if err := configurator.insertIPTablesRulesForServicePorts(ipt, vip, comment); err != nil { + return fmt.Errorf("could not add iptables rules for service ports: %v", err) + } + + return nil +} + +func (configurator *network) insertIPTablesRulesForServicePorts(ipt *iptables.IPTables, vip, comment string) error { + isPortsRuleExisting := make([]bool, len(configurator.ports)) + + // delete rules of ports that are not in the service + rules, err := ipt.List(iptables.TableFilter, iptables.ChainInput) + if err != nil { + return fmt.Errorf("could not list iptables rules: %w", err) + } + for _, rule := range rules { + // only handle rules with kube-vip comment + if iptables.GetIPTablesRuleSpecification(rule, "--comment") != comment { + continue + } + // if the rule is not for the vip, delete it + if iptables.GetIPTablesRuleSpecification(rule, "-d") != vip { + if err := ipt.Delete(iptables.TableFilter, iptables.ChainInput, rule); err != nil { + return fmt.Errorf("could not delete iptables rule: %w", err) + } + } + + protocol := iptables.GetIPTablesRuleSpecification(rule, "-p") + port := iptables.GetIPTablesRuleSpecification(rule, "--dport") + // ignore DHCP client port + if protocol == string(v1.ProtocolUDP) && port == dhcpClientPort { + continue + } + // if the rule is for the vip, but its protocol and port are not in the service, delete it + toBeDeleted := true + for i, p := range configurator.ports { + if string(p.Protocol) == protocol && strconv.Itoa(int(p.Port)) == port { + // the rule is for the vip and its protocol and port are in the service, keep it and mark it as existing + toBeDeleted = false + isPortsRuleExisting[i] = true + } + } + if toBeDeleted { + if err := ipt.Delete(iptables.TableFilter, iptables.ChainInput, strings.Split(rule, "")...); err != nil { + return fmt.Errorf("could not delete iptables rule: %w", err) + } + } + } + // add rules of ports that are not existing + // iptables -A INPUT -d -p --dport -j ACCEPT -m comment —comment “ kube-vip load balancer IP” + for i, ok := range isPortsRuleExisting { + if !ok { + if err := ipt.InsertUnique(iptables.TableFilter, iptables.ChainInput, 1, "-d", vip, "-p", + string(configurator.ports[i].Protocol), "--dport", strconv.Itoa(int(configurator.ports[i].Port)), + "-m", "comment", "--comment", comment, "-j", "ACCEPT"); err != nil { + return fmt.Errorf("could not add iptables rule to accept the traffic to VIP %s for allowed "+ + "port %d: %v", vip, configurator.ports[i].Port, err) + } + } + } + + return nil +} + +func insertCommonIPTablesRules(ipt *iptables.IPTables, vip, comment string) error { + if err := ipt.InsertUnique(iptables.TableFilter, iptables.ChainInput, 1, "-d", vip, "-p", + string(v1.ProtocolUDP), "--dport", dhcpClientPort, "-m", "comment", "--comment", comment, "-j", "ACCEPT"); err != nil { + return fmt.Errorf("could not add iptables rule to accept the traffic to VIP %s for DHCP client port: %w", vip, err) + } + // add rule to drop the traffic to VIP that is not allowed + // iptables -A INPUT -d -j DROP + if err := ipt.InsertUnique(iptables.TableFilter, iptables.ChainInput, 2, "-d", vip, "-m", + "comment", "--comment", comment, "-j", "DROP"); err != nil { + return fmt.Errorf("could not add iptables rule to drop the traffic to VIP %s: %v", vip, err) + } + return nil +} + +func deleteCommonIPTablesRules(ipt *iptables.IPTables, vip, comment string) error { + if err := ipt.DeleteIfExists(iptables.TableFilter, iptables.ChainInput, "-d", vip, "-p", + string(v1.ProtocolUDP), "--dport", dhcpClientPort, "-m", "comment", "--comment", comment, "-j", "ACCEPT"); err != nil { + return fmt.Errorf("could not delete iptables rule to accept the traffic to VIP %s for DHCP client port: %w", vip, err) + } + // add rule to drop the traffic to VIP that is not allowed + // iptables -A INPUT -d -j DROP + if err := ipt.DeleteIfExists(iptables.TableFilter, iptables.ChainInput, "-d", vip, "-m", "comment", + "--comment", comment, "-j", "DROP"); err != nil { + return fmt.Errorf("could not delete iptables rule to drop the traffic to VIP %s: %v", vip, err) + } + return nil +} + +func (configurator *network) removeIptablesRuleToLimitTrafficPorts() error { + ipt, err := iptables.New() + if err != nil { + return errors.Wrap(err, "could not create iptables client") + } + vip := configurator.address.IP.String() + comment := fmt.Sprintf(iptablesComment, configurator.serviceName) + + if err := deleteCommonIPTablesRules(ipt, vip, comment); err != nil { + return fmt.Errorf("could not delete common iptables rules: %w", err) + } + + log.Debugf("remove iptables rules, vip: %s, ports: %+v", vip, configurator.ports) + for _, port := range configurator.ports { + // iptables -D INPUT -d -p --dport -j ACCEPT + if err := ipt.DeleteIfExists(iptables.TableFilter, iptables.ChainInput, "-d", vip, "-p", string(port.Protocol), + "--dport", strconv.Itoa(int(port.Port)), "-m", "comment", "--comment", comment, "-j", "ACCEPT"); err != nil { + return fmt.Errorf("could not delete iptables rule to accept the traffic to VIP %s for allowed port %d: %v", vip, port.Port, err) + } + } + return nil } @@ -158,6 +305,12 @@ func (configurator *network) DeleteIP() error { return errors.Wrap(err, "could not delete ip") } + if os.Getenv("enable_service_security") == "true" { + if err := configurator.removeIptablesRuleToLimitTrafficPorts(); err != nil { + return errors.Wrap(err, "could not remove iptables rules to limit traffic ports") + } + } + return nil } @@ -227,6 +380,16 @@ func (configurator *network) SetIP(ip string) error { return nil } +// SetServicePorts updates the service ports from the service +// If you want to limit traffic to the VIP to only the service ports, add service ports to the network firstly. +func (configurator *network) SetServicePorts(service *v1.Service) { + configurator.mu.Lock() + defer configurator.mu.Unlock() + + configurator.ports = service.Spec.Ports + configurator.serviceName = service.Namespace + "/" + service.Name +} + // IP - return the IP Address func (configurator *network) IP() string { configurator.mu.Lock() diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index f0d6c085..d057013d 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -14,6 +14,8 @@ import ( log "github.com/sirupsen/logrus" ) +const dhcpClientPort = "68" + // Callback is a function called on certain events type Callback func(*nclient4.Lease) From cfbf9b0458dfcd581adbd4d0ae906fe839dfac88 Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Thu, 11 May 2023 11:38:02 -0400 Subject: [PATCH 378/542] Move helper from pkg/service and remove package The pkg/service package is no longer used. Signed-off-by: Matthew Sykes --- go.mod | 2 +- pkg/manager/instance.go | 5 +- pkg/manager/services.go | 37 ++++--- pkg/manager/watch_services.go | 7 +- pkg/service/manager.go | 111 -------------------- pkg/service/manager_arp.go | 143 -------------------------- pkg/service/manager_bgp.go | 83 --------------- pkg/service/prom.go | 10 -- pkg/service/services.go | 184 ---------------------------------- pkg/service/services_dhcp.go | 144 -------------------------- pkg/service/util.go | 17 ---- pkg/service/util_test.go | 84 ---------------- pkg/service/watcher.go | 96 ------------------ 13 files changed, 29 insertions(+), 894 deletions(-) delete mode 100644 pkg/service/manager.go delete mode 100644 pkg/service/manager_arp.go delete mode 100644 pkg/service/manager_bgp.go delete mode 100644 pkg/service/prom.go delete mode 100644 pkg/service/services.go delete mode 100644 pkg/service/services_dhcp.go delete mode 100644 pkg/service/util.go delete mode 100644 pkg/service/util_test.go delete mode 100644 pkg/service/watcher.go diff --git a/go.mod b/go.mod index 9b51b997..fadbf694 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/net v0.8.0 golang.org/x/sys v0.6.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde k8s.io/api v0.26.2 @@ -92,6 +91,7 @@ require ( github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/crypto v0.1.0 // indirect + golang.org/x/net v0.8.0 // indirect golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/term v0.6.0 // indirect diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index b5192a5d..8e19f7be 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -12,7 +12,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/cluster" "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/service" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -43,7 +42,7 @@ type Instance struct { } func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { - instanceAddress := service.FetchServiceAddress(svc) + instanceAddress := fetchServiceAddress(svc) instanceUID := string(svc.UID) // Detect if we're using a specific interface for services @@ -56,7 +55,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { // Generate new Virtual IP configuration newVip := &kubevip.Config{ - VIP: instanceAddress, //TODO support more than one vip? + VIP: instanceAddress, // TODO support more than one vip? Interface: serviceInterface, SingleNode: true, EnableARP: config.EnableARP, diff --git a/pkg/manager/services.go b/pkg/manager/services.go index ca9a3cf2..4c318339 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -14,19 +14,19 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" - "github.com/kube-vip/kube-vip/pkg/service" "github.com/kube-vip/kube-vip/pkg/vip" ) const ( - hwAddrKey = "kube-vip.io/hwaddr" - requestedIP = "kube-vip.io/requestedIP" - vipHost = "kube-vip.io/vipHost" - egress = "kube-vip.io/egress" - egressDestinationPorts = "kube-vip.io/egress-destination-ports" - egressSourcePorts = "kube-vip.io/egress-source-ports" - endpoint = "kube-vip.io/active-endpoint" - flushContrack = "kube-vip.io/flush-conntrack" + hwAddrKey = "kube-vip.io/hwaddr" + requestedIP = "kube-vip.io/requestedIP" + vipHost = "kube-vip.io/vipHost" + egress = "kube-vip.io/egress" + egressDestinationPorts = "kube-vip.io/egress-destination-ports" + egressSourcePorts = "kube-vip.io/egress-source-ports" + endpoint = "kube-vip.io/active-endpoint" + flushContrack = "kube-vip.io/flush-conntrack" + loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" ) func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.WaitGroup) error { @@ -36,7 +36,7 @@ func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.W // Iterate through the synchronising services foundInstance := false - newServiceAddress := service.FetchServiceAddress(svc) + newServiceAddress := fetchServiceAddress(svc) newServiceUID := string(svc.UID) for x := range sm.serviceInstances { @@ -104,7 +104,7 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - serviceIP := service.FetchServiceAddress(svc) + serviceIP := fetchServiceAddress(svc) // Check if we need to flush any conntrack connections (due to some dangling conntrack connections) if svc.Annotations[flushContrack] == "true" { @@ -146,7 +146,7 @@ func (sm *Manager) addService(svc *v1.Service) error { } func (sm *Manager) deleteService(uid string) error { - //pretect multiple calls + // pretect multiple calls sm.mutex.Lock() defer sm.mutex.Unlock() @@ -195,7 +195,7 @@ func (sm *Manager) deleteService(uid string) error { // If we've been through all services and not found the correct one then error if !found { // TODO: - fix UX - //return fmt.Errorf("unable to find/stop service [%s]", uid) + // return fmt.Errorf("unable to find/stop service [%s]", uid) return nil } @@ -281,3 +281,14 @@ func (sm *Manager) updateStatus(i *Instance) error { } return nil } + +// fetchServiceAddress tries to get the address from annotations +// kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP +func fetchServiceAddress(s *v1.Service) string { + if s.Annotations != nil { + if v, ok := s.Annotations[loadbalancerIPAnnotation]; ok { + return v + } + } + return s.Spec.LoadBalancerIP +} diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index e803d8eb..634d8f0c 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -15,8 +15,6 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" - - "github.com/kube-vip/kube-vip/pkg/service" ) // TODO: Fix the naming of these contexts @@ -103,7 +101,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } // We only care about LoadBalancer services that have been allocated an address - if service.FetchServiceAddress(svc) == "" { + if fetchServiceAddress(svc) == "" { break } @@ -126,7 +124,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } - log.Debugf("service [%s] has been added/modified with addresses [%s]", svc.Name, service.FetchServiceAddress(svc)) + log.Debugf("service [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddress(svc)) // Scenarios: // 1. @@ -209,7 +207,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context statusErr, ok := errObject.(*apierrors.StatusError) if !ok { log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - } status := statusErr.ErrStatus diff --git a/pkg/service/manager.go b/pkg/service/manager.go deleted file mode 100644 index aa4387f2..00000000 --- a/pkg/service/manager.go +++ /dev/null @@ -1,111 +0,0 @@ -//nolint:unparam - -package service - -import ( - "fmt" - "os" - "strings" - - "github.com/kamhlos/upnp" - "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/vip" - "github.com/prometheus/client_golang/prometheus" - log "github.com/sirupsen/logrus" - "k8s.io/client-go/kubernetes" -) - -const plunderLock = "plunder-lock" - -var signalChan chan os.Signal - -// Manager defines the manager of the load-balancing services -type Manager struct { - clientSet *kubernetes.Clientset - configMap string - config *kubevip.Config - - // Keeps track of all running instances - serviceInstances []Instance - - // Additional functionality - upnp *upnp.Upnp - - //BGP Manager, this is a singleton that manages all BGP advertisements - bgpServer *bgp.Server - - // This channel is used to signal a shutdown - signalChan chan os.Signal - - // This is a prometheus counter used to count the number of events received - // from the service watcher - countServiceWatchEvent *prometheus.CounterVec - - // This is a prometheus gauge indicating the state of the sessions. - // 1 means "ESTABLISHED", 0 means "NOT ESTABLISHED" - bgpSessionInfoGauge *prometheus.GaugeVec -} - -// Instance defines an instance of everything needed to manage a vip -type Instance struct { - // Virtual IP / Load Balancer configuration - vipConfig kubevip.Config - - // cluster instance - cluster cluster.Cluster - - // Service uses DHCP - isDHCP bool - dhcpInterface string - dhcpInterfaceHwaddr string - dhcpInterfaceIP string - dhcpClient *vip.DHCPClient - - // Kubernetes service mapping - Vip string - Port int32 - UID string - Type string - - ServiceName string -} - -// NewManager will create a new managing object -func NewManager(configMap string, config *kubevip.Config, clientset *kubernetes.Clientset) (*Manager, error) { - return &Manager{ - clientSet: clientset, - configMap: configMap, - config: config, - }, nil -} - -// Start will begin the Manager, which will start services and watch the configmap -func (sm *Manager) Start() error { - - // If BGP is enabled then we start a server instance that will broadcast VIPs - if sm.config.EnableBGP { - log.Infoln("Starting loadBalancer Service with the BGP engine") - return sm.startBGP() - } - - // If ARP is enabled then we start a LeaderElection that will use ARP to advertise VIPs - if sm.config.EnableARP { - log.Infoln("Starting loadBalancer Service with the ARP engine") - return sm.startARP() - } - - log.Infoln("Prematurely exiting Load-balancer as neither Layer2 or Layer3 is enabled") - return nil -} - -func returnNameSpace() (string, error) { - if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { - if ns := strings.TrimSpace(string(data)); len(ns) > 0 { - return ns, nil - } - return "", err - } - return "", fmt.Errorf("Unable to find Namespace") -} diff --git a/pkg/service/manager_arp.go b/pkg/service/manager_arp.go deleted file mode 100644 index b8e3e098..00000000 --- a/pkg/service/manager_arp.go +++ /dev/null @@ -1,143 +0,0 @@ -//nolint:unparam -package service - -import ( - "context" - "os" - "os/signal" - "strconv" - "syscall" - "time" - - "github.com/kamhlos/upnp" - 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" -) - -// Start will begin the Manager, which will start services and watch the configmap -func (sm *Manager) startARP() error { - ns, err := returnNameSpace() - if err != nil { - return err - } - - id, err := os.Hostname() - if err != nil { - return err - } - - // Before starting the leader Election enable any additional functionality - upnpEnabled, _ := strconv.ParseBool(os.Getenv("enableUPNP")) - - if upnpEnabled { - sm.upnp = new(upnp.Upnp) - err := sm.upnp.ExternalIPAddr() - if err != nil { - log.Errorf("Error Enabling UPNP %s", err.Error()) - // Set the struct to nil so nothing should use it in future - sm.upnp = nil - } else { - log.Infof("Successfully enabled UPNP, Gateway address [%s]", sm.upnp.GatewayOutsideIP) - } - } - - // // If BGP is enabled then we start the server that will broadcast VIPs - // if sm.config.EnableBGP { - // // Lets start BGP - // log.Info("Starting the BGP server to advertise VIP routes to VGP peers") - // sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig) - // if err != nil { - // log.Error(err) - // } - // } - - // // Defer a function to check if the bgpServer has been created and if so attempt to close it - // defer func() { - // if sm.bgpServer != nil { - // sm.bgpServer.Close() - // } - // }() - - log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, 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{ - LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, - Namespace: ns, - }, - Client: sm.clientSet.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{ - Identity: id, - }, - } - - // use a Go context so we can tell the leaderelection code when we - // want to step down - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // listen for interrupts or the Linux SIGTERM signal and cancel - // our context, which the leader election code will observe and - // step down - signalChan := make(chan os.Signal, 1) - // Add Notification for Userland interrupt - signal.Notify(signalChan, syscall.SIGINT) - - // Add Notification for SIGTERM (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGTERM) - - // Add Notification for SIGKILL (sent from Kubernetes) - //nolint - signal.Notify(signalChan, syscall.SIGKILL) - go func() { - <-signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context, which will in turn cancel the leadership - cancel() - }() - - // start the leader election code loop - leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ - Lock: lock, - // IMPORTANT: you MUST ensure that any code you have that - // is protected by the lease must terminate **before** - // you call cancel. Otherwise, you could have a background - // loop still running and another process could - // get elected before your background loop finished, violating - // the stated goal of the lease. - ReleaseOnCancel: true, - LeaseDuration: time.Duration(sm.config.LeaseDuration) * time.Second, - RenewDeadline: time.Duration(sm.config.RenewDeadline) * time.Second, - RetryPeriod: time.Duration(sm.config.RetryPeriod) * time.Second, - Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - if err := sm.servicesWatcher(ctx); err != nil { - log.Fatalf("error starting services watcher: %v", err) - } - }, - OnStoppedLeading: func() { - // we can do cleanup here - log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() - } - }, - OnNewLeader: func(identity string) { - // we're notified when new leader elected - if identity == id { - // I just got the lock - return - } - log.Infof("new leader elected: %s", identity) - }, - }, - }) - - //<-signalChan - log.Infof("Shutting down Kube-Vip") - - return nil -} diff --git a/pkg/service/manager_bgp.go b/pkg/service/manager_bgp.go deleted file mode 100644 index 0f417d20..00000000 --- a/pkg/service/manager_bgp.go +++ /dev/null @@ -1,83 +0,0 @@ -//nolint:unparam - -package service - -import ( - "context" - "os" - "os/signal" - "syscall" - - "github.com/kube-vip/kube-vip/pkg/bgp" - "github.com/kube-vip/kube-vip/pkg/equinixmetal" - "github.com/packethost/packngo" - log "github.com/sirupsen/logrus" -) - -// Start will begin the Manager, which will start services and watch the configmap -func (sm *Manager) startBGP() error { - // If Equinix Metal is enabled then we can begin our preparation work - var packetClient *packngo.Client - var err error - if sm.config.EnableMetal { - packetClient, err = packngo.NewClient() - if err != nil { - log.Error(err) - } - - // 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 packet") - err = equinixmetal.BGPLookup(packetClient, sm.config) - if err != nil { - log.Error(err) - } - } - } - - log.Info("Starting the BGP server to advertise VIP routes to VGP peers") - sm.bgpServer, err = bgp.NewBGPServer(&sm.config.BGPConfig, nil) - if err != nil { - return err - } - - // Defer a function to check if the bgpServer has been created and if so attempt to close it - defer func() { - if sm.bgpServer != nil { - sm.bgpServer.Close() - } - }() - - // use a Go context so we can tell the leaderelection code when we - // want to step down - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // listen for interrupts or the Linux SIGTERM signal and cancel - // our context, which the leader election code will observe and - // step down - signalChan = make(chan os.Signal, 1) - // Add Notification for Userland interrupt - signal.Notify(signalChan, syscall.SIGINT) - - // Add Notification for SIGTERM (sent from Kubernetes) - signal.Notify(signalChan, syscall.SIGTERM) - - // Add Notification for SIGKILL (sent from Kubernetes) - //nolint - signal.Notify(signalChan, syscall.SIGKILL) - go func() { - <-signalChan - log.Info("Received termination, signaling shutdown") - // Cancel the context, which will in turn cancel the leadership - cancel() - }() - - if err := sm.servicesWatcher(ctx); err != nil { - log.Fatalf("error starting services watcher: %v", err) - } - - log.Infof("Shutting down Kube-Vip") - - return nil -} diff --git a/pkg/service/prom.go b/pkg/service/prom.go deleted file mode 100644 index 8ed38954..00000000 --- a/pkg/service/prom.go +++ /dev/null @@ -1,10 +0,0 @@ -//nolint:unparam - -package service - -import "github.com/prometheus/client_golang/prometheus" - -// PrometheusCollector - required for statistics // TODO - improve monitoring -func (sm *Manager) PrometheusCollector() []prometheus.Collector { - return []prometheus.Collector{sm.countServiceWatchEvent, sm.bgpSessionInfoGauge} -} diff --git a/pkg/service/services.go b/pkg/service/services.go deleted file mode 100644 index 8acfeb4e..00000000 --- a/pkg/service/services.go +++ /dev/null @@ -1,184 +0,0 @@ -//nolint:unparam - -package service - -import ( - "context" - "fmt" - "strings" - - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" -) - -const ( - hwAddrKey = "kube-vip.io/hwaddr" - requestedIP = "kube-vip.io/requestedIP" - loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" -) - -func (sm *Manager) stopService(uid string) error { - found := false - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == uid { - found = true - sm.serviceInstances[x].cluster.Stop() - } - } - if !found { - return fmt.Errorf("unable to find/stop service [%s]", uid) - } - return nil -} - -func (sm *Manager) deleteService(uid string) error { - var updatedInstances []Instance - found := false - for x := range sm.serviceInstances { - // Add the running services to the new array - if sm.serviceInstances[x].UID != uid { - updatedInstances = append(updatedInstances, sm.serviceInstances[x]) - } else { - // Flip the found when we match - found = true - if sm.serviceInstances[x].isDHCP { - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) - if err != nil { - return fmt.Errorf("error finding VIP Interface, for deleting DHCP Link : %v", err) - } - if err := netlink.LinkDel(macvlan); err != nil { - return fmt.Errorf("error deleing link: %v", err) - } - } - if sm.serviceInstances[x].vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) - err := sm.bgpServer.DelHost(cidrVip) - return err - } - } - } - // If we've been through all services and not found the correct one then error - if !found { - return fmt.Errorf("unable to find/stop service [%s]", uid) - } - - // Update the service array - sm.serviceInstances = updatedInstances - - log.Infof("Removed [%s] from manager, [%d] advertised services remain", uid, len(sm.serviceInstances)) - - return nil -} - -func (sm *Manager) syncServices(service *v1.Service) error { - log.Debugf("[STARTING] Service Sync") - // Iterate through the synchronising services - foundInstance := false - newServiceAddress := service.Spec.LoadBalancerIP - newServiceUID := string(service.UID) - - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - // We have found this instance in the manager, we can determine if it needs updating - foundInstance = true - } - - } - - // Generate new Virtual IP configuration - newVip := kubevip.Config{ - VIP: newServiceAddress, //TODO support more than one vip? - Interface: sm.config.Interface, - SingleNode: true, - EnableARP: sm.config.EnableARP, - EnableBGP: sm.config.EnableBGP, - VIPCIDR: sm.config.VIPCIDR, - EnableServiceSecurity: sm.config.EnableServiceSecurity, - } - - // This instance wasn't found, we need to add it to the manager - if !foundInstance { - // Create new service - var newService Instance - newService.UID = newServiceUID - newService.Vip = newServiceAddress - newService.Type = string(service.Spec.Ports[0].Protocol) //TODO - support multiple port types - newService.Port = service.Spec.Ports[0].Port - newService.ServiceName = service.Name - newService.dhcpInterfaceHwaddr = service.Annotations[hwAddrKey] - newService.dhcpInterfaceIP = service.Annotations[requestedIP] - - // If this was purposely created with the address 0.0.0.0 then we will create a macvlan on the main interface and try DHCP - if newServiceAddress == "0.0.0.0" { - err := sm.createDHCPService(newServiceUID, &newVip, &newService, service) - if err != nil { - return err - } - return nil - } - - log.Infof("New VIP [%s] for [%s/%s] ", newService.Vip, newService.ServiceName, newService.UID) - - // Generate Load Balancer config - newLB := kubevip.LoadBalancer{ - Name: fmt.Sprintf("%s-load-balancer", newService.ServiceName), - Port: int(newService.Port), - Type: newService.Type, - BindToVip: true, - } - - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) - - // Create Add configuration to the new service - newService.vipConfig = newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]", newService.ServiceName, newService.UID) - return err - } - c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - - sm.upnpMap(newService) - - newService.cluster = *c - - // Begin watching this service - // TODO - we may need this - // go sm.serviceWatcher(&newService, sm.config.Namespace) - - // Update the "Status" of the LoadBalancer (one or many may do this), as long as one does it - service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - } - sm.serviceInstances = append(sm.serviceInstances, newService) - } - - log.Debugf("[COMPLETE] Service Sync") - - return nil -} - -func (sm *Manager) upnpMap(s Instance) { - // If upnp is enabled then update the gateway/router with the address - // TODO - work out if we need to mapping.Reclaim() - if sm.upnp != nil { - - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.ServiceName) - if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.ServiceName); err == nil { - log.Infof("Service should be accessible externally on port [%d]", s.Port) - } else { - sm.upnp.Reclaim() - log.Errorf("Unable to map port to gateway [%s]", err.Error()) - } - } -} diff --git a/pkg/service/services_dhcp.go b/pkg/service/services_dhcp.go deleted file mode 100644 index 5959a557..00000000 --- a/pkg/service/services_dhcp.go +++ /dev/null @@ -1,144 +0,0 @@ -//nolint:unparam - -package service - -import ( - "context" - "fmt" - "net" - - "github.com/insomniacslk/dhcp/dhcpv4/nclient4" - log "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/util/retry" - - "github.com/kube-vip/kube-vip/pkg/cluster" - "github.com/kube-vip/kube-vip/pkg/kubevip" - "github.com/kube-vip/kube-vip/pkg/vip" -) - -func (sm *Manager) createDHCPService(newServiceUID string, newVip *kubevip.Config, newService *Instance, service *v1.Service) error { - parent, err := netlink.LinkByName(sm.config.Interface) - if err != nil { - return fmt.Errorf("Error finding VIP Interface, for building DHCP Link : %v", err) - } - - // Create macvlan - - // Generate name from UID - interfaceName := fmt.Sprintf("vip-%s", newServiceUID[0:8]) - - // 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) - - hwaddr, err := net.ParseMAC(newService.dhcpInterfaceHwaddr) - if newService.dhcpInterfaceHwaddr != "" && err != nil { - return err - } - - mac := &netlink.Macvlan{ - LinkAttrs: netlink.LinkAttrs{ - Name: interfaceName, - ParentIndex: parent.Attrs().Index, - HardwareAddr: hwaddr, - }, - Mode: netlink.MACVLAN_MODE_DEFAULT, - } - - err = netlink.LinkAdd(mac) - if err != nil { - return fmt.Errorf("Could not add %s: %v", interfaceName, err) - } - - err = netlink.LinkSetUp(mac) - if err != nil { - return fmt.Errorf("Could not bring up interface [%s] : %v", interfaceName, err) - } - iface, err = net.InterfaceByName(interfaceName) - if err != nil { - return fmt.Errorf("Error finding new DHCP interface by name [%v]", err) - } - } else { - log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) - } - - var initRebootFlag bool - if newService.dhcpInterfaceIP != "" { - initRebootFlag = true - } - - client := vip.NewDHCPClient(iface, initRebootFlag, newService.dhcpInterfaceIP, func(lease *nclient4.Lease) { - newVip.VIP = lease.ACK.YourIPAddr.String() - - log.Infof("DHCP VIP [%s] for [%s/%s] ", newVip.VIP, newService.ServiceName, newServiceUID) - - // Create Add configuration to the new service - newService.vipConfig = *newVip - - // TODO - start VIP - c, err := cluster.InitCluster(&newService.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service [%s] / [%s]: %v", newService.ServiceName, newService.UID, err) - return - } - c.StartLoadBalancerService(&newService.vipConfig, sm.bgpServer) - newService.cluster = *c - - retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { - // Retrieve the latest version of Deployment before attempting update - // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver - currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - currentServiceCopy := currentService.DeepCopy() - if currentServiceCopy.Annotations == nil { - currentServiceCopy.Annotations = make(map[string]string) - } - currentServiceCopy.Annotations[hwAddrKey] = iface.HardwareAddr.String() - currentServiceCopy.Annotations[requestedIP] = newVip.VIP - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", newService.ServiceName, err) - return err - } - - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: newVip.VIP}} - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service [%s] Status: %v", newService.ServiceName, err) - return err - } - return nil - }) - - if retryErr != nil { - log.Errorf("Failed to set Services: %v", retryErr) - } - // Find an update our array - - for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - sm.serviceInstances[x] = *newService - } - } - sm.upnpMap(*newService) - }) - // Set that DHCP is enabled - newService.isDHCP = true - // Set the name of the interface so that it can be removed on Service deletion - newService.dhcpInterface = interfaceName - // Add the client so that we can call it's stop function - newService.dhcpClient = client - - sm.serviceInstances = append(sm.serviceInstances, *newService) - - go client.Start() - - return nil -} diff --git a/pkg/service/util.go b/pkg/service/util.go deleted file mode 100644 index 8e3d6386..00000000 --- a/pkg/service/util.go +++ /dev/null @@ -1,17 +0,0 @@ -//nolint:unparam - -package service - -import ( - v1 "k8s.io/api/core/v1" -) - -// it will first fetch from annotations kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP -func FetchServiceAddress(s *v1.Service) string { - if s.Annotations != nil { - if v, ok := s.Annotations[loadbalancerIPAnnotation]; ok { - return v - } - } - return s.Spec.LoadBalancerIP -} diff --git a/pkg/service/util_test.go b/pkg/service/util_test.go deleted file mode 100644 index d120da81..00000000 --- a/pkg/service/util_test.go +++ /dev/null @@ -1,84 +0,0 @@ -//nolint:unparam - -package service - -import ( - "testing" - - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func Test_FetchServiceAddress(t *testing.T) { - - tests := []struct { - name string - svc v1.Service - expectedLBIP string - }{ - { - name: "service with both annotation and spec.loadbalancerIP, get ip from annotations", - svc: v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "name", - Annotations: map[string]string{ - "kube-vip.io/loadbalancerIPs": "192.168.1.1", - }, - }, - Spec: v1.ServiceSpec{ - LoadBalancerIP: "192.168.1.2", - }, - }, - expectedLBIP: "192.168.1.1", - }, - { - name: "service with only annotations", - svc: v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "name", - Annotations: map[string]string{ - "kube-vip.io/loadbalancerIPs": "192.168.1.1", - }, - }, - Spec: v1.ServiceSpec{}, - }, - expectedLBIP: "192.168.1.1", - }, - { - name: "service with only spec.loadbalancerIp", - svc: v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "name", - }, - Spec: v1.ServiceSpec{ - LoadBalancerIP: "192.168.1.2", - }, - }, - expectedLBIP: "192.168.1.2", - }, - { - name: "service without spec.loadbalancerIp and annotations", - svc: v1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test", - Name: "name", - }, - Spec: v1.ServiceSpec{}, - }, - expectedLBIP: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ip := FetchServiceAddress(&tt.svc) - if ip != tt.expectedLBIP { - t.Errorf("got ip '%s', expected: '%s'", ip, tt.expectedLBIP) - return - } - }) - } -} diff --git a/pkg/service/watcher.go b/pkg/service/watcher.go deleted file mode 100644 index 03a54d53..00000000 --- a/pkg/service/watcher.go +++ /dev/null @@ -1,96 +0,0 @@ -//nolint:unparam - -package service - -import ( - "fmt" - - "github.com/davecgh/go-spew/spew" - log "github.com/sirupsen/logrus" - "golang.org/x/net/context" - v1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/tools/cache" - watchtools "k8s.io/client-go/tools/watch" -) - -// This file handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly -func (sm *Manager) servicesWatcher(ctx context.Context) error { - // Watch function - - // Use a restartable watcher, as this should help in the event of etcd or timeout issues - rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return sm.clientSet.CoreV1().Services(v1.NamespaceAll).Watch(ctx, metav1.ListOptions{}) - }, - }) - if err != nil { - return fmt.Errorf("error creating services watcher: %s", err.Error()) - } - go func() { - <-sm.signalChan - // Cancel the context - rw.Stop() - }() - ch := rw.ResultChan() - //defer rw.Stop() - log.Infoln("Beginning watching services for type: LoadBalancer in all namespaces") - - for event := range ch { - //sm.countServiceWatchEvent.With(prometheus.Labels{"type": string(event.Type)}).Add(1) - - // We need to inspect the event and get ResourceVersion out of it - switch event.Type { - case watch.Added, watch.Modified: - // log.Debugf("Endpoints for service [%s] have been Created or modified", s.service.ServiceName) - svc, ok := event.Object.(*v1.Service) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") - } - if FetchServiceAddress(svc) == "" { - log.Infof("Service [%s] has been added/modified, it has no assigned external addresses", svc.Name) - } else { - log.Infof("Service [%s] has been added/modified, it has an assigned external addresses [%s]", svc.Name, svc.Spec.LoadBalancerIP) - err = sm.syncServices(svc) - if err != nil { - log.Error(err) - } - } - case watch.Deleted: - svc, ok := event.Object.(*v1.Service) - if !ok { - return fmt.Errorf("Unable to parse Kubernetes services from API watcher") - } - err = sm.stopService(string(svc.UID)) - if err != nil { - log.Error(err) - } - err = sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } - log.Infof("Service [%s] has been deleted", svc.Name) - - case watch.Bookmark: - // Un-used - case watch.Error: - log.Error("Error attempting to watch Kubernetes services") - - // This round trip allows us to handle unstructured status - errObject := apierrors.FromObject(event.Object) - statusErr, ok := errObject.(*apierrors.StatusError) - if !ok { - log.Errorf(spew.Sprintf("Received an error which is not *metav1.Status but %#+v", event.Object)) - - } - - status := statusErr.ErrStatus - log.Errorf("%v", status) - default: - } - } - log.Warnln("Stopping watching services for type: LoadBalancer in all namespaces") - return nil -} From cc362f77740b140904a754f15c65ea407bae7042 Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Wed, 3 May 2023 22:36:56 -0400 Subject: [PATCH 379/542] checks - fix things flagged by linting Signed-off-by: Matthew Sykes --- cmd/kube-vip.go | 18 +++--- pkg/cluster/clusterDDNS.go | 6 +- pkg/equinixmetal/eip.go | 2 +- pkg/kubevip/config_envvar.go | 96 ++++++++++++++++---------------- pkg/kubevip/config_types.go | 6 +- pkg/manager/services.go | 2 +- pkg/vip/address.go | 10 +--- pkg/vip/dhcp.go | 3 +- testing/e2e/services/services.go | 9 +-- 9 files changed, 67 insertions(+), 85 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index de7584b5..c3ecb68e 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -51,8 +51,10 @@ var Release struct { } // Structs used via the various subcommands -var initConfig kubevip.Config -var initLoadBalancer kubevip.LoadBalancer +var ( + initConfig kubevip.Config + initLoadBalancer kubevip.LoadBalancer +) // Points to a kubernetes configuration file var kubeConfigPath string @@ -63,7 +65,6 @@ var kubeVipCmd = &cobra.Command{ } func init() { - // Basic flags kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)") @@ -211,7 +212,6 @@ var kubeVipManager = &cobra.Command{ Use: "manager", Short: "Start the kube-vip manager", Run: func(cmd *cobra.Command, args []string) { - // parse environment variables, these will overwrite anything loaded or flags err := kubevip.ParseEnvironment(&initConfig) if err != nil { @@ -273,11 +273,10 @@ var kubeVipManager = &cobra.Command{ err = netlink.LinkAdd(&netlink.Wireguard{LinkAttrs: netlink.LinkAttrs{Name: initConfig.Interface}}) if err != nil { log.Fatalln(err) - } else { - l, err = netlink.LinkByName(initConfig.Interface) - if err != nil { - log.Fatalln(err) - } + } + l, err = netlink.LinkByName(initConfig.Interface) + if err != nil { + log.Fatalln(err) } } } @@ -385,5 +384,4 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC if err == http.ErrServerClosed { err = nil } - } diff --git a/pkg/cluster/clusterDDNS.go b/pkg/cluster/clusterDDNS.go index 9f904ef2..ebacad42 100644 --- a/pkg/cluster/clusterDDNS.go +++ b/pkg/cluster/clusterDDNS.go @@ -19,9 +19,5 @@ func (cluster *Cluster) StartDDNS(ctx context.Context) error { return err } - if err = cluster.Network.SetIP(ip); err != nil { - return err - } - - return nil + return cluster.Network.SetIP(ip) } diff --git a/pkg/equinixmetal/eip.go b/pkg/equinixmetal/eip.go index ca079094..dcbe808d 100644 --- a/pkg/equinixmetal/eip.go +++ b/pkg/equinixmetal/eip.go @@ -10,7 +10,7 @@ import ( ) // AttachEIP will use the Equinix Metal APIs to move an EIP and attach to a host -func AttachEIP(c *packngo.Client, k *kubevip.Config, hostname string) error { +func AttachEIP(c *packngo.Client, k *kubevip.Config, _ string) error { // Use MetalProjectID if it is defined projID := k.MetalProjectID diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index e21f01a3..510f12fa 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -3,46 +3,46 @@ package kubevip // Environment variables const ( - //vipArp - defines if the arp broadcast should be enabled + // vipArp - defines if the arp broadcast should be enabled vipArp = "vip_arp" - //vip_arpRate - defines the rate of gARP broadcasts + // vip_arpRate - defines the rate of gARP broadcasts vipArpRate = "vip_arpRate" - //vipLeaderElection - defines if the kubernetes algorithm should be used + // vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaderElection = "vip_leaderelection" - //vipLeaderElection - defines if the kubernetes algorithm should be used + // vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaseDuration = "vip_leaseduration" - //vipLeaderElection - defines if the kubernetes algorithm should be used + // vipLeaderElection - defines if the kubernetes algorithm should be used vipRenewDeadline = "vip_renewdeadline" - //vipLeaderElection - defines if the kubernetes algorithm should be used + // vipLeaderElection - defines if the kubernetes algorithm should be used vipRetryPeriod = "vip_retryperiod" - //vipLogLevel - defines the level of logging to produce (5 being the most verbose) + // vipLogLevel - defines the level of logging to produce (5 being the most verbose) vipLogLevel = "vip_loglevel" - //vipInterface - defines the interface that the vip should bind too + // vipInterface - defines the interface that the vip should bind too vipInterface = "vip_interface" - //vipServicesInterface - defines the interface that the service vips should bind too + // vipServicesInterface - defines the interface that the service vips should bind too vipServicesInterface = "vip_servicesinterface" - //vipCidr - defines the cidr that the vip will use (for BGP) + // vipCidr - defines the cidr that the vip will use (for BGP) vipCidr = "vip_cidr" - //vipSubnet - defines the subnet that the vip will use + // vipSubnet - defines the subnet that the vip will use vipSubnet = "vip_subnet" - //egressPodCidr - defines the cidr that egress will ignore + // egressPodCidr - defines the cidr that egress will ignore egressPodCidr = "egress_podcidr" - //egressServiceCidr - defines the cidr that egress will ignore + // egressServiceCidr - defines the cidr that egress will ignore egressServiceCidr = "egress_servicecidr" - //egressWithNftables - enables using nftables over iptables + // egressWithNftables - enables using nftables over iptables egressWithNftables = "egress_withnftables" ///////////////////////////////////// @@ -50,7 +50,7 @@ const ( // Determine how to tidy this mess up ///////////////////////////////////// - //vipAddress - defines the address that the vip will expose + // vipAddress - defines the address that the vip will expose // DEPRECATED: will be removed in a next release vipAddress = "vip_address" @@ -59,98 +59,98 @@ const ( // kube-vip will try to resolve it and use the IP as a VIP address = "address" - //port - defines the port for the VIP + // port - defines the port for the VIP port = "port" // annotations annotations = "annotation" - //vipDdns - defines if use dynamic dns to allocate IP for "address" + // vipDdns - defines if use dynamic dns to allocate IP for "address" vipDdns = "vip_ddns" - //vipSingleNode - defines the vip start as a single node cluster + // vipSingleNode - defines the vip start as a single node cluster vipSingleNode = "vip_singlenode" - //vipStartLeader - will start this instance as the leader of the cluster + // vipStartLeader - will start this instance as the leader of the cluster vipStartLeader = "vip_startleader" - //vipPacket defines that the packet API will be used for EIP + // vipPacket defines that the packet API will be used for EIP vipPacket = "vip_packet" - //vipPacketProject defines which project within Packet to use + // vipPacketProject defines which project within Packet to use vipPacketProject = "vip_packetproject" - //vipPacketProjectID defines which projectID within Packet to use + // vipPacketProjectID defines which projectID within Packet to use vipPacketProjectID = "vip_packetprojectid" - //providerConfig defines a path to a configuration that should be parsed + // providerConfig defines a path to a configuration that should be parsed providerConfig = "provider_config" - //bgpEnable defines if BGP should be enabled + // bgpEnable defines if BGP should be enabled bgpEnable = "bgp_enable" - //bgpRouterID defines the routerID for the BGP server + // bgpRouterID defines the routerID for the BGP server bgpRouterID = "bgp_routerid" - //bgpRouterInterface defines the interface that we can find the address for + // bgpRouterInterface defines the interface that we can find the address for bgpRouterInterface = "bgp_routerinterface" - //bgpRouterAS defines the AS for the BGP server + // bgpRouterAS defines the AS for the BGP server bgpRouterAS = "bgp_as" - //bgpPeerAddress defines the address for a BGP peer + // bgpPeerAddress defines the address for a BGP peer bgpPeerAddress = "bgp_peeraddress" - //bgpPeers defines the address for a BGP peer + // bgpPeers defines the address for a BGP peer bgpPeers = "bgp_peers" - //bgpPeerAS defines the AS for a BGP peer + // bgpPeerAS defines the AS for a BGP peer bgpPeerAS = "bgp_peeras" - //bgpPeerAS defines the AS for a BGP peer + // bgpPeerAS defines the AS for a BGP peer bgpPeerPassword = "bgp_peerpass" // nolint - //bgpMultiHop enables mulithop routing + // bgpMultiHop enables mulithop routing bgpMultiHop = "bgp_multihop" - //bgpSourceIF defines the source interface for BGP peering + // bgpSourceIF defines the source interface for BGP peering bgpSourceIF = "bgp_sourceif" - //bgpSourceIP defines the source address for BGP peering + // bgpSourceIP defines the source address for BGP peering bgpSourceIP = "bgp_sourceip" - //vipWireguard - defines if wireguard will be used for vips + // vipWireguard - defines if wireguard will be used for vips vipWireguard = "vip_wireguard" //nolint - //vipRoutingTable - defines if table mode will be used for vips + // vipRoutingTable - defines if table mode will be used for vips vipRoutingTable = "vip_routingtable" //nolint - //cpNamespace defines the namespace the control plane pods will run in + // cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" - //cpEnable enables the control plane feature + // cpEnable enables the control plane feature cpEnable = "cp_enable" - //svcEnable enables the Kubernetes service feature + // svcEnable enables the Kubernetes service feature svcEnable = "svc_enable" - //svcNamespace defines the namespace the service pods will run in + // svcNamespace defines the namespace the service pods will run in svcNamespace = "svc_namespace" - //svcElection enables election per Kubernetes service + // svcElection enables election per Kubernetes service svcElection = "svc_election" - //lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only + // lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only lbClassOnly = "lb_class_only" - //lbClassName enables load-balancer for a specific class only + // lbClassName enables load-balancer for a specific class only lbClassName = "lb_class_name" - //lbEnable defines if the load-balancer should be enabled + // lbEnable defines if the load-balancer should be enabled lbEnable = "lb_enable" - //lbPort defines the port of load-balancer + // lbPort defines the port of load-balancer lbPort = "lb_port" - //lbForwardingMethod defines the forwarding method of load-balancer + // lbForwardingMethod defines the forwarding method of load-balancer lbForwardingMethod = "lb_fwdmethod" // EnableServiceSecurity defines if the load-balancer should only allow traffic to service ports EnableServiceSecurity = "enable_service_security" - //prometheusServer defines the address prometheus listens on + // prometheusServer defines the address prometheus listens on prometheusServer = "prometheus_server" - //vipConfigMap defines the configmap that kube-vip will watch for service definitions + // vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" ) diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index be842419..3552b0cb 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -8,7 +8,6 @@ import ( // Config defines all of the settings for the Kube-Vip Pod type Config struct { - // Logging, settings Logging int `yaml:"logging"` @@ -142,7 +141,6 @@ type Config struct { // LeaderElection defines all of the settings for Kubernetes LeaderElection type LeaderElection struct { - // EnableLeaderElection will use the Kubernetes leader election algorithm EnableLeaderElection bool `yaml:"enableLeaderElection"` @@ -170,10 +168,10 @@ type LoadBalancer struct { // BindToVip will bind the load balancer port to the VIP itself BindToVip bool `yaml:"bindToVip"` - //BackendPort, is a port that all backends are listening on (To be used to simplify building a list of backends) + // BackendPort, is a port that all backends are listening on (To be used to simplify building a list of backends) BackendPort int `yaml:"backendPort"` - //Backends, is an array of backend servers + // Backends, is an array of backend servers Backends []BackEnd `yaml:"backends"` // Forwarding method of LoadBalancer, either Local, Tunnel, DirectRoute or Bypass diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 4c318339..02f05b89 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -29,7 +29,7 @@ const ( loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" ) -func (sm *Manager) syncServices(ctx context.Context, svc *v1.Service, wg *sync.WaitGroup) error { +func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.WaitGroup) error { defer wg.Done() log.Debugf("[STARTING] Service Sync") diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 245cae4e..eadaf833 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -126,10 +126,7 @@ func (configurator *network) AddRoute() error { LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, } - if err := netlink.RouteAdd(route); err != nil { - return err - } - return nil + return netlink.RouteAdd(route) } // AddRoute - Add an IP address to a route table @@ -140,10 +137,7 @@ func (configurator *network) DeleteRoute() error { LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, } - if err := netlink.RouteDel(route); err != nil { - return err - } - return nil + return netlink.RouteDel(route) } // AddIP - Add an IP address to the interface diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index d057013d..cb90101b 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -131,9 +131,8 @@ func (c *DHCPClient) Start() { log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur) time.Sleep(dur) continue - } else { - backoff.Reset() } + backoff.Reset() c.initRebootFlag = false c.lease = lease diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index e0e406a7..0a35d6e0 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -29,7 +29,7 @@ import ( func main() { log.Info("🔬 beginning e2e tests") - //return + // return _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") _, ignoreDeployments := os.LookupEnv("IGNORE_DEPLOY") @@ -284,9 +284,8 @@ func main() { deploy.address = GetLocalIP() if deploy.address == "" { log.Fatalf("Unable to detect local IP address") - } else { - log.Infof("📠 found local address [%s]", deploy.address) } + log.Infof("📠 found local address [%s]", deploy.address) err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) @@ -391,7 +390,6 @@ func leaderFailover(ctx context.Context, name, leaderNode *string, clientset *ku // Used for tracking an active endpoint / pod for event := range ch { - // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added: @@ -475,7 +473,6 @@ func podFailover(ctx context.Context, name, leaderNode *string, clientset *kuber // Used for tracking an active endpoint / pod for event := range ch { - // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added: @@ -525,7 +522,7 @@ func tcpServer(egressAddress *string) bool { conn, err := listen.Accept() if err != nil { return false - //log.Fatal(err) + // log.Fatal(err) } remoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) log.Infof("📞 incoming from [%s]", remoteAddress) From 9ec6b3e8f508219a57d8a9ff7d5793328174dc10 Mon Sep 17 00:00:00 2001 From: Canwu Yao Date: Fri, 12 May 2023 10:48:44 +0800 Subject: [PATCH 380/542] Add annotation kube-vip.io/ignore-service-security Skip service security configuration for the service whose annotation kube-vip.io/ignore-service-security is true Signed-off-by: Canwu Yao --- pkg/vip/address.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pkg/vip/address.go b/pkg/vip/address.go index eadaf833..98e27991 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -17,8 +17,9 @@ import ( ) const ( - defaultValidLft = 60 - iptablesComment = "%s kube-vip load balancer IP" + defaultValidLft = 60 + iptablesComment = "%s kube-vip load balancer IP" + ignoreServiceSecurityAnnotation = "kube-vip.io/ignore-service-security" ) // Network is an interface that enable managing operations for a given IP @@ -43,10 +44,11 @@ type Network interface { type network struct { mu sync.Mutex - address *netlink.Addr - link netlink.Link - ports []v1.ServicePort - serviceName string + address *netlink.Addr + link netlink.Link + ports []v1.ServicePort + serviceName string + ignoreSecurity bool dnsName string isDDNS bool @@ -146,7 +148,7 @@ func (configurator *network) AddIP() error { return errors.Wrap(err, "could not add ip") } - if os.Getenv("enable_service_security") == "true" { + if os.Getenv("enable_service_security") == "true" && !configurator.ignoreSecurity { if err := configurator.addIptablesRulesToLimitTrafficPorts(); err != nil { return errors.Wrap(err, "could not add iptables rules to limit traffic ports") } @@ -299,7 +301,7 @@ func (configurator *network) DeleteIP() error { return errors.Wrap(err, "could not delete ip") } - if os.Getenv("enable_service_security") == "true" { + if os.Getenv("enable_service_security") == "true" && !configurator.ignoreSecurity { if err := configurator.removeIptablesRuleToLimitTrafficPorts(); err != nil { return errors.Wrap(err, "could not remove iptables rules to limit traffic ports") } @@ -382,6 +384,7 @@ func (configurator *network) SetServicePorts(service *v1.Service) { configurator.ports = service.Spec.Ports configurator.serviceName = service.Namespace + "/" + service.Name + configurator.ignoreSecurity = service.Annotations[ignoreServiceSecurityAnnotation] == "true" } // IP - return the IP Address From b594d459fc4e2061015157715fc84e84bee12d81 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Mon, 15 May 2023 12:29:34 +0100 Subject: [PATCH 381/542] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 02a7f7bb..b785ea18 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL: $(TARGET) # These will be provided to the target -VERSION := v0.5.12 +VERSION := v0.6.0 BUILD := `git rev-parse HEAD` From 2a21b87b77c30283b27b01beca2929053d8cd294 Mon Sep 17 00:00:00 2001 From: Enkel Prifti <43306174+enkelprifti98@users.noreply.github.com> Date: Thu, 18 May 2023 20:09:26 -0400 Subject: [PATCH 382/542] Add BGP password support for Equinix Metal The Equinix Metal API integration was missing support for BGP session passwords so this PR adds the BGP password parameter. Signed-off-by: Enkel Prifti --- pkg/equinixmetal/bgp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/equinixmetal/bgp.go b/pkg/equinixmetal/bgp.go index f229a196..5f113aa6 100644 --- a/pkg/equinixmetal/bgp.go +++ b/pkg/equinixmetal/bgp.go @@ -54,6 +54,7 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error { Address: neighbours[0].PeerIps[x], AS: uint32(neighbours[0].PeerAs), MultiHop: neighbours[0].Multihop, + Password: neighbours[0].Md5Password, } k.BGPConfig.Peers = append(k.BGPConfig.Peers, peer) } From d7f4abafb89b62de65bb32615843ed0aff45d88f Mon Sep 17 00:00:00 2001 From: Enkel Prifti <43306174+enkelprifti98@users.noreply.github.com> Date: Fri, 19 May 2023 16:56:37 -0400 Subject: [PATCH 383/542] Add support for multiple BGP peers when using Equinix Metal annotations Using Equinix Metal annotations was limited to only the first BGP peer. This PR adds support for multiple BGP peer by looking at all bgp peer node annotations. Signed-off-by: Enkel Prifti --- pkg/manager/watch_annotations.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index dfe23b57..7445d0f7 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -208,11 +208,13 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er peerIPString := "" for k, v := range node.Annotations { - regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-0-)?peer-ip", prefix)) + regex := regexp.MustCompile(fmt.Sprintf("^%s/(bgp-peers-[0-9]+-)?peer-ip", prefix)) if regex.Match([]byte(k)) { - peerIPString = v + peerIPString += v + "," } } + peerIPString = strings.TrimRight(peerIPString, ",") + peerIPs := strings.Split(peerIPString, ",") for _, peerIP := range peerIPs { From 24588d006a66d7691ab053875cea9995acd3e861 Mon Sep 17 00:00:00 2001 From: Chris Privitere <23177737+cprivitere@users.noreply.github.com> Date: Fri, 19 May 2023 16:16:32 -0500 Subject: [PATCH 384/542] fix: formatting spaces on 217 --- pkg/manager/watch_annotations.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index 7445d0f7..93bc7f35 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -214,7 +214,7 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er } } peerIPString = strings.TrimRight(peerIPString, ",") - + peerIPs := strings.Split(peerIPString, ",") for _, peerIP := range peerIPs { From ef4995841a82883df26d9d44c4c9d6b52bb701dd Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Fri, 19 May 2023 22:52:48 +0100 Subject: [PATCH 385/542] Revert "adding iptables-wrappers script to entrypoint" --- Dockerfile_iptables | 7 +------ entrypoint_iptables.sh | 6 ------ 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 entrypoint_iptables.sh diff --git a/Dockerfile_iptables b/Dockerfile_iptables index ff1f003c..01e236b7 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -16,9 +16,4 @@ FROM alpine:3.16.2 RUN apk add --no-cache iptables # Add kube-vip binary COPY --from=dev /src/kube-vip / -COPY /entrypoint_iptables.sh / -# Adding iptables-wrapper-installer from https://github.com/kubernetes-sigs/iptables-wrappers -ADD https://raw.githubusercontent.com/kubernetes-sigs/iptables-wrappers/v2/iptables-wrapper-installer.sh / -RUN chmod 755 /entrypoint_iptables.sh /iptables-wrapper-installer.sh - -ENTRYPOINT ["/entrypoint_iptables.sh"] +ENTRYPOINT ["/kube-vip"] diff --git a/entrypoint_iptables.sh b/entrypoint_iptables.sh deleted file mode 100644 index f55773e1..00000000 --- a/entrypoint_iptables.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -echo "Executing /iptables-wrapper-installer.sh to configure iptables ..." -/iptables-wrapper-installer.sh - -echo "Executing /kube-vip $@" -exec /kube-vip "$@" From cd29e3d70a01cf6c1c6d3007e9707a45f3c25193 Mon Sep 17 00:00:00 2001 From: lubronzhan Date: Mon, 22 May 2023 14:35:41 -0700 Subject: [PATCH 386/542] Check activeServiceLoadBalancerCancel is nil or not before calling it Signed-off-by: lubronzhan --- pkg/manager/watch_services.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 634d8f0c..fdfdcfcd 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -191,8 +191,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if err != nil { log.Error(err) } + // Calls the cancel function of the context - activeServiceLoadBalancerCancel[string(svc.UID)]() + if activeServiceLoadBalancerCancel[string(svc.UID)] != nil { + + activeServiceLoadBalancerCancel[string(svc.UID)]() + } activeService[string(svc.UID)] = false watchedService[string(svc.UID)] = false From 313c4c04f8f06ae6559d42f2f3f4ab28cd54eaee Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Thu, 25 May 2023 16:37:21 +0200 Subject: [PATCH 387/542] use config leasename instead of hardcoded Signed-off-by: Timo Sluis --- cmd/kube-vip.go | 1 + pkg/cluster/clusterLeaderElection.go | 6 ++---- pkg/kubevip/config_environment.go | 6 ++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 4 ++++ pkg/kubevip/config_types.go | 3 +++ 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index c3ecb68e..1c2945bd 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -87,6 +87,7 @@ func init() { // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.LeaseName, "leaseName", "plndr-cp-lock", "Name of the lease that is used for leader election") kubeVipCmd.PersistentFlags().IntVar(&initConfig.LeaseDuration, "leaseDuration", 5, "Length of time a Kubernetes leader lease can be held for") kubeVipCmd.PersistentFlags().IntVar(&initConfig.RenewDeadline, "leaseRenewDuration", 3, "Length of time a Kubernetes leader can attempt to renew its lease") kubeVipCmd.PersistentFlags().IntVar(&initConfig.RetryPeriod, "leaseRetry", 1, "Number of times the host will retry to hold a lease") diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 4a9d501d..3046e05a 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -30,8 +30,6 @@ import ( watchtools "k8s.io/client-go/tools/watch" ) -const plunderLock = "plndr-cp-lock" - // Manager degines the manager of the load-balancing services type Manager struct { KubernetesClient *kubernetes.Clientset @@ -79,13 +77,13 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * return err } - log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", c.Namespace, plunderLock, id) + log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", c.Namespace, c.LeaseName, 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{ LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, + Name: c.LeaseName, Namespace: c.Namespace, }, Client: sm.KubernetesClient.CoordinationV1(), diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 5c7c8a9a..9095c00a 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -53,6 +53,12 @@ func ParseEnvironment(c *Config) error { c.EnableLeaderElection = b } + // Attempt to find the Lease name from the environment variables + env = os.Getenv(vipLeaseName) + if env != "" { + c.LeaseName = env + } + // Attempt to find the Lease configuration from the environment variables env = os.Getenv(vipLeaseDuration) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 510f12fa..40da58d7 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -12,6 +12,9 @@ const ( // vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaderElection = "vip_leaderelection" + // vipLeaseName - defines the name of the lease lock + vipLeaseName = "vip_leasename" + // vipLeaderElection - defines if the kubernetes algorithm should be used vipLeaseDuration = "vip_leaseduration" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index b6a54395..16610c86 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -146,6 +146,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: vipLeaderElection, Value: strconv.FormatBool(c.EnableLeaderElection), }, + { + Name: vipLeaseName, + Value: c.LeaseName, + }, { Name: vipLeaseDuration, Value: fmt.Sprintf("%d", c.LeaseDuration), diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 3552b0cb..072d8b3d 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -144,6 +144,9 @@ type LeaderElection struct { // EnableLeaderElection will use the Kubernetes leader election algorithm EnableLeaderElection bool `yaml:"enableLeaderElection"` + // LeaseName - name of the lease for leader election + LeaseName string `yaml:"leaseName"` + // Lease Duration - length of time a lease can be held for LeaseDuration int From 6f2acf019877b34cacb19ec27964bb7bf2666885 Mon Sep 17 00:00:00 2001 From: James Connor Date: Tue, 30 May 2023 12:54:46 +0100 Subject: [PATCH 388/542] Increase client QPS to reduce clientside k8api throttling --- pkg/k8s/client.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index 9be3848f..bb47dab7 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -32,7 +32,16 @@ func NewClientset(configPath string, inCluster bool, hostname string) (*kubernet func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { if kubeconfig != "" && !inCluster { - return clientcmd.BuildConfigFromFlags("", kubeconfig) + cfg, err = clientcmd.BuildConfigFromFlags("", kubeConfig) + } else { + cfg, err = rest.InClusterConfig() } - return rest.InClusterConfig() + + if err != nil { + return nil, err + } + + cfg.QPS = 100 + cfg.Burst = 250 + return cfg, nil } From c3ab677ad14e582dc6c5e8851c6765e9ab35317e Mon Sep 17 00:00:00 2001 From: James Connor Date: Fri, 2 Jun 2023 17:22:21 +0100 Subject: [PATCH 389/542] PR Fixes --- pkg/k8s/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index bb47dab7..2241eec8 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -32,9 +32,9 @@ func NewClientset(configPath string, inCluster bool, hostname string) (*kubernet func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { if kubeconfig != "" && !inCluster { - cfg, err = clientcmd.BuildConfigFromFlags("", kubeConfig) + cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) } else { - cfg, err = rest.InClusterConfig() + cfg, err := rest.InClusterConfig() } if err != nil { From 2dcd9e50c9e91faf8075e3732c25edbdefa8722c Mon Sep 17 00:00:00 2001 From: marc-cerebras Date: Mon, 19 Jun 2023 11:07:45 -0700 Subject: [PATCH 390/542] enable leaderelection for bgp in CP mode Signed-off-by: marc-cerebras --- pkg/cluster/clusterLeaderElection.go | 2 +- pkg/manager/manager_bgp.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 3046e05a..04b3cc45 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -167,7 +167,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * } } - if c.EnableBGP { + if c.EnableBGP && bgpServer == nil { // Lets start BGP log.Info("Starting the BGP server to advertise VIP routes to VGP peers") bgpServer, err = bgp.NewBGPServer(&c.BGPConfig, nil) diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index 353ec993..bb9cd6cb 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -109,7 +109,11 @@ func (sm *Manager) startBGP() error { } go func() { - err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer, packetClient) + if sm.config.EnableLeaderElection { + err = cpCluster.StartCluster(sm.config, clusterManager, sm.bgpServer) + } else { + err = cpCluster.StartVipService(sm.config, clusterManager, sm.bgpServer, packetClient) + } if err != nil { log.Errorf("Control Plane Error [%v]", err) // Trigger the shutdown of this manager instance From f2f7d362c76822caf172986af812cb9a0949aedc Mon Sep 17 00:00:00 2001 From: runsisi Date: Wed, 21 Jun 2023 07:53:43 +0800 Subject: [PATCH 391/542] Fix makefile default target Signed-off-by: runsisi --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b785ea18..3581cd34 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SHELL := /bin/sh # The name of the executable (default is current directory name) TARGET := kube-vip -.DEFAULT_GOAL: $(TARGET) +.DEFAULT_GOAL := $(TARGET) # These will be provided to the target VERSION := v0.6.0 From 23492519ed77d717a62cbf8494bd030e2637d98c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jul 2023 21:37:26 +0000 Subject: [PATCH 392/542] Bump google.golang.org/grpc from 1.51.0 to 1.53.0 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.51.0 to 1.53.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.51.0...v1.53.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index fadbf694..1a970134 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( github.com/BurntSushi/toml v1.2.1 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect @@ -92,15 +92,15 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/crypto v0.1.0 // indirect golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect + golang.org/x/oauth2 v0.4.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/term v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e // indirect - google.golang.org/grpc v1.51.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.53.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index d0d84085..ccf72000 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -556,8 +557,8 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -796,8 +797,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e h1:S9GbmC1iCgvbLyAokVCwiO6tVIrU9Y7c5oMx1V/ki/Y= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -814,8 +815,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 9667c7766fb681237b7e275e12c66b65ab0bd8ef Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Wed, 12 Jul 2023 11:14:14 +0200 Subject: [PATCH 393/542] add lease annotations Signed-off-by: Timo Sluis --- pkg/cluster/clusterLeaderElection.go | 5 +++-- pkg/kubevip/config_environment.go | 10 ++++++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_types.go | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 3046e05a..e117d40a 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -83,8 +83,9 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * // and fewer objects in the cluster watch "all Leases". lock := &resourcelock.LeaseLock{ LeaseMeta: metav1.ObjectMeta{ - Name: c.LeaseName, - Namespace: c.Namespace, + Name: c.LeaseName, + Namespace: c.Namespace, + Annotations: c.LeaseAnnotations, }, Client: sm.KubernetesClient.CoordinationV1(), LockConfig: resourcelock.ResourceLockConfig{ diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 9095c00a..36c8d864 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -3,6 +3,7 @@ package kubevip import ( "os" "strconv" + "encoding/json" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/detector" @@ -87,6 +88,15 @@ func ParseEnvironment(c *Config) error { c.RetryPeriod = int(i) } + // Attempt to find the Lease annotations from the environment variables + env = os.Getenv(vipLeaseAnnotations) + if env != "" { + err := json.Unmarshal([]byte(env), &c.LeaseAnnotations) + if err != nil { + return err + } + } + // Find vip address env = os.Getenv(vipAddress) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 40da58d7..25b45649 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -24,6 +24,9 @@ const ( // vipLeaderElection - defines if the kubernetes algorithm should be used vipRetryPeriod = "vip_retryperiod" + // vipLeaderElection - defines the annotations given to the lease lock + vipLeaseAnnotations = "vip_leaseannotations" + // vipLogLevel - defines the level of logging to produce (5 being the most verbose) vipLogLevel = "vip_loglevel" diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 072d8b3d..5f61a0dc 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -155,6 +155,9 @@ type LeaderElection struct { // RetryPerion - Number of times the host will retry to hold a lease RetryPeriod int + + // LeaseAnnotations - annotations which will be given to the lease object + LeaseAnnotations map[string]string } // LoadBalancer contains the configuration of a load balancing instance From 64f8ebd8651e8ca3366d871d3e225814b26d2efb Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Wed, 12 Jul 2023 11:27:49 +0200 Subject: [PATCH 394/542] fix formatting Signed-off-by: Timo Sluis --- pkg/kubevip/config_environment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 36c8d864..6b7498e4 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -1,9 +1,9 @@ package kubevip import ( + "encoding/json" "os" "strconv" - "encoding/json" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/detector" From 0060d36694d35bbb89a6e37e32af6579561d494a Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Fri, 21 Jul 2023 14:34:24 +0000 Subject: [PATCH 395/542] Update the DHCP workflows Signed-off-by: Ricardo Katz --- go.mod | 31 +++++---- go.sum | 84 +++++++++---------------- pkg/manager/instance.go | 3 +- pkg/manager/services.go | 10 +-- pkg/vip/dhcp.go | 136 +++++++++++----------------------------- 5 files changed, 88 insertions(+), 176 deletions(-) diff --git a/go.mod b/go.mod index 1a970134..f53295a2 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,12 @@ module github.com/kube-vip/kube-vip go 1.18 -replace github.com/insomniacslk/dhcp => github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 - require ( github.com/cloudflare/ipvs v0.8.0 github.com/davecgh/go-spew v1.1.1 github.com/florianl/go-conntrack v0.4.0 github.com/golang/protobuf v1.5.2 - github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd + github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.0 @@ -23,7 +21,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/sys v0.6.0 + golang.org/x/sys v0.10.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde k8s.io/api v0.26.2 k8s.io/apimachinery v0.26.2 @@ -58,19 +56,17 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/josharian/native v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc // indirect - github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect github.com/mdlayher/genetlink v1.2.0 // indirect - github.com/mdlayher/netlink v1.6.2 // indirect - github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b // indirect - github.com/mdlayher/socket v0.2.3 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/packet v1.1.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -78,6 +74,7 @@ require ( github.com/nxadm/tail v1.4.8 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect @@ -88,14 +85,14 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.14.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect - github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/crypto v0.1.0 // indirect - golang.org/x/net v0.8.0 // indirect + github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.12.0 // indirect golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index ccf72000..5926fdf9 100644 --- a/go.sum +++ b/go.sum @@ -95,7 +95,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= @@ -206,16 +205,12 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3 h1:StGYqyAyFXHsJAZgFD4xLzfCrLOaHd86ZhX/5pZY/4I= -github.com/harvester/dhcp v0.0.0-20220421024905-28b38eafefe3/go.mod h1:DwyLjKGwSxRt84j0FEB58tAFgjuEDEu20dyJG2canEI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -223,18 +218,21 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd h1:D772X7igTag7yKErVWAR7boXpOml3fqqBzH1wNaD/jk= +github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= @@ -248,7 +246,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= @@ -279,11 +276,6 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc h1:m7rJJJeXrYCFpsxXYapkDW53wJCDmf9bsIXUg0HoeQY= -github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ6yv+WafaKzY37MFZ58TdfIhQ+8nQbiis= -github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= @@ -303,19 +295,16 @@ github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGk github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= -github.com/mdlayher/netlink v1.6.2 h1:D2zGSkvYsJ6NreeED3JiVTu1lj2sIYATqSaZlhPzUgQ= -github.com/mdlayher/netlink v1.6.2/go.mod h1:O1HXX2sIWSMJ3Qn1BYZk1yZM+7iMki/uYGGiwGyq/iU= -github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= -github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= +github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= -github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -353,6 +342,9 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -394,8 +386,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= @@ -426,15 +416,13 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= +github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -455,8 +443,8 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -499,9 +487,7 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -543,9 +529,8 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -570,9 +555,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -581,13 +565,10 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -619,7 +600,6 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -647,16 +627,15 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -665,8 +644,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -678,7 +657,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 8e19f7be..fe3855c4 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -185,8 +185,7 @@ func (i *Instance) startDHCP() (chan string, error) { client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP, func(lease *nclient4.Lease) { ipChan <- lease.ACK.YourIPAddr.String() - - log.Infof("DHCP VIP [%s] for [%s/%s] ", i.vipConfig.VIP, i.serviceSnapshot.Namespace, i.serviceSnapshot.Name) + log.Infof("DHCP VIP [%s] for [%s/%s] ", lease.ACK.YourIPAddr.String(), i.serviceSnapshot.Namespace, i.serviceSnapshot.Name) }) go client.Start() diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 02f05b89..2e397dee 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -43,11 +43,11 @@ func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.Wai if sm.serviceInstances[x].UID == newServiceUID { log.Debugf("isDHCP: %t, newServiceAddress: %s", sm.serviceInstances[x].isDHCP, newServiceAddress) // 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" || - !sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0" || - !sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && - newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP || - len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc) { + if (sm.serviceInstances[x].isDHCP && newServiceAddress != "0.0.0.0") || + (!sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0") || + (!sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && + newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP) || + (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) { if err := sm.deleteService(newServiceUID); err != nil { return err } diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index cb90101b..88f52a34 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -15,6 +15,7 @@ import ( ) const dhcpClientPort = "68" +const defaultDHCPRenew = time.Hour // Callback is a function called on certain events type Callback func(*nclient4.Lease) @@ -117,15 +118,7 @@ func (c *DHCPClient) Start() { Max: 1 * time.Minute, } for { - var lease *nclient4.Lease - var err error - if c.initRebootFlag { - // DHCP State-transition: INIT-REBOOT --> BOUND - lease, err = c.initReboot() - } else { - // DHCP State-transition: INIT --> BOUND - lease, err = c.request() - } + lease, err := c.request(c.initRebootFlag) if err != nil { dur := backoff.Duration() log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur) @@ -139,15 +132,15 @@ func (c *DHCPClient) Start() { c.onBound(lease) // Set up two ticker to renew/rebind regularly - t1Timeout := c.lease.ACK.IPAddressLeaseTime(0) / 2 - t2Timeout := c.lease.ACK.IPAddressLeaseTime(0) / 8 * 7 + t1Timeout := c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 2 + t2Timeout := (c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 8) * 7 t1, t2 := time.NewTicker(t1Timeout), time.NewTicker(t2Timeout) for { select { case <-t1.C: - // renew + // renew is a unicast request of the IP renewal lease, err := c.renew() if err == nil { c.lease = lease @@ -157,8 +150,10 @@ func (c *DHCPClient) Start() { log.Errorf("renew failed, error: %s", err.Error()) } case <-t2.C: - // rebind - lease, err := c.rebind() + // rebind is just like a request, but forcing to provide a new IP address + // TODO: If err on Request or Renew is NAK, we should make a new request + // and get a New IP address + lease, err := c.request(true) if err == nil { c.lease = lease log.Infof("rebind, lease: %+v", lease) @@ -167,10 +162,10 @@ func (c *DHCPClient) Start() { log.Errorf("rebind failed, error: %s", err.Error()) t1.Stop() t2.Stop() - break + return } case <-c.stopChan: - // release + // 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) } else { @@ -186,35 +181,6 @@ func (c *DHCPClient) Start() { } } -func (c *DHCPClient) request() (*nclient4.Lease, error) { - broadcast, err := nclient4.New(c.iface.Name) - if err != nil { - return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %w", c.iface.Name, err) - } - - defer broadcast.Close() - - if c.ddnsHostName != "" { - return broadcast.Request(context.TODO(), - dhcpv4.WithOption(dhcpv4.OptHostName(c.ddnsHostName)), - dhcpv4.WithOption(dhcpv4.OptClientIdentifier([]byte(c.ddnsHostName)))) - } - - return broadcast.Request(context.TODO()) -} - -func (c *DHCPClient) release() error { - unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(c.iface.Name, &net.UDPAddr{IP: c.lease.ACK.YourIPAddr, Port: nclient4.ClientPort}), - nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) - if err != nil { - return fmt.Errorf("create unicast client failed, error: %w, iface: %s, server ip: %v", err, c.iface.Name, c.lease.ACK.ServerIPAddr) - } - defer unicast.Close() - - // TODO modify lease - return unicast.Release(c.lease) -} - // -------------------------------------------------------- // | |INIT-REBOOT | RENEWING |REBINDING | // -------------------------------------------------------- @@ -223,76 +189,48 @@ func (c *DHCPClient) release() error { // |requested-ip |MUST | MUST NOT |MUST NOT | // |ciaddr |zero | IP address |IP address| // -------------------------------------------------------- -func (c *DHCPClient) initReboot() (*nclient4.Lease, error) { - broadcast, err := nclient4.New(c.iface.Name) - if err != nil { - return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %w", c.iface.Name, err) - } - defer broadcast.Close() - message, err := dhcpv4.New( - dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), - dhcpv4.WithHwAddr(c.iface.HardwareAddr), - dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.requestedIP))) + +func (c *DHCPClient) request(rebind bool) (*nclient4.Lease, error) { + dhclient, err := nclient4.New(c.iface.Name) if err != nil { - return nil, fmt.Errorf("new dhcp message failed, error: %w", err) + return nil, fmt.Errorf("create a client for iface %s failed, error: %w", c.iface.Name, err) } - return sendMessage(broadcast, message) -} + defer dhclient.Close() -func (c *DHCPClient) renew() (*nclient4.Lease, error) { - unicast, err := nclient4.New(c.iface.Name, nclient4.WithUnicast(c.iface.Name, &net.UDPAddr{IP: c.lease.ACK.YourIPAddr, Port: nclient4.ClientPort}), - nclient4.WithServerAddr(&net.UDPAddr{IP: c.lease.ACK.ServerIPAddr, Port: nclient4.ServerPort})) - if err != nil { - return nil, fmt.Errorf("create unicast client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) + modifiers := make([]dhcpv4.Modifier, 0) + + if c.ddnsHostName != "" { + modifiers = append(modifiers, + dhcpv4.WithOption(dhcpv4.OptHostName(c.ddnsHostName)), + dhcpv4.WithOption(dhcpv4.OptClientIdentifier([]byte(c.ddnsHostName))), + ) } - defer unicast.Close() - message, err := dhcpv4.New( - dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), - dhcpv4.WithHwAddr(c.iface.HardwareAddr), - dhcpv4.WithClientIP(c.lease.ACK.ClientIPAddr)) - if err != nil { - return nil, fmt.Errorf("new dhcp message failed, error: %w", err) + if rebind { + modifiers = append(modifiers, dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.requestedIP))) } - return sendMessage(unicast, message) + return dhclient.Request(context.TODO(), modifiers...) } -func (c *DHCPClient) rebind() (*nclient4.Lease, error) { - broadcast, err := nclient4.New(c.iface.Name) - if err != nil { - return nil, fmt.Errorf("create a broadcast client for iface %s failed, error: %s", c.iface.Name, err) - } - defer broadcast.Close() - message, err := dhcpv4.New( - dhcpv4.WithMessageType(dhcpv4.MessageTypeRequest), - dhcpv4.WithHwAddr(c.iface.HardwareAddr), - dhcpv4.WithClientIP(c.lease.ACK.ClientIPAddr)) +func (c *DHCPClient) release() error { + dhclient, err := nclient4.New(c.iface.Name) if err != nil { - return nil, fmt.Errorf("new dhcp message failed, error: %w", err) + return fmt.Errorf("create release client failed, error: %w, iface: %s, server ip: %v", err, c.iface.Name, c.lease.ACK.ServerIPAddr) } + defer dhclient.Close() - return sendMessage(broadcast, message) + // TODO modify lease + return dhclient.Release(c.lease) } -func sendMessage(client *nclient4.Client, message *dhcpv4.DHCPv4) (*nclient4.Lease, error) { - response, err := client.SendAndRead(context.TODO(), client.RemoteAddr(), message, - nclient4.IsMessageType(dhcpv4.MessageTypeAck, dhcpv4.MessageTypeNak)) +func (c *DHCPClient) renew() (*nclient4.Lease, error) { + dhclient, err := nclient4.New(c.iface.Name) if err != nil { - return nil, fmt.Errorf("got an error while processing the request: %w", err) - } - if response.MessageType() == dhcpv4.MessageTypeNak { - return nil, &nclient4.ErrNak{ - Offer: message, - Nak: response, - } + return nil, fmt.Errorf("create renew client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) } + defer dhclient.Close() - lease := &nclient4.Lease{} - lease.ACK = response - lease.Offer = message - lease.CreationTime = time.Now() - - return lease, nil + return dhclient.Renew(context.TODO(), c.lease) } From 702a27bb1ee142fe70e94cf2a550d4b005447ca7 Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Sat, 22 Jul 2023 00:07:56 +0000 Subject: [PATCH 396/542] Add proper backoff and max errors on dhcp client Signed-off-by: Ricardo Katz --- pkg/manager/instance.go | 34 +++----- pkg/manager/services.go | 18 +++- pkg/vip/ddns.go | 12 +-- pkg/vip/dhcp.go | 188 +++++++++++++++++++++++++--------------- 4 files changed, 154 insertions(+), 98 deletions(-) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index fe3855c4..aee164fe 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -5,7 +5,6 @@ import ( "net" "time" - "github.com/insomniacslk/dhcp/dhcpv4/nclient4" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" @@ -99,15 +98,15 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { // If this was purposely created with the address 0.0.0.0, // we will create a macvlan on the main interface and a DHCP client if instanceAddress == "0.0.0.0" { - ipChan, err := instance.startDHCP() + err := instance.startDHCP() if err != nil { return nil, err } select { - case <-time.After(dhcpTimeout): - return nil, fmt.Errorf("timeout to request the IP from DHCP server for service %s/%s", - instance.serviceSnapshot.Namespace, instance.serviceSnapshot.Name) - case ip := <-ipChan: + case err := <-instance.dhcpClient.ErrorChannel(): + return nil, fmt.Errorf("error starting DHCP for %s/%s: error: %s", + instance.serviceSnapshot.Namespace, instance.serviceSnapshot.Name, err) + case ip := <-instance.dhcpClient.IPChannel(): instance.vipConfig.VIP = ip instance.dhcpInterfaceIP = ip } @@ -124,10 +123,10 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { return instance, nil } -func (i *Instance) startDHCP() (chan string, error) { +func (i *Instance) startDHCP() error { parent, err := netlink.LinkByName(i.vipConfig.Interface) if err != nil { - return nil, fmt.Errorf("error finding VIP Interface, for building DHCP Link : %v", err) + return fmt.Errorf("error finding VIP Interface, for building DHCP Link : %v", err) } // Generate name from UID @@ -140,11 +139,11 @@ func (i *Instance) startDHCP() (chan string, error) { hwaddr, err := net.ParseMAC(i.dhcpInterfaceHwaddr) if i.dhcpInterfaceHwaddr != "" && err != nil { - return nil, err + return err } else if hwaddr == nil { hwaddr, err = net.ParseMAC(vip.GenerateMac()) if err != nil { - return nil, err + return err } } @@ -160,17 +159,17 @@ func (i *Instance) startDHCP() (chan string, error) { err = netlink.LinkAdd(mac) if err != nil { - return nil, fmt.Errorf("could not add %s: %v", interfaceName, err) + return fmt.Errorf("could not add %s: %v", interfaceName, err) } err = netlink.LinkSetUp(mac) if err != nil { - return nil, fmt.Errorf("could not bring up interface [%s] : %v", interfaceName, err) + return fmt.Errorf("could not bring up interface [%s] : %v", interfaceName, err) } iface, err = net.InterfaceByName(interfaceName) if err != nil { - return nil, fmt.Errorf("error finding new DHCP interface by name [%v]", err) + return fmt.Errorf("error finding new DHCP interface by name [%v]", err) } } else { log.Infof("Using existing macvlan interface for DHCP [%s]", interfaceName) @@ -181,12 +180,7 @@ func (i *Instance) startDHCP() (chan string, error) { initRebootFlag = true } - ipChan := make(chan string) - - client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP, func(lease *nclient4.Lease) { - ipChan <- lease.ACK.YourIPAddr.String() - log.Infof("DHCP VIP [%s] for [%s/%s] ", lease.ACK.YourIPAddr.String(), i.serviceSnapshot.Namespace, i.serviceSnapshot.Name) - }) + client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP) go client.Start() @@ -198,5 +192,5 @@ func (i *Instance) startDHCP() (chan string, error) { // Add the client so that we can call it to stop function i.dhcpClient = client - return ipChan, nil + return nil } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 2e397dee..f3708609 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -47,7 +47,9 @@ func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.Wai (!sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0") || (!sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP) || - (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) { + (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) || + (sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && + sm.serviceInstances[x].dhcpInterfaceIP != svc.Status.LoadBalancer.Ingress[0].IP) { if err := sm.deleteService(newServiceUID); err != nil { return err } @@ -94,6 +96,20 @@ func (sm *Manager) addService(svc *v1.Service) error { sm.upnpMap(newService) + if newService.isDHCP { + go func() { + for ip := range newService.dhcpClient.IPChannel() { + log.Debugf("IP %s may have changed", ip) + newService.vipConfig.VIP = ip + newService.dhcpInterfaceIP = ip + if err := sm.updateStatus(newService); err != nil { + log.Warnf("error updating svc: %s", err) + } + } + log.Debugf("IP update channel closed, stopping") + }() + } + sm.serviceInstances = append(sm.serviceInstances, newService) if err := sm.updateStatus(newService); err != nil { diff --git a/pkg/vip/ddns.go b/pkg/vip/ddns.go index 0595a92b..7ff9f701 100644 --- a/pkg/vip/ddns.go +++ b/pkg/vip/ddns.go @@ -5,7 +5,6 @@ import ( "net" "time" - "github.com/insomniacslk/dhcp/dhcpv4/nclient4" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) @@ -39,12 +38,7 @@ func (ddns *ddnsManager) Start() (string, error) { return "", err } - // channel to wait for IP - ipCh := make(chan string) - - client := NewDHCPClient(iface, false, "", func(lease *nclient4.Lease) { - ipCh <- lease.ACK.YourIPAddr.String() - }) + client := NewDHCPClient(iface, false, "") client.WithHostName(ddns.network.DDNSHostName()) @@ -60,7 +54,7 @@ func (ddns *ddnsManager) Start() (string, error) { case <-timeout: client.Stop() return "", errors.New("failed to get IP from dhcp for ddns in 1 minutes") - case ip = <-ipCh: + case ip = <-client.IPChannel(): log.Info("got ip from dhcp: ", ip) } @@ -79,7 +73,7 @@ func (ddns *ddnsManager) Start() (string, error) { log.Info("stop dhclient for ddns") client.Stop() return - case ip := <-ipCh: + case ip := <-client.IPChannel(): log.Info("got ip from dhcp: ", ip) } } diff --git a/pkg/vip/dhcp.go b/pkg/vip/dhcp.go index 88f52a34..78703683 100644 --- a/pkg/vip/dhcp.go +++ b/pkg/vip/dhcp.go @@ -16,9 +16,7 @@ import ( const dhcpClientPort = "68" const defaultDHCPRenew = time.Hour - -// Callback is a function called on certain events -type Callback func(*nclient4.Lease) +const maxBackoffAttempts = 3 // DHCPClient is responsible for maintaining ipv4 lease for one specified interface type DHCPClient struct { @@ -29,18 +27,20 @@ type DHCPClient struct { requestedIP net.IP stopChan chan struct{} // used as a signal to release the IP and stop the dhcp client daemon releasedChan chan struct{} // indicate that the IP has been released - onBound Callback + errorChan chan error // indicates there was an error on the IP request + ipChan chan string } // NewDHCPClient returns a new DHCP Client. -func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string, onBound Callback) *DHCPClient { +func NewDHCPClient(iface *net.Interface, initRebootFlag bool, requestedIP string) *DHCPClient { return &DHCPClient{ iface: iface, stopChan: make(chan struct{}), releasedChan: make(chan struct{}), + errorChan: make(chan error), initRebootFlag: initRebootFlag, requestedIP: net.ParseIP(requestedIP), - onBound: onBound, + ipChan: make(chan string), } } @@ -51,11 +51,21 @@ func (c *DHCPClient) WithHostName(hostname string) *DHCPClient { // Stop state-transition process and close dhcp client func (c *DHCPClient) Stop() { + close(c.ipChan) close(c.stopChan) - <-c.releasedChan } +// Gets the IPChannel for consumption +func (c *DHCPClient) IPChannel() chan string { + return c.ipChan +} + +// Gets the ErrorChannel for consumption +func (c *DHCPClient) ErrorChannel() chan error { + return c.errorChan +} + // Start state-transition process of dhcp client // // -------- ------- @@ -111,72 +121,65 @@ func (c *DHCPClient) Stop() { // ---------- // Figure: State-transition diagram for DHCP clients func (c *DHCPClient) Start() { - backoff := backoff.Backoff{ - Factor: 2, - Jitter: true, - Min: 10 * time.Second, - Max: 1 * time.Minute, - } - for { - lease, err := c.request(c.initRebootFlag) - if err != nil { - dur := backoff.Duration() - log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur) - time.Sleep(dur) - continue - } - backoff.Reset() + lease := c.requestWithBackoff() - c.initRebootFlag = false - c.lease = lease - c.onBound(lease) - - // Set up two ticker to renew/rebind regularly - t1Timeout := c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 2 - t2Timeout := (c.lease.ACK.IPAddressLeaseTime(defaultDHCPRenew) / 8) * 7 - - t1, t2 := time.NewTicker(t1Timeout), time.NewTicker(t2Timeout) - - for { - select { - case <-t1.C: - // renew is a unicast request of the IP renewal - lease, err := c.renew() - if err == nil { - c.lease = lease - log.Infof("renew, lease: %+v", lease) - t2.Reset(t2Timeout) - } else { - log.Errorf("renew failed, error: %s", err.Error()) - } - case <-t2.C: - // rebind is just like a request, but forcing to provide a new IP address - // TODO: If err on Request or Renew is NAK, we should make a new request - // and get a New IP address - lease, err := c.request(true) - if err == nil { - c.lease = lease - log.Infof("rebind, lease: %+v", lease) - t1.Reset(t1Timeout) - } else { - log.Errorf("rebind failed, error: %s", err.Error()) + c.initRebootFlag = false + c.lease = lease + + // 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) + t1, t2 := time.NewTicker(t1Timeout), time.NewTicker(t2Timeout) + + for { + select { + case <-t1.C: + // renew is a unicast request of the IP renewal + // A point on renew is: the library does not return the right message (NAK) + // on renew error due to IP Change, but instead it returns a different error + // This way there's not much to do other than log and continue, as the renew error + // may be an offline server, or may be an incorrect package match + lease, err := c.renew() + if err == nil { + c.lease = lease + log.Infof("renew, lease: %+v", lease) + t2.Reset(t2Timeout) + } else { + log.Errorf("renew failed, error: %s", err.Error()) + } + 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) + } else { + if _, ok := err.(*nclient4.ErrNak); !ok { t1.Stop() t2.Stop() + log.Errorf("rebind failed, error: %s", err.Error()) return } - 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) - } else { - log.Infof("release, lease: %+v", c.lease) - } - t1.Stop() - t2.Stop() + log.Warnf("ip %s may have changed: %s", c.lease.ACK.YourIPAddr, err.Error()) + c.initRebootFlag = false + c.lease = c.requestWithBackoff() + } + t1.Reset(t1Timeout) + t2.Reset(t2Timeout) - close(c.releasedChan) - return + 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) + } else { + log.Infof("release, lease: %+v", c.lease) } + t1.Stop() + t2.Stop() + + close(c.releasedChan) + return } } } @@ -190,6 +193,45 @@ func (c *DHCPClient) Start() { // |ciaddr |zero | IP address |IP address| // -------------------------------------------------------- +func (c *DHCPClient) requestWithBackoff() *nclient4.Lease { + backoff := backoff.Backoff{ + Factor: 2, + Jitter: true, + Min: 10 * time.Second, + Max: 1 * time.Minute, + } + + var lease *nclient4.Lease + var err error + + for { + log.Debugf("trying to get a new IP, attempt %f", 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) + c.errorChan <- errMsg + c.Stop() + return nil + } + log.Errorf("request failed, error: %s (waiting %v)", err.Error(), dur) + time.Sleep(dur) + continue + } + backoff.Reset() + break + } + + if c.ipChan != nil { + log.Debugf("using channel") + c.ipChan <- lease.ACK.YourIPAddr.String() + } + + return lease +} + func (c *DHCPClient) request(rebind bool) (*nclient4.Lease, error) { dhclient, err := nclient4.New(c.iface.Name) if err != nil { @@ -207,10 +249,18 @@ func (c *DHCPClient) request(rebind bool) (*nclient4.Lease, error) { ) } - if rebind { + // 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) 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) + modifiers = append(modifiers, dhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(c.lease.ACK.YourIPAddr))) + } + return dhclient.Request(context.TODO(), modifiers...) } @@ -226,7 +276,9 @@ func (c *DHCPClient) release() error { } func (c *DHCPClient) renew() (*nclient4.Lease, error) { - dhclient, err := nclient4.New(c.iface.Name) + // renew needs a unicast client. This is due to some servers (like dnsmasq) require the exact request coming from the vip interface + dhclient, err := nclient4.New(c.iface.Name, + nclient4.WithUnicast(&net.UDPAddr{IP: c.lease.ACK.YourIPAddr, Port: nclient4.ClientPort})) if err != nil { return nil, fmt.Errorf("create renew client failed, error: %w, server ip: %v", err, c.lease.ACK.ServerIPAddr) } From 3d357a452bd9b2e9dfbc131055acf90042a469c1 Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Thu, 27 Jul 2023 16:41:41 -0300 Subject: [PATCH 397/542] Fix linter error Signed-off-by: Ricardo Katz --- pkg/manager/instance.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index aee164fe..1fa96e17 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -3,7 +3,6 @@ package manager import ( "fmt" "net" - "time" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" @@ -14,8 +13,6 @@ import ( "github.com/kube-vip/kube-vip/pkg/vip" ) -const dhcpTimeout = 10 * time.Second - // Instance defines an instance of everything needed to manage a vip type Instance struct { // Virtual IP / Load Balancer configuration From f36b433093436bb499d06777b05180f7c295586a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Wed, 31 May 2023 15:56:43 +0200 Subject: [PATCH 398/542] Update go dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 6 +- .github/workflows/release.yaml | 14 +- Dockerfile | 2 +- demo/server/main.go | 2 +- go.mod | 82 +++++----- go.sum | 265 ++++++++++++--------------------- testing/e2e/e2e/Dockerfile | 2 +- 7 files changed, 148 insertions(+), 225 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b58cb546..2734d38a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,11 +11,11 @@ jobs: - name: Init run: sudo apt-get update && sudo apt-get install -y build-essential golint - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v4 with: - go-version: '1.19' + go-version: '1.20' - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.50.1 - name: checks diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 10b01349..f0b16ccf 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,25 +11,25 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Github Packages - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push main branch id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x @@ -41,7 +41,7 @@ jobs: ghcr.io/kube-vip/kube-vip:latest - name: Build iptables version and push main branch id: docker_build_iptables - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . file: Dockerfile_iptables diff --git a/Dockerfile b/Dockerfile index e2567d6d..b3d8649b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.19.2-alpine3.16 as dev +FROM golang:1.20.6-alpine3.17 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/demo/server/main.go b/demo/server/main.go index 9d2ecec3..89c2928d 100644 --- a/demo/server/main.go +++ b/demo/server/main.go @@ -60,7 +60,7 @@ func main() { fmt.Println("error: ", err) } - ServerConn.WriteTo(buf[0:n], ) + ServerConn.WriteTo(buf[0:n]) } } } diff --git a/go.mod b/go.mod index f53295a2..147d44cf 100644 --- a/go.mod +++ b/go.mod @@ -1,33 +1,33 @@ module github.com/kube-vip/kube-vip -go 1.18 +go 1.19 require ( - github.com/cloudflare/ipvs v0.8.0 + github.com/cloudflare/ipvs v0.9.1 github.com/davecgh/go-spew v1.1.1 github.com/florianl/go-conntrack v0.4.0 - github.com/golang/protobuf v1.5.2 - github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd + github.com/golang/protobuf v1.5.3 + github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 - github.com/mdlayher/ndp v1.0.0 + github.com/mdlayher/ndp v1.0.1 github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.27.2 - github.com/osrg/gobgp/v3 v3.12.0 - github.com/packethost/packngo v0.29.0 + github.com/onsi/gomega v1.27.10 + github.com/osrg/gobgp/v3 v3.17.0 + github.com/packethost/packngo v0.30.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.14.0 - github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.2 + github.com/prometheus/client_golang v1.16.0 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 golang.org/x/sys v0.10.0 - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde - k8s.io/api v0.26.2 - k8s.io/apimachinery v0.26.2 - k8s.io/client-go v0.26.2 - k8s.io/klog/v2 v2.80.1 - sigs.k8s.io/kind v0.17.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 + k8s.io/api v0.27.4 + k8s.io/apimachinery v0.27.4 + k8s.io/client-go v0.27.4 + k8s.io/klog/v2 v2.100.1 + sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.3.0 ) @@ -42,10 +42,10 @@ require ( github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -54,16 +54,16 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/josharian/native v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k-sone/critbitgo v1.4.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mdlayher/genetlink v1.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/packet v1.1.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect @@ -73,39 +73,39 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/spf13/afero v1.9.2 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.14.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/spf13/viper v1.15.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect golang.org/x/crypto v0.11.0 // indirect golang.org/x/net v0.12.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect + golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect - golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect - golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect + golang.org/x/time v0.1.0 // indirect + golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect - k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 5926fdf9..1f27c9e2 100644 --- a/go.sum +++ b/go.sum @@ -42,20 +42,11 @@ github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -64,8 +55,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/ipvs v0.8.0 h1:2cl7WMwQI6pklBcwrzdusAqHuPThu/VBdAFNl5r/D5w= -github.com/cloudflare/ipvs v0.8.0/go.mod h1:rL2uv7wRPwNsyRig+6EJybJVLVIuw7+L6dc8DPyn+84= +github.com/cloudflare/ipvs v0.9.1 h1:4azDqbWqNAkcuD78yK9y9rxZoQfW2OnC9DFo+y7HPgk= +github.com/cloudflare/ipvs v0.9.1/go.mod h1:5H4icNJZ8T4H7bg0/THRew5BbNOkDgl2RC1twjeSOHU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -77,8 +68,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= @@ -106,30 +97,18 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -159,8 +138,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= @@ -176,7 +156,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -195,7 +174,7 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= @@ -216,15 +195,14 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd h1:D772X7igTag7yKErVWAR7boXpOml3fqqBzH1wNaD/jk= -github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -239,25 +217,17 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXp github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -266,23 +236,21 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU= -github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ= -github.com/mdlayher/ndp v1.0.0 h1:rcFaJVj04Rj47ZlV/t3iZcuKzlpwBuBsD3gR9AHDzcI= -github.com/mdlayher/ndp v1.0.0/go.mod h1:+3vkk6YnlL8ZTRTjmQanCNQFqDKOpP2zNyHl2HqyoZs= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= +github.com/mdlayher/ndp v1.0.1 h1:+yAD79/BWyFlvAoeG5ncPS0ItlHP/eVbH7bQ6/+LVA4= +github.com/mdlayher/ndp v1.0.1/go.mod h1:rf3wKaWhAYJEXFKpgF8kQ2AxypxVbfNcZbqoAo6fVzk= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -294,7 +262,6 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= -github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= @@ -302,7 +269,6 @@ github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= @@ -311,15 +277,11 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -328,94 +290,73 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.8.4 h1:gf5mIQ8cLFieruNLAdgijHF1PYfLphKm2dxxcUtcqK0= +github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY= -github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI= -github.com/osrg/gobgp/v3 v3.12.0 h1:coxnxOntqE1tKMM3a4ftBGe5ft/I5rklxlezISpBXx4= -github.com/osrg/gobgp/v3 v3.12.0/go.mod h1:rAPmqyijW79JIOkGu0BpLUCNdY769l7H+TlOKi5/5KY= -github.com/packethost/packngo v0.29.0 h1:gRIhciVZQ/zLNrIdIdbOUyB/Tw5IgoaXyhP4bvE+D2s= -github.com/packethost/packngo v0.29.0/go.mod h1:/UHguFdPs6Lf6FOkkSEPnRY5tgS0fsVM+Zv/bvBrmt0= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= +github.com/osrg/gobgp/v3 v3.17.0/go.mod h1:tSUXn/s9uggSRTKP3IBeT5zI4ayOUX3O7fG5+n+SHPc= +github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= +github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= -github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= @@ -434,7 +375,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -442,7 +382,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -483,7 +423,6 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -491,7 +430,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -525,10 +463,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -540,10 +477,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -558,14 +493,11 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -579,7 +511,6 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -593,8 +524,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -616,7 +545,6 @@ golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -625,15 +553,12 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -649,8 +574,8 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -702,15 +627,15 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c h1:Okh6a1xpnJslG9Mn84pId1Mn+Q8cvpo4HCeeFWHo0cA= -golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c/go.mod h1:enML0deDxY1ux+B6ANGiwtg0yAJi1rctkTpcHNAVPyg= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde h1:ybF7AMzIUikL9x4LgwEmzhXtzRpKNqngme1VGDWz+Nk= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ= +golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= +golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -775,8 +700,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -807,15 +732,14 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -824,10 +748,8 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -836,6 +758,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -845,25 +768,25 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= -k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= -k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= -k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= -k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= -k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= +k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= +k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= +k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= +k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= +k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kind v0.17.0 h1:CScmGz/wX66puA06Gj8OZb76Wmk7JIjgWf5JDvY7msM= -sigs.k8s.io/kind v0.17.0/go.mod h1:Qqp8AiwOlMZmJWs37Hgs31xcbiYXjtXlRBSftcnZXQk= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= +sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/testing/e2e/e2e/Dockerfile b/testing/e2e/e2e/Dockerfile index 410ddd7a..74db1526 100644 --- a/testing/e2e/e2e/Dockerfile +++ b/testing/e2e/e2e/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.19-alpine as dev +FROM golang:1.20-alpine as dev RUN apk add --no-cache git ca-certificates RUN adduser -D appuser COPY . /src/ From 7b64893703b80dc9e6006038bf3a9204c404fd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Thu, 27 Jul 2023 17:35:26 +0200 Subject: [PATCH 399/542] Update golangci-lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2734d38a..2c673e0d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,7 @@ jobs: with: go-version: '1.20' - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.50.1 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - name: checks run: make check - name: test docker build From 9bfbb295ddc5013dc585a344819bc5eb1c334ac8 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 13:09:41 +0000 Subject: [PATCH 400/542] Fixes to e2e tests and re-enabling Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 2 - testing/e2e/services/kind.go | 5 +-- testing/e2e/services/services.go | 63 +++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2c673e0d..959f1976 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,8 +23,6 @@ jobs: - name: test docker build run: make dockerx86Action - name: e2e controlplane - if: ${{ github.event.label.name == 'control plane' }} run: DOCKERTAG=action make e2e-tests - name: e2e services - if: contains(github.event.pull_request.labels.*.name, 'services') run: DOCKERTAG=action make service-tests diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index f7ae5f97..e9e2e1c8 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -1,7 +1,6 @@ package main import ( - "os" "os/exec" "time" @@ -14,7 +13,7 @@ import ( var provider *cluster.Provider -func createKind() error { +func createKind(imagePath string) error { clusterConfig := kindconfigv1alpha4.Cluster{ Networking: kindconfigv1alpha4.Networking{ IPFamily: kindconfigv1alpha4.IPv4Family, @@ -35,8 +34,6 @@ func createKind() error { }, } - imagePath := os.Getenv("E2E_IMAGE_PATH") - provider = cluster.NewProvider(cluster.ProviderWithLogger(cmd.NewLogger()), cluster.ProviderWithDocker()) clusters, err := provider.List() if err != nil { diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 0a35d6e0..8db2c915 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -29,7 +29,8 @@ import ( func main() { log.Info("🔬 beginning e2e tests") - // return + var testCount int + imagePath := os.Getenv("E2E_IMAGE_PATH") _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") _, ignoreDeployments := os.LookupEnv("IGNORE_DEPLOY") @@ -38,7 +39,7 @@ func main() { _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") _, ignoreEgress := os.LookupEnv("IGNORE_EGRESS") _, retainCluster := os.LookupEnv("RETAIN_CLUSTER") - err := createKind() + err := createKind(imagePath) if !retainCluster { if err != nil { @@ -91,20 +92,21 @@ func main() { log.Fatal(err) } svc := service{ - name: s, + name: s, + testHTTP: true, } _, _, err = svc.createService(ctx, clientset) if err != nil { log.Error(err) + } else { + testCount++ } - log.Warnf("🧹 deleting Service [%s]", s) + log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } - - log.Warnf("🧹 deleting Deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) @@ -128,21 +130,24 @@ func main() { } for i := 1; i < 5; i++ { svc := service{ - name: fmt.Sprintf("%s-%d", s, i), + name: fmt.Sprintf("%s-%d", s, i), + testHTTP: true, } _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) + } else { + testCount++ } } for i := 1; i < 5; i++ { - log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) + log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } } - log.Warnf("🧹 deleting deployment [%s]", d) + log.Infof("🧹 deleting deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, l, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) @@ -166,6 +171,7 @@ func main() { name: s, egress: false, policyLocal: true, + testHTTP: true, } leader, _, err := svc.createService(ctx, clientset) if err != nil { @@ -175,15 +181,16 @@ func main() { err = leaderFailover(ctx, &s, &leader, clientset) if err != nil { log.Error(err) + } else { + testCount++ } - log.Warnf("🧹 deleting Service [%s]", s) + log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } - log.Warnf("🧹 deleting Deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) @@ -206,6 +213,7 @@ func main() { svc := service{ name: s, policyLocal: true, + testHTTP: true, } leader, _, err := svc.createService(ctx, clientset) if err != nil { @@ -215,15 +223,15 @@ func main() { err = podFailover(ctx, &s, &leader, clientset) if err != nil { log.Error(err) + } else { + testCount++ } - log.Warnf("🧹 deleting Service [%s]", s) + log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } - - log.Warnf("🧹 deleting Deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) @@ -246,20 +254,23 @@ func main() { svc := service{ policyLocal: true, name: fmt.Sprintf("%s-%d", s, i), + testHTTP: true, } _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) + } else { + testCount++ } } for i := 1; i < 5; i++ { - log.Warnf("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) + log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, fmt.Sprintf("%s-%d", s, i), metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } } - log.Warnf("🧹 deleting deployment [%s]", d) + log.Infof("🧹 deleting deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, l, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) @@ -271,6 +282,7 @@ func main() { log.Infof("🧪 ---> egress IP re-write (local policy) <---") var egress string var found bool + // Set up a local listener go func() { found = tcpServer(&egress) }() @@ -281,22 +293,27 @@ func main() { replicas: 1, client: true, } + + // Find this machines IP address deploy.address = GetLocalIP() if deploy.address == "" { log.Fatalf("Unable to detect local IP address") } log.Infof("📠 found local address [%s]", deploy.address) + // Create a deployment that connects back to this machines IP address err = deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } + svc := service{ policyLocal: true, name: s, egress: true, + testHTTP: false, } - ldr, egress, err := svc.createService(ctx, clientset) + _, egress, err := svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } @@ -304,25 +321,25 @@ func main() { for i := 1; i < 5; i++ { if found { log.Infof("🕵️ egress has correct IP address") + testCount++ break } time.Sleep(time.Second * 1) } if !found { - log.Errorf("%s %s", ldr, egress) + log.Error("😱 No traffic found from loadbalancer address ") } - log.Warnf("🧹 deleting Service [%s]", s) + log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } - - log.Warnf("🧹 deleting deployment [%s]", d) err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) if err != nil { log.Fatal(err) } + log.Infof("🏆 Testing Complete [%d] passed", testCount) } } @@ -525,9 +542,11 @@ func tcpServer(egressAddress *string) bool { // log.Fatal(err) } remoteAddress, _, _ := net.SplitHostPort(conn.RemoteAddr().String()) - log.Infof("📞 incoming from [%s]", remoteAddress) if remoteAddress == *egressAddress { + log.Infof("📞 👍 incoming from egress Address [%s]", remoteAddress) return true + } else { + log.Infof("📞 👎 incoming from pod address [%s]", remoteAddress) } go handleRequest(conn) From 1da54e6d8e85dd307355dbf581be150437d0fab4 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 13:13:18 +0000 Subject: [PATCH 401/542] lint fixes. Signed-off-by: Dan Finneran --- testing/e2e/services/services.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 8db2c915..bc3babde 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -136,9 +136,8 @@ func main() { _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) - } else { - testCount++ } + testCount++ } for i := 1; i < 5; i++ { log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) @@ -259,9 +258,8 @@ func main() { _, _, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) - } else { - testCount++ } + testCount++ } for i := 1; i < 5; i++ { log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) @@ -545,10 +543,8 @@ func tcpServer(egressAddress *string) bool { if remoteAddress == *egressAddress { log.Infof("📞 👍 incoming from egress Address [%s]", remoteAddress) return true - } else { - log.Infof("📞 👎 incoming from pod address [%s]", remoteAddress) } - + log.Infof("📞 👎 incoming from pod address [%s]", remoteAddress) go handleRequest(conn) } } From c2215e5d985fa9fe74d9e7c0cb4ae635258d13c3 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 13:57:12 +0000 Subject: [PATCH 402/542] Fixes to ginko Signed-off-by: Dan Finneran --- go.mod | 4 ++++ go.sum | 6 ++++++ testing/e2e/e2e/e2e | Bin 4562944 -> 0 bytes testing/e2e/e2e_suite_test.go | 2 +- testing/e2e/e2e_test.go | 2 +- 5 files changed, 12 insertions(+), 2 deletions(-) delete mode 100755 testing/e2e/e2e/e2e diff --git a/go.mod b/go.mod index 147d44cf..69a16795 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 github.com/onsi/ginkgo v1.16.5 + github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.10 github.com/osrg/gobgp/v3 v3.17.0 github.com/packethost/packngo v0.30.0 @@ -46,10 +47,12 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -94,6 +97,7 @@ require ( golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.1.0 // indirect + golang.org/x/tools v0.9.3 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect diff --git a/go.sum b/go.sum index 1f27c9e2..862532dd 100644 --- a/go.sum +++ b/go.sum @@ -108,6 +108,7 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -175,6 +176,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= @@ -291,6 +293,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= @@ -348,6 +351,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -420,6 +424,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -628,6 +633,7 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/testing/e2e/e2e/e2e b/testing/e2e/e2e/e2e deleted file mode 100755 index 4cd6189dbdffaa4afbf70bffd6c1f445e8fd2594..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4562944 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 s)F@z=0pDP= zzc*HW*|c`4_9qVB*M}Ul{hcjJnKN3D1OBzL2rZ-+57-agDF#xr9qS_kYu3jXO>{d> zO=7sYWce~;j1LswGK;&1Ik?bzfW+(vdetHE+}}%=3vf?+frQLa+=Th`!l;a?>M|;wYuq*`p1wyKX6iiT*Z<($>F5v{_m@VSAB7!e4v+^d&tk-A7S@SjejuX zFJ0qKIGCSj!U)a&=H6Gr#^kS7_kVLwr8prDzDA!1s9@8B>Xo@b_JSQ~E~YnDjS&D! zn`X?-+KyZ8tgBd5fb=gEJtSBlsVJ&v!mbNw5uzHT5OoswhYljU6| z;@yatX34o8*Zraa#&l^`+5-8E`@W>8j+yrHiwU|BxWO-aQjTw019x6g25|02_u4Wz zJJ|h=*F-4;DPQyKvrfTu=Blr=e-qM!6Xs3se^x%fSU8hQX&m)r*I-|IslF_@q_1J% zUe0DnX@1xVKG9zNSeQkO1Zxgt#v-W*bdN|3oUNGx&Ziq~%8-?#N(5>9m9!ouS`UWA zwM*Nek8lI$sZibHudi}Kf19_Qla35^cW2AdRN)2D(7L%dI;qLffUW_2noKa^$dCy+P{8b(=fUjEg`hVL^qHOe-di4vOFu}nnrS<~Z`%0<%WnjUSxJyv7jc27Gqk4g zgN0mi_C9VK_ig^r{)t!7K1n0<+*iDKiAwh@!VugEp8JI8KaEefN&c2%Eq6HAH%H4( z!yX@Os--{o$F`w+X3~(kbgPAi+`fKwP;|ECMai(isdD%0UX5yxj|;!9@p>+anKPZ_dBfkjERPFvl4J;GE93x?EKB`QF*)0lcQcmKJVjSMW(OIc|+7A0`aba>BK6?DbA-TAmoPtdXvc${jVGr~dnI_J2-jcS9NZ zN3KxMBwX0&cfQx#f6#Ic)4k}A`2)HAQ^i`IQbTK82DazT%TTG9rAxVwUN>un^XfQP ze$i@dIyzGPy>@18%ytH(R41gb^8>MUpPq(K(vu^+;!JlqkNby-tUB`k*du&!!_@Gz z%`t?(!K->jQ-uZbU1T8qFdAyBn;98(Ad;$;y9^{4l(p?nt&OX z_}kpcxmc=MuGB2U??}qD${E!bglF<>9|?}%BRQ$mbojFSkzv3*XRW@dNJIpG zNJs3YqOEfNj$SYpQIme3Lvn124V!(!Q`NKF03(_Rcu@rQv)8-AdPaQ zucI6X1w*SBai?s*Rk7q<8bCDk@*Fo3dVDLt=e`OhMMu3HNj`jl8MgGhps-6%OAgyp zfs@<*j;!|G-1Y;#{Pu@+X}<&3c$@OeIH3=Nx9y>_;R*z=3>g>v>6&1?iB}w=JwBRJ zcC!DPb&M`p9u`ZMmBkXD<=W>j1ft1%^)?b;QxZ*>pV830vw71nu?GAtmvx#Q9@7?2 zqs24a7f8#@E{AmJIY(fd(cV6A;sT8E4wpL!Yp zS

    AfS32AuIo#XWf^Kxh2_+kxpeJskd;mIDW!KTJ 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�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¥RxgqMI#7MYwvHT-meT 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

  • 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 g^j6DTD=Q{_^>UCQ_O<@awZf5Lw&pN_c& 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

    7=Nm%LIA^rfbV}%E;zU;^m{V3aEeMB{`5qv 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� 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 z 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

    RoS^Ql;`X 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�v&KAK7R;~n8yNVRu~T591)oT}g)5~F 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ଘqTw0HfleDlLj zQvPQNAC6Ogb4EW~L&EPP{{1Dq$B#`P{GKb}3%x+)KhL}VZ~U!NZ3$n5=a2oo>#ttY zJ9kR>w`u+p{LwrAv3>h5lkkUV{13+&KOQ(-XQYHrrSUIty?6eHGZJP?_*wy7etB`m zzrBz56!AgIKiJYc|7n}9tSse!6^&ncaqzhdx}22o&4~YCEARZb9hq=c!spTWl@|wp z?`2)eOZef0&yCametvPzL2UM%68k^L?Zr~l?Yw8tmmD^vdA0p9KZ z)m5dRlJHB&{uhqZ{!UpVcT4!xsnma`cz^$cwKj?RPj~+Q?%w#~%^paW^6y9ZP)qOc zZ`XF;1PR}P+Fx!Q{;LcuoG9Uc9j(7Vcd9r4w?FuPISGF~jlcfd-u$=xq*ZAN|3B(~ zp*Zcw|HtI#C42_uAC80Hvf=87Bz$qOzl4kUtWb`({LgGZzm9~j4S0OQ$GyvMTiqK5 zOZYcfe=g%a{uMd=mnGqEcuwaZh=YH&`>W4M`17Q{g>Ln(zdL^VRGdH5r1hV`ZQl5C z58c*5%0HF*Z}5b7`Mvn#o)Qv1`5pcJ)*$cv7u4x~gM_co_}{(r-@dY@SpJy-oqs4! z`ERKmJS^qkiq?;EBP(_ztUR&?{r~kJ5yp;dV8#F$5x;Ng}sgo%GcfG3d!E3zn70*=={g2Af z{5>xYe&AK>DoOmGApfC2Pw)Ik|9;;=37`Ih=HEZV8y`HfP_+N||BAkUn>W5vcJ~A+ z|L3-AeBMcKe7US9mr3~5`zil+-uR7I|F%TJAE*5NA#eQ9JBv(_@JA{Czz}cw(dnzA zV*k72gyuhRqj&zx?pwc5%HRK~#^>($mjA&IlSKcEa&Hqp&i7Y(vh2-L{wt~dSc%^G z*T4N8(SPOD?{xmwQ19})`$8R2|NLn;m0z6v=bhOmu76*4K;!*M-sAU^U(^uw=e|__ z{srFkchj-QOG@R}a)-`89H;(w>>nhqKdUU0zCf2!5@Eao+v-t_0i=QZ10`_6UEvLmH5x5@zZ+IyZ&1(tFl7E zcVYWY2XFjSk4(;#@IyCh{zGxv@3NJ5iQ~_&&r$pN+xz<;uKbm_{xO&JuQc!e*S&GW zwG#iglK$i0=Z*jSP#;l$ok-tr!TIsd$Mhe$yHIb@esnXHe>hJ0wQ2T3Gl~BY&EKpf zZ~67%=8B(5_&X{8KpgySv!55+-$Kei9OwJfrd4}D%6|>v1Gjs(zYQDxqW{2EvvjHF zz3z=)Jo8yJ07m)$wg0s*Lv{YdQ$!mQu_;x^lm>l{;yS% zgkS%;&Oa2V{tkxU5XaAz)PJl4-tEU%^m$Q!SJ|iY51jY@{tdIIiuRA8%QZfH%sc-j z{Yr}VmkErI^ZiZUTqDZwZdCtp(>+zB4$S`BF6s8WrShLk{U=!7yZyW|aGB^o`4r*v z;*?*Vy3dLF--dwZH}@7=2&Att`L8!{Rey>9HxCj3PG5IECjPxsbKaNmOUeHu6sP>I ze5L&b34fCMe=z7>ep?2gYcJuSqW%-y@6G?W54INP59?X}|Kr_$w|D9&+JDzj{e|P; z8_hW<`fvTYLzj9uPWhMrByGO*{nM!Z2LJWuzvhWmV*7cQ_z!jTF8_|%6+V#iueek5 zANtk1|NPXuc0&pOZb0Mn(!AU6ypvT^B>Y;MzlTP9*MF%Qy+r%lhSfU%aGdtLr|gfT zr2My%{0U@u=U*xBnrkF{9_4S{;f=3%&B0qGynmYJKlh?{{jVBui#UFKN%aqRcWXlQ zf3yFm{M}CU|2)R_n+Lq}ziLre(f<1bm0#}r-tF(J>-vlSBfDt)3;gGu|Hj>`#r317 zpVuFp7YE-dWq1pz{Fih8i!*)(9EMdME(PW$`#tx=-= zqVfuze_ovV)5Q{h?v(Nm(Dw&+c(=c^O+Wib!WVyyzW;#t_g7xELe&2o6aRs+-uMeo zel3n)sa$_?%I}}ePmBIDA5i-b$H8xzyRWtM{Xx$EZtwDYqF$Rb68a7G;f)@ON?h@9mxc z;nnR$`+G6+zYiDjF2CEi-zCmpJ|q1h94G%K4?p~g#Q$)z-{cna&VR&XUt~%6MhkTP zg)4japACPs5&Pdss=rWi@BC}`A1>-YHvY>{}0E(KlNFewMSzJ&MPr}24l@ZYv>JWs-ZNA;iA!Mpz6$UdAW;S(wU;FsRz zSN*Z`qW)q%sre7Zk)I`czx$1pf4LVlK6koz{wu71ME$dDCo2C*-sRuA(Xv!2|C(I> zhrIDMf0>#o;dhb$WjN0FpZ$5oLlS-^k3Z$T$Di;$vztr!mk1w-gP+>0Y!3;)j_{#4 z_`H(qMfp*h{a@qYcb;FeK+6Ay+PeO%3f|w}aqaN0CHyNSzpTmL^_OtfW7{PB+dO{7 z!T%VzMwGvQyhiPRig*4g?O$ms<=>UsUm(u+U$zk0kGB7=f1mo#!y~95b-;QjhySME zk}Kiwc!l_nlYglrFN^*cd!E(!U`Ox#mv>8_B;~)5*6;lXz3czuuIGwK_(i>S{&_!o zmw#%vR#hc@fcy`vL~r~r57&H6!n6N$xTd%KdSqe|as8z<*$+c;zW>J^XOBzy@13W= z-#Y1Cey3Wr-zwqnWc`urzg6U7B0LRIT~0Kp9v!6!2SBNNYZ{veB@VF)h@(Rj3yR|d z6bp*u!xW=%>Jscr_`Z0!Sl<^17xVk#;3D5g&7nMn-2cZl^*03vka84l@%d4O-=LWO z?)GcqttF2imGBh_?;qfef4KIivn6~J!Ut~l#(zEVv+WZ8vX_bf#qRcR^1tcTA}u8R zV9GylhIjrSebc#-gnxUB&Oh|ba4uREn)wguxv;#1|D_kfjPtup{MyWk!zKLw&nW*V zy}$qbqU#$<_yhFW{y}c}ZRUTvNs%ule0VnHzsmdjw?6h+s)XOg`CoL)Uo-!U6P`FM z;n(lg`RBrQEzZZpufC^ivV?z+%dhT0)39JwZ~oh~-+rTn|BLEB z_Yv>*SM#p34@vkBR_go%8@$WE*mtj{N%-_78lU@`H~%}|y6j;IkLR}qiux@7DDU!r zu+zYC68=YOKe_9?+wX7h9=%S&Z+}no?=R<_f8QrJi}_FG@1Nye{?A{yQ|v!;2p0^l;k&W?TJK$c|J%OlDhVH)MD2H-cm4nPUZuGbem|AJ z^{F@iPgXscCE-&k|Ikiv{9DI|i2e6Z%0K+MH-2sHZ_i2je@^lv^o2LR#O}LBOZbX3 z{)E5u#`{VZrmKO5&Kn)tn+ z4;1yMeLv~)3;pZO|KeTs-jMPSQTxyRz*~NO^w^+^5WM_;K&+{PW`AH?LT>Si)O_h=1e!O0)h? zZ9DOngdY>qc=P-t6JNebAW_0^r1CS*KQi%aO5E93!ap#FzTY_i$i%mt)bOB$_mTa^ zJpahVTi+b{Rl+Z&{LS-+O#JS5ZyqY)!&Lu%iIGKTdZWBmSDcUz7ji&s3N%;RlfZ5T4~-es8y%FOHve ziGOqdteOATva7`JpGEpxo^gJMiBBokcLPD&b$}_IIE6_t*Zb z!$b-H6t%zHU%c^Oe=zKN315inFE391&o_H8Q^H?O^%uC`JO36tzdtGAcO2CXHguzR z`|We$eX;$$LEj&q=3V|Z>xXlt{M!@%xpDaaZpNC*628nX&A++-(QH3gKW*J4;ooQb zk+J{G#1Ck`EL79Sc44f`lK%{m${BPKs zA?iFG4Y)%cOD>>-;cNH z@(a%OZa20-x7xY6D;8^zqe)HDXyQKBK`x0|B#vg zuR~|nkn;bRB7tq2pdD|1x}jO&t8jv_AJs_{w~K zO&olBps;AaQTN{z^I73I_~SSJAnGswWBV=pAL!;3rGK_>`QzypQ#Eo$B^saG`nz+&Kuywql;yaLaD5VN>zG)OP-n`p!VQ>yIvy1n4#T zL-TV7VAPG6*TlOv&*Of-YpD^LZf34F6#bI!;*3I*GnS0DU&cVQOO}X^yo`Zn$1D*Y zd1;{4<&lxA2>Yh1dzM{yNJie;jf=iJezP1j1RG3`)K1VyY;^mWWgc}cvg4LwxI$jJ zrdd&NyIdo1igLm!DheJcSR2k!4md|e!6PMW!#TWpUW35mhknz z)Oc<`vG4=#srS5uZ$tBE>nW{2#KI?>7&c$Rccu9=pFbE2|M2D)N=f+Rd#S?c{JmKC zZsj&smhgq=Qu)29=Z~@QLxU9tOZbG78qfB}SonJ;F6b}et^FF$=dZ=W|2ciD$p78P zHJ;Bui-j*#{A;uZ1+8U9C z`maLe$L%+PK8O1)hYQYpIz{6D@^3YO+g~jF4Ta7;E#cc9rVOe5F`nfRy|qf5dT25n z09HCQ;0_hV@(=G{4GZ#*`DXn8e)xS`(ZYpGJ!Ih3{i~Npq$THT;)^A1SX`=Du>>AJ zIR8~Re|@ZwRgCobSop!U0HXt zUk)2)KJd1L-)Z23Gv)k0K3Q#`gg14=%s(+2P{%-<byJ`SU&0jN`E9uY+;@Eh_(O_8a`a zEw{geA2nJb;jewwjSrC@BInEDhzCj}OZeiW-FTh{Fpk42%S+FZ@J}x_@NdiQckAe{ z4@mg?Y5u|G&wfmtFNeVkcj5X?RQXjH?an_;^AN^yc>BO*=>HmpuVdiZ4~cOce*MB6 z^xuxcFXZ_H^?#nnFpk5{sn-mZ@E;iM$09!v#&LMljDGJ*_(KNXPktPXYDqaU9k^^XD)LU)#vvKSyr=r4N+ZCgC453m7TU7pA3_PDh%lUHX%X>+b9}6eDzn{;MVH}6w%q?@dl>b_z{|9Lv#5fKgNu7-T zr&0Xp8u{}+e#UY5PoVM}Sy8SVp?GXIk9L~Mz6Z;Ew?2OMB?;fn zzz1j@nDgcE!AI{bB;mtm`NwE~EkC=unuKq--OYc1)-gF>4*yI%c2>eS-tEToI-)s` z`f)?KRxp1mZ{4Ej?`(g?`}4w8ebzFvLzy^D-Le)9%=tu`KYmge=6}_=_AHC>Y)4@H zmqlxKD3y>6ADus!8x!fg|LbMIe-YDu zfcMu01bl>|rqJTpcbz5sE#6-j67VMfJ2tl&E%A@{pM`4ptlevMK3slg{?GI~I0N!8 zX4;SO{rL-ps#UyJ{Vz{PFzoKx>~>)A)W9KdkMe zl_fl$za3~3AHV0=_`wn$&)*K^17BxZ<5?1ZAmDQ!ONip%Y=6H!+Nr8k|9F0NxNUs? zZ(i_ZqLe?L9~`@n0$r_!sb8?pi8X*2m$osnC9|Fvp(;fDa3Jv;N-PIkl)%e|UaoxO1eo zOdRLGy!rh@bDzzTzF(a`*TZLZF#5mw{nwWKcLd}g zHU6se+j>UxZ`R-9I%(fZ^@r!T1q8gw{}1PC|03~^=eLCfyvhH*hT9iN^@r!Tg#~=% zi*yZ4dpPGYssE_++ir-Y=JGf5AAB~uuT+0{ep|o;&vd%gyY)Qaui^S<{Ta_c3*6|l z@<5Nphx3ncq~q(}RBo)qKb~I}2K?N!I$bRM2c16ZA>r}-t8j0hRpf6s9+Z-ilQPo; zPc?^ci0v;WB&!P)B#*6}G}*blrG)Qj@31HTj@(&{X7 zVSAi4YpPwpzzvMtzS{XCFPouz7%!? zcxH6+qkX>&C*k$UvK=Uf_P2)ehI10naIEomWRbUL6!-bctodV@dc*W<5d8q{e+<(( z7$)8zXXP3ZUw+l3EUXWg37vA&e|V2hXz!2sRr3$i9?!>oe=s!nAo3qF_-{n~+y2*d z4u*-3%FGZ@PrsHm2l-!U&_6=+s@z#46^Zayn*UG~K_i0cQ~1X1RnY&$re9`3rULv! z^zHL=zRn+gGylQAy*miYr?gT2&3kFS%^N>l<_;*R;-*^2zqBHXEH~8-sqx?<0LC(6; zh&aFC-rh(*V9>8a{PX>`fuD5wn|Om<6#aXu{JdA9-!}&T@#w>}%k|uG-I<bDpg%MQ|0X^v2V;Pr_3|^S{g*!NmY;LkzwzS{ zibPzwjw6A5%Wu7NdOP(Kp|}l-zg&md|d(zII29@-guSyH*z? zqIlJL_ZBZ)xJ=d=clk_a`m}Dx=Q!B|sX>STnaF=o`1n=(Y9s#(jryI*^m%^|jV~tN zAZH~R5hu=`3nBengZ}&&^i8}$F3P|4!CwyE4E5X8)GzmL)<{0zk|JgbrpAQr+Abl>MCQtu~>pyn4FQs+;(2x0}&*kn{+*;NLw{1cHIlKK#d`h>^(vv6wpT9x+Nq)P9s=NBfP`Q(txh5sF#U*SHf z{ol*-nbt)EH2&t7KIhZxVBcg(KKEIvIk5Myo-A1Tb3HtD|3UPRiE979)A-B#I|F~@ zkA8VB7zzi^s-^UYlZO8Ad<^};#2e(Sqea~@EiQzg!}1Rs^zWng$@dd*`Ty&NNB!$R zBj)g}vv0%pV;TDGe5zlw{g`-zT+{}iTi5-Oi2Uy+{(I8=I`1(+!v1(ZUo}Abi50H_ zQ30MTr*j@MCkOp^Z29vE(O=BvL+z6Fhq&~)VbX_vQR>t`PX4+7j-~!(%Kw7We{$Dr z?IrrtX@2de^Dn~3bo-1;-CYjOKXK_B^;7e%Uprv?G3Q6i zW3->R^r_>XrHR_oj;l92>vs;-??@USd4F`6`foh?m5l~lA=EVi`S%;`e{GEZYvK)Z z7O4ex^yb-}GLU`~gZ|qw=$m+(5dGmd!jtLeugCIPO5@AxS=vu|DwPkP-xnbJWP(Z1 z__s;F_~|$Be33G_2L0JF^pkk>b16R#znF5BnqRCU`rGGe{oypq2YC4Y>hLeR{l}wk zzMp+x%`36|P5pdIjPcRLYc3rB=k`zGJ4x#+VE^UzKX^Xr=d9n-`R5@zhuQBSCH-l> zf9d7Li;(}I(SAOT(SA&PR36Mfy+~-#y0(*lmTw=Dd@#qCg3@o4*k&BgkGOo8{vA|4 zVcOpxKBen79{oI$Z+j_hyY+7L|0=VF+D~FolAI6y96*BPVKh5#~$ma29u>4K^VJ5Xt_PYy_{XZUk^L^nlH}Avt6END(ycq4@ z#GCv#F(PJV4}A~muQBL<9ix4kc!Qj6KjHWZ{ZfCy@;B#?hhmh!G5j$ZJM`Os=|5Wg z_nu3D@$pS+KiocxY|-!e{I&4Ux_!o@A28@Y7OcAq>$i!~exBW<6WaH?l7DDC`mEP- zHqA$UxfaKF)4q3@%0FO?@A2rH?~~K7z6tBs^sibPqy3n8=F<+154iH)kJe)OEHv8B z|5$%B<`-5R0o}^ZNdK|%%Zq)H|C0v&6EWJSi8shufr>hY!+j-(7eoGoRKIfSKI`{f)jo~-eI`cx zH1Rg0^hX^dV&(6(uEF{Z8T41hnE%G3f7UQiuX|*A7o;CH=&xt`wEoNT|MocTKVa}b zW8}UtmX9fa5~=*n`JIV3$XT6?h_pFbZzBDG(LSrjpl{+0a@KW5#G%EjUPSt-2K{<5 z=$m+hT-5r-|I(K9NBUU?{Z=vPcQFYX|2D_B?bEK?g!OBVkMDB*8uHE5KMe9w>vxAv zH9C#sW5DQN=VOeIhIzpxZ<+7^xuv!8PY4<1vpPoqGVx{xej_3{es{@`kc>-&tJgxN1Og@G`_D}sTncttMTY_ z`{i)>!K||2f7zTri|yxuSHOSJasGpOjsvGRL!KWo{cbE8cYE#>&@T_? zJJR}239?5R>ZM6OYW=jGc(gRH7o z$fp0MPZNm8KbH%K!v=km3i?}A`QQHsbEp*tUT5Zg!2H$>nJ$NmUhK6}qTk{IBQ^cN z)#)mN_u27VGi16PcE2!B+fzFAM#237x~3aKXCmB6;V+7<$nBXtVDm{VS_&HA1)~U zhYw~Rk?0Sz&u7r(6Kbj3PeJLApY@K|KCAhtL(znh_aE{(1pIYo$o0x$UZ3{wN&Me! z@Xz~W3rc_1$XR%PX;l9$Y41O#_DOn5LCfc|=PtwZO{3`Ve4oEu(`PwXQ2Ob&{W(vf z{~awv`Pd-O_qcM%*&893JBLFqbi(uDqxdg!Q3IJipO3LxZgSPo~S^isa{BkmygN^H;ch!Zk-J8U?N2 zUDwaV^@XVNzd-Vt>05kHEQdD7?mw7s4wFyb_Pa#?7JL6S_2WOaL8zeopLu#|d5QkB zTQy(IzyGzgODdn%g=hDc=pQ}irXSj(`7fw^cw_cz@qD82aW{STKM7{*eDvGs|8u!> zc<#BCX#a_--<0ic`aJ&HVKiwK!*n^EyMDmq68)QAmFX9>eEvCl<69E_%YThQzmpy( zW3X@ApPBz(YmF7pcR0FUreDzZx%rv>+a>-}cE_Mk=dk3L|9d~Zznw&XHuWzp{ec>- zliOj847gl4eCp#+ibTKKvzh?Y=Xxz@`JCFceu_kY(qT>C?!R*`P5XYO2GzkCi*e#<|lV`;o!DN4T8Gvq_=t(PYMZ+NYis2{#= zjK6`Bmq!1YF)!aM@!$Pkcm1*-NFSw%JjLO^IQJ?k3I5Ue z`K6!n(y6;8`pro`GylBKY=<#2V7brXh%q0D=T{Xr3`O+`Cy6uaZ^6i`CA3;U!Qz_V3tIG9?2iBU!MQ^jr+>X@8ELh@a;Me zi{}?Tds-v8esia4`N`v$Ntgf4bUB>XYxjK;{|Pj|WBzleYx>r)g7x3-^KUsS(Vt=P z?_Z$l7gYY7crf(_iGB}Lzk2b~^z*=jABy#Rz1hF$9;1S`pPsF5tS|BZi!r{iA9OCA z_sjKZhFq^4{_*F+P7?j(4I0Vqhw0m)Ntpi4bU8fp(62#>{N|EbYFnSOASwo}F+A2ohG(fM`Jel^mZ|MEI;9Q(7m zzVOJ#)nlafh37!O@-IlR0?AGMqj@>qnt=6th_CwV}^- zzvXh}^kx{K2o7s4yXPZ`{$uaygrR3NUF(ZWqhGbtkvbCnB1?$=Dx$yV(&*MFOmNK zYX4ntu2a=|8xs`+14~Gcz>(;5wpD z=K~a!|Lfjba8aV4^s%OIeM;?<_D95{A12ru3d^imtM=L1L4uR#6RI;6`daEbK)Zu(IdiT}`6F_65U~H!f1F=`>^~=c=Kr#ge$VHQTjZY;kG}c-iZ;H>r1A;VG%G}Q!w~KN zHSq?!R-O^@>zwT=68*9vozTBckM9=kpN&U9kf3o*DEz&H(*N!9-%R@>8u0jgIeiH2 zPl-#P_zzIn;pBc?U$*J9{4ZMAr&5HbYW~Cdr0*xX98}xcZ7=$V^S`-%SChX<_-9Q& zKyoM^{~;nYmBLfuPkwRoKaSexK9Ua>`6Yz%Nk2ezIe4`DH!k|j|E*PY3brS)oQuc5 zp9xc#Ik|Fpq+eNkseKlZ zJ{6O7-GNLO|J;72e5_N1>0J8|?eESn|4hGQ-EW6E`M2qF`H(#)tE|EF>PJ*WA%X#a0K`hKF%LDyORs!Q$vB(+bzpFL!pPtSNW3{eD+ zUnMI4SJ+uTJbqnA{(=c=XNo-!gg95UKt5 zX8y@;6`=jm@#y=F4?zERsr>(c`nNmFpZo8n`nLy&e-8K5p4s0?pZo9AB%e+H;dtd^ zmj9CL)4rF=|6S70`Tp?$o&Qi!`o4RAX)e*lvHYylaz5UlVaxxTte=zox9<<9{j>4t zbGzXT1C8%acGBne86f)@-wz(jC;jq7nEA*WxOItS|7^Pt5_XLEZ=2_EGk<1i(x0^K z+P@|G1Au<+iUiw#yCvzhS*va7 zTv#|xHPdkhYx5@dNvd#@_{8+7cphtSkrpt8_d3I`TbFkJ?DTQNGBWW1*H$gs`KM%O zOq`gWsqQdW|AsSW{q^{uS+n#a$BXcr!D$_uLit7AA6fHpsGm{^)`s?YgOSfZzqi*F zfSm2K0>w*N!7r|4GIq%I!V%LCU61EON6|036jGE=c#;~bU`TY7L?Efg6pzi;4mJhcd|6}E?yik1l4SyZ`o<#rtFQ9zNMbqc<_b)7O z1*XNPzkO5gOF%#B{*%(+pB}D|U~L0CwZwmJ(Q;Psd|A65`46*vT3=&zkof=kSy))D zm|%4WJq(8wmU|CXu&n>+36!eNWbKgYbNKV^4~qV$pOO8>vI;3I>lqnsYLi-%X~t>9b$D88VJTrfY}U z_lfr#jW_7CU%DAGT@G!!6mieiI->vkYJ)!erJEts<zmFt}|FoXR zTC|>+-}+sVu`XLG|2>!K@@M+Fmq@>D?~4yh^xIJTH0kHf*AtWc@_#gSo#?;Zkj{N) z`s}~Y>*x8Uf6c1-JtY2X+5Qo_oJ{}ySbi#I{U#R;-y_lAL;G)Z?*&=+8%@}1(>{bY zG_U1`L!n83_RnorNc8*D`aGA9Md$4BeA5o&(9fv#i|F5dx4r(a%O|i&+do(i<+pr> zKRti3#Q&TGw|wC9$@rYs{MPTDJAM`G_r*W-hjaP!`H{?be(6vDxUT3wRsSDN-!6al zA1C>lU;34cPHHBV&&@IDv;532{rhK*`dOlXZw&e@Kl4lf^=5mnl<2<_gFeg8{Lv`L@$B%Afb&a2TikfAIV-6D0lz?w9HFdO?2q@4n*quO#}1Y5$5n{&M@FFuXZ` z@*(A``^EbcANyAGZ_;P}^D7@}&n*6+#Qz;6|Cv7fRoZ@>v>(AJe%rpwa&FoFF}VI5 zr9V7rj9;MvdVFO6W$wrE=&!c6w2kkjAFJ*%aewo0qy2DyV*ma8^8e#4ABgh5;lJ+o z$@B}_{wsZdVy;xbSNx#q+v6kqhZb;t(Q^0jsuKOxM*FeYPRAj&(|GOwn+1zx`Dyz< zl77PegB<3wf9U zN#DP?Iob!J==Tg*R-h`_f1rRQ`aB1=3DX}Y{WkOdcZ)Q?ZnhBs)&B4FGrJ7QlIY)Y zFW67~`hH1?|IjhNWwn5x@f0@xJ?`6&%1QT!-TEEauda%w&-RnhF29w#sfs~O+Y+3S zuWZ_LpL9Rg_qadl>S+4aVL0Hj$IwX&|K|40@oNwGawYmRH$eLl=yUrCZU+9}j^^LA zk6oO3WSC^XS`GC5wW9fF`r-HdRVc{zqYGKOXc0lYn;HX!=Z-GY&qo_n=h%{`nx^8YigxXPx|W`3FW9 zvjTqAT2fbs_?H@x3gqMr-&t)Jr4AJM&JO`soj|74%%fqrv+ z|0>EXuD8-4fW73K$^VH*s;!ggKaT4QNB{5i`<$&=R4V_MfWFm&=||RIxco!Yi&%N@ z+Qn}FVe((|#CwlO{O?BoA7}cPUOwf+f1Z};U%mq9FZ;jKubBGE9}@k;8-e~41*dP0 zU&${%vRWFys=@kB*rWXY_Y|>0W6aUqt_J&$o2$b4b3R{%4~_eyz6;n%)E{f+=1+g) zcFgr$?dfekNj?k({sV0jtnI*}vwyMt30zg&3Z1;%%>?|5>GF#uiH~MW?K5pRl>fB} zR!gv>Nc6)qt5~^xi zExd#k-pmI2`p>#Rv0(Ryj>{S4x>|JNuRhEkjCeJFhc#2H_=^>H^q>{ zOqat^*FC;LqL1s->Y1SXjn_Igu2u8HbU9qMe@B)?U#(9AC`k0Z)~Ru=njfaiVRp~9 zH6;2!Jfjiet(yOns(d1HzS|Yhzji{)Oavp3ne3Ke^X??tU5q z)d2fZxOpPnGoQ%h?f%d73txV^o<#p!qR;1N#-gA1zeEdv{4iY(8=ngmmFWLQ^!a|w znDqApefaUibU93Ydf5?){&nwYgrDrB|J~>=pN>U9KK$dea(kwzUo845e=l1o(SLR@ zA#T+Ejj`zGbpbyI`0>Mhb9j@lYAuOA`ZwScruOOO=YYNr{4iY(FZ4RMT%tc>fkuQ{ zfr1Rr#rE$0`x+8}$vewpl?eXFbU7R|^!bk^`shD_k3UL$8fe+uWXVT~LM?Vn!@xydEJkYmA8Hs-V z7c?U83oZXm`rN;)HWe)OqYRiXhZ_P9J|WS+{HO-xuGi&L0rpc#dWbb2EN=LVLI1mA zO~vtRyJq91;=yoEo0m~Re`Ex-H?iT_G#G$OBsH~)Ey!A}N${4iY(+r0JW z3W+}Y-{2F-(funH|LBKJaP zUwFQ*vwd>;#FL+|JiWS-#DAf!#QzpuK6t*alRnFbz_MfufBZ1t9QLd*?plfdVAij; zdeaXtO}6mI57XuF$5$plDbfGodyUAQ=uO|>KH0(_KTMayjlC;9D$z&(E%i*)?cd9f z3w^oxVY(dtxA}|p68*skG$MFV^RNB5BI6gAf8LeVE&TDrbU6&>{q>hbAN|Ad2@?Na zeqz{$bn58w_m$qy50vN^nyC@FRKGF#FAMy`k00in!`z0Siu&^&Iv?0SNte%Fs6x4Y z7J>E&$`(CLm&0>gKH4qu-wNh$_~a7(WqXl+WS*FEwLDK`x*Wd!#Mm^6e(q>R-U_8^ z`S69|2MDf*R^Y+-`p@_KO4XI<*sKm7P%x*Yzp=7rS~{TG)J;wMdiH2l+9zdXJNKQ3nBk01Vv!%Cm_ zEiTdj_iaLy1i^;SBscv+z%t8Dul7IU&*e=d`mLz_hmUIhP5LcbLY@zR|ND^2>Zf>s z|1sYjzP;h%?-Ko<0gVV!{pNR_i|KOs_!S$!l;{_u@g?tj-F_~We$#fF@094P^)vVc z-k*4>^j}Ka(MqD#_qWph*QCGYQNzxolSkEW zy-!DcBGE6}M+0)-bkdKO|J+82d=&kmP5O3|=+B|{8G1*zPqX~PCG`B%8VUw0{L#bh zhQmDz=d_UM|s{gq@2qv)Tj)?1vvJol2lbicjj1$erf8zfs;=95&5tW zoBY3U|LslCKHmiB$`^0~k#z&KXTfTkfxBT$qhv{;-!*}b;5`FZaP|pL-_8;kAHvON0 zKK%G$x*XoIqphf)TcjW6(s^~7|49G(aajKJhptyI=p*qziRHr$a``j=!86c4;l~g2 z&0)JGp@tHD^#8yo7^i%c9|-t@@WXUD{9|f&aePPr4}8LL=%XJ9{`g_K9Pa#nyV$?b z{{tWYgWmOvejxbchv{MZIsAKW^9~aI_XlZ2pqI1#MB1lK|1F>oKYo}lhwDEaewRc) zhui-dC;dqO;_=I$0`%d>57Xsv?LSEqB>F$HeicLhFny~KjE(rChv{KME~VyH6rkyTs~*|;rj$D?*g=c`0>MZIZWDq zUes@Aj@F29ocawz-QtfQrfY{=uRbpEU*U6&@XwO@x65Y)ln?y)vFTDo(aQh&CHmGp zoggnp`SAD>y6Cs?$B#+hUwGxa5`FZq!Y7aVua}<{`daa0(r?sjx2T_A`KCq${?z4T z(r5iS?~2M6{`fKJmw9Q{{SyDme+xi?hqQe2^5Y7FFBd;1{hsOH{3y}?D6A2=apGcUYx<$Tbp4w2S-x2np``Ig5C6sC z&?~y^lIS<%`km@5pGf;(UiAO*_9gH>RPX=iUe~@C*)!HG5wewJ$`Xa7(8}lHT5{v! z%2G0Rm8~LMYLq3ZXp>gcMoPAl3iZ*RqKgVG`ajQ{^Zv|y=5yxW&(-($KlgR+Gc%u= z=lwj-*>_@?MEvhCyX6Hs{`*!*fsB)W`91!dDkfL|9Q4$pb~^s&PL=$v44Hmw(Nrpb z|ID$1lD{ZT7wnaTT|m=oJ>6T!zs+j-fvxsOlKegS$5lyA{`Mc$vvvG={v|s{#s47x zuz8q}8?=3iU-#(vZ&&Hds4T-b$bU35pnVv`I-=~A17Fa0d%vn}-?{TI=^N`lnLh;W zAFF@TJWQU82?xHoZ+mjW%_RSM*q;RZw~STxiT>>8@7cdZf#mG}?80{1`X|p{be)=4 z7$!f@V`L8p`9aT_-}VZf{mVM?3v-l=pS*vIzkDfAQw!1enOpz-_a}R3=SS63{2i75 zOa5N|kNTU)EG=BG6oA~IW2XPJLMQ*+N7M&ZWc&%r5Bo{f%ik|ks*cd{-!)!J6e%I?e|aE(c#^9mv-2+BCr%iztsl1CD*0R4 ze*RwkEZ>CE_HQX7np4E}VfMLn!=KvrMK8tQIFvho^BB)FhqV*OU+hVJzSP-g0sgz2CzpTjc;|@@I{v3s``x@&)=wmV zFaEpz51pv}ySkd|!{pB@uyd)7e<9Qlx8%;>SW``~hl5=}x3v0O%YWh)`9<_qzkL$r zkF2dG*u#M@XpeS-YU||Ryi$H)x6Ylvc#?RtR}OqZ`$W2G$Cn$Z{#BvoKZnheH)x(b zdpPg~E%o`^Z|dad`Se4aon6xd#k_{aA5L;dZF&&f7rs6;=}-~Gl?`(uN_SBK;k+S_=p)Q0-v zc){+xKU7(9Jl%ce1)MLil=4oJANwjfyCe>3B0L|OU68-wKK1_HdH27onSbPj-M@u<>E!46;YQh1f&D;)I^QHO`Gfq=EM9W4jz7;2 zw}?OX12L22Zz%mhYCAVyr?bz2Q}jmJaQn14AUOo>-vo>m?Xv67ROY`SVE?q!)VHMJ zUr2oy#=mob|FB-g_cQ|@JC4=#@|b65~y|g=I_z^nX*Pe{zA7A{|esz zkl0rV-}8J^c0v18l#gTm95d6eTBS?BJb%)xNad3$^S9jQPg><;$v?&y`GXkt*dE>f z0u#rixRRt&AF%6gkogewK)MU=^8mh}KOWNWfAm^_Kla@Lf86KAzfYG91$FYD4)Bkq zGqwKs*e9%%09995Bn&)z)pGDXH-U|nmYcM z{VoLpfA9mfL(UsUxPs2P=+omm{*MRbkL@p`+S|a%Oa8L${(MZw|5$AQFBwmb10gMA`Yr(%lEK^8FUd zKdV#!yDHx;RlXxS6}w!1AIzU|4|<*P^xtHka<*E(I^Q1de)!_|3SW_|tumih)&h)J zNxw&S;Hg(0fd6+-r*Zfu@Xt}><3QOJ!vEJ6R1VQR4mj`y&1iCh_t#6{|8YS6ChzOz zA8F*yU)<1Un2!JP0RQ`1=bJOd`Spnx>vtN{($f2 z-z-_c4q%9M1-fkK-Q!4pvZ8dze|mi@@2w~MyBF9;*}O}(m&)|H-F;p}^oWa+;0s#+ z^-^ne{QuZ1`Qv;y@E3RIkN?3|b#Kw}@AQX~U!A`O{!TvmUpTM$!#e)g|04P0{3GzU zCQA9ARN+-d%onKh@E5QP=+E1G^7-Hi_8+Xqe`Dt#A%DInV4sR*Qv6v0_=2|F`3aw| zn!vvh^_Q>%e+%abO$zYuJU=xz{%OBF!S#m({yX1P{MGqN$TuCuzoLpiDPUFiM!TCXI zUn>XvA%BsqT;<<5<3`T^6ZmgZ_6L9T6IfFN_Q`{PnQe3Ve4+&Y<)%paQI5kt<}}Ga zmj9I5m8<-_sz(d!_+R^jK@ zPgeeA&z;v@$N#%8r2Lq_4gS`Q{MqNrH$MJE$Gqt5pMe{*Iae9LUe)&7wW&k;KQ zFR1vB`K915W=a0Z<`0+cD$3_eCd8j1YX3*fFO8i;735#!#$4sEH)#v+FPXr9jcUJu zKhEK??hVMF2mf`$7V!RV3H%qLe8KrasMp>X;GakS`P^pbP96Uy2w%k?`KP#F@)s)p zr>4}))jo5F|8c2~|3)Q0=Eov@ogn`*cCP#v&705XA0^o5$L%VAQ|AXkervXr-&v6E zzF?$OOv$bMef8!mcz@~y{^fp^{Dm4HNBM5fk^E2j%J-O z&agF4$)6{6|oKK)#^PU$Y*}pZskyue?gfzv|2J z_Q&~C=0o}8|5v2qBpv_EIr03Fe#L?S|CGhK$IpYG4At=;NppK#hwvRI)0q?GpGW*} zd#w5n9sfG2euD5tJ;hoWkUtOpD;KV4t>Zsg)&IdC^%V2r0RKGdhfg)Q`)M8j6g55$ z{;_iu7X|p|A^*d-4z8`^KU|eB;E!_@oqX~ibxFE5d@oe>Tkyv@b=Km5{KouT)9;u4 z8$PI$zt*bw_z4_yNq~PI_J8ZyMF({JTLt)I97Ze+@Xy2kSF9VVE#L1!`cnNrNMDZP zpKSSlQNiUcbn+il`6v39V&|wYQ}QR-zPM~og!k7@$lvCu_yhhp=iGcGfBe_48^HaO z3H(1&ib;GakPuKCn*+<%+E|96%D$M~yum=olm)+5*YPtVsY&(-n2O2vPi zrx0t0Ju2mowJ*|gZ{NL9yEXTZCCEQo*$3yx#p3^Cl7B4zl*zsR_Hd8s>vjAeQ2cRz z9QX@6fBg5}Qt?q8|A$rii1XvX-^nNcKII4erQ=^0{U_Lu8s*FiDSxuAL{J7-*KI*qc;_D}<>!SYl=D}{ob>nNie%z-0mmS6TZ7MGP^Gh+m5p(!d zZWwC|ga5@}KL3u6Kd*l@Y5!vI4_jZuYagS&^)N}oK$u7trc9Fjd(YevGZ0?^A z&i`CCmB!yMPwbyhRUd}&56U0??v=6JKOB_*&&||7yxg-t`iJp-vghqp`Ro2GboQVB z425sEaQpLo6n0_uft}9z;Evmff5P}znQ_FwJI6@EAjk7V*ctABqB$y`z_{3ra-T-` z_&(ZhanMlSn~~4*Yo9SHd+4B{1JbiI)RO_3LoO9z!SU zHEl_oHmaljV*54TtleF4z!2lIM*O)kn)ZRr%ovn8bnuYu#yvAekIBq#V`PpPF>FlM zRij3X$!ecId_YE~ciNwO+iA@30mejeiQw zZ=WUqk&&Bs>G*H>i1^>-@fY7FCqMEXXs~GG%nZu^6V9i6jOO6})ekKYVwUr+9Tg&8uES`*vMjPP8Bu zEgBz;&>mX`-3R5bf8E{fN&bZM3ky^Hx2b3DENZ5UiAB$I{q)H`7@9o=Nq9O8l&I!ci}Nl0enHPtotYT zpC{O-YPOU+Fa9`BDU5%=4H9&ys)r zFRuAr$3Oim%HQ@W+mkRR#(5x^qJ1cTVizX=%^$VZ=FfwveGzF?Kz>aB?GXOl?qCQ0 z!SL_)c9(^4}-VpU~yc(Ko1Fv8kF^bQ3YBbzo@6AYHkj^l!w{2kKD%Sv*)j z|8N)apAG(=e8F`)shx<4Zyh1@0M4n)x*yf$pYKrk+7HU}5B%}d-B<2YPu@-EdFueg z@xl;0Mo&Gs;)E`I`!1tbT6^)+Q0vTMAF7LBJ0mE6fgjInuakc}^$!~h<^KDA`B6U+ zBWPXOePsH61mv?%5P#(A>DTMzuT15;)5en@>*Rvp2jvg`J}IZsVI6;7e@8t}vDeLC z^yxRqKWLx3z8*45XP@7x{b;E35484~Tu6xf6Yb+^EJYji&6LYY{vtVn`9Cj^{DwOJ zfVF^Jrz*$SN2Xln#UD-sF@@E|+h0{2O7TCTe)y)3R&5sd?zh5Z5DTyL&m5(Ge+_05dK##Hil$pXEo-3%{q-rzayj1 zsG->z-f<5D^MGh#aKFT5jSN10VrW)Zw<`i26S2O9rcKou7Jlev>KS!S=ut*w4pjXa z=>5nZHD*AzaTmAa!#X&+~f_|rR$DC8%_2VKGU$&t@*xtih=wd0UZlf}R7tsU3s@a=JugQ@mcm-t>k0nU#wGf02(R2;kb(SdZ{0QoQn zy+IFk$!x8|pBj}MjCZ8{xu3vq|LW&c`R!{Lr#>h1LF-#;H&EWbI9o zgSA+uyJYe6YyZdFl+&(%uX%;SSN%RgeB?t8_0zCNKF$3!?86-N2EDr93)=nBXRTNG zAItbB@x6M$Gqr>;d0uoC!XiJE!pHuA(!=>xT%Rm{m4~lS(}n+aYW;IGF8mYmBQ>aB ziahWmt>~V7n1kM+H5ZlC?$0x4zvSQ)_J@BWzR{iRO&<78PYMt6VGg*Uf6bhwKVRaA zN+S!?&Y~!>761-#AoRum`^J6Wx;!bHD}d^>BM_`N#dY?4oh`Pon*U`bU4M zEZB!R;DVORsIg3^|EzhEgPn)|PG_<=`I!FQC_R!7bHD|CsCl!#I(+V5W`}<3u>3Em zzmrb#kPmaf1>N%HqzoN?*X5E!bYJe_FOHC{$wPnpcxAyp%mEj)z_HVlboj$m{%d`f zJAP1qJ3{#n`7j4u(4QXoNPE82;U6Rit99=AUl8B?t+HSr=70;@d%


    -6XTe|8vG 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%0DZfuN#nHMx=TtUq`m7E?k!}j>btr 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¥nG_K&L4nj=ZvLasA#||%3fVmT*K|rVD_VLCo$@0as0TxP8guBu#FuW@*ocq zUc**j32oV5sx!B#3okr1@>=lAN6y}*f~=wy_v84A@dF}3rhCa?5WxuqRj

    QLjb? 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

    kube-vip Metrics

    +

    Metrics

    + + `)) + }) srv := &http.Server{ Addr: config.Addr, From 5ac633f31993e64e9c13ddf26cef92c9f153e03a Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Tue, 19 Sep 2023 13:47:44 +0200 Subject: [PATCH 428/542] ARP: Add node labeling for ARP mode DaemonSet deployment. This feature is related to #611, to configure the `CiliumEgressGatewayPolicy` EgressIP correctly. As this is not a very common usage for this project, there is a default disabled configuration flag added, `enable_node_labeling`. Signed-off-by: Mario Trangoni --- cmd/kube-vip.go | 1 + pkg/kubevip/config_environment.go | 10 +++++ pkg/kubevip/config_envvar.go | 3 ++ pkg/kubevip/config_generator.go | 11 +++++ pkg/kubevip/config_types.go | 3 ++ pkg/manager/manager_arp.go | 3 ++ pkg/manager/node_labeling.go | 73 +++++++++++++++++++++++++++++++ 7 files changed, 104 insertions(+) create mode 100644 pkg/manager/node_labeling.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1c2945bd..3e5abf73 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -133,6 +133,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.LoadBalancerClassOnly, "lbClassOnly", false, "Enable load balancing only for services with LoadBalancerClass \"kube-vip.io/kube-vip-class\"") kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerClassName, "lbClassName", "kube-vip.io/kube-vip-class", "Name of load balancer class for kube-VIP, defaults to \"kube-vip.io/kube-vip-class\"") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 6b7498e4..b96fe0e7 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -425,6 +425,16 @@ func ParseEnvironment(c *Config) error { c.EnableServiceSecurity = b } + // Find if node labeling is enabled + env = os.Getenv(EnableNodeLabeling) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableNodeLabeling = b + } + // Find Prometheus configuration env = os.Getenv(prometheusServer) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 25b45649..96661231 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -154,6 +154,9 @@ const ( // EnableServiceSecurity defines if the load-balancer should only allow traffic to service ports EnableServiceSecurity = "enable_service_security" + // EnableNodeLabeling, will enable node labeling as the node becomes leader + EnableNodeLabeling = "enable_node_labeling" + // prometheusServer defines the address prometheus listens on prometheusServer = "prometheus_server" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 16610c86..d775584c 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -181,6 +181,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, leaderElection...) } + // If we're enabling node labeling on leader election + if c.EnableNodeLabeling { + EnableNodeLabeling := []corev1.EnvVar{ + { + Name: EnableNodeLabeling, + Value: strconv.FormatBool(c.EnableNodeLabeling), + }, + } + newEnvironment = append(newEnvironment, EnableNodeLabeling...) + } + // If we're specifying an annotation configuration if c.Annotations != "" { annotations := []corev1.EnvVar{ diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 5f61a0dc..8d4f8a35 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -32,6 +32,9 @@ type Config struct { // EnableServicesElection, will enable leaderElection per service EnableServicesElection bool `yaml:"enableServicesElection"` + // EnableNodeLabeling, will enable node labeling as it becomes leader + EnableNodeLabeling bool `yaml:"enableNodeLabeling"` + // LoadBalancerClassOnly, will enable load balancing only for services with LoadBalancerClass set to "kube-vip.io/kube-vip-class" LoadBalancerClassOnly bool `yaml:"lbClassOnly"` diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 610d2fc9..ebb15ed4 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -169,6 +169,9 @@ func (sm *Manager) startARP() error { }, OnNewLeader: func(identity string) { // we're notified when new leader elected + if sm.config.EnableNodeLabeling { + applyNodeLabel(sm.clientSet, sm.config.Address, id, identity) + } if identity == id { // I just got the lock return diff --git a/pkg/manager/node_labeling.go b/pkg/manager/node_labeling.go new file mode 100644 index 00000000..610cdfc0 --- /dev/null +++ b/pkg/manager/node_labeling.go @@ -0,0 +1,73 @@ +package manager + +import ( + "context" + "encoding/json" + "fmt" + + log "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" +) + +const ( + nodeLabelIndex = "kube-vip.io/has-ip" + nodeLabelJSONPath = `kube-vip.io~1has-ip` +) + +type patchStringLabel struct { + Op string `json:"op"` + Path string `json:"path"` + Value string `json:"value"` +} + +// applyNodeLabel add/remove node label `kube-vip.io/has-ip=` to/from +// the node where the virtual IP was added to/removed from. +func applyNodeLabel(clientSet *kubernetes.Clientset, address, id, identity string) { + 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) + return + } + + log.Debugf("node %s labels: %+v", id, node.Labels) + + value, ok := node.Labels[nodeLabelIndex] + path := fmt.Sprintf("/metadata/labels/%s", nodeLabelJSONPath) + if (!ok || value != address) && id == identity { + log.Debugf("setting node label `has-ip=%s` on %s", address, id) + // Append label + applyPatchLabels(ctx, clientSet, id, "add", path, address) + } else if ok && value == address { + log.Debugf("removing node label `has-ip=%s` on %s", address, id) + // Remove label + applyPatchLabels(ctx, clientSet, id, "remove", path, address) + } else { + log.Debugf("no node label change needed") + } +} + +// applyPatchLabels add/remove node labels +func applyPatchLabels(ctx context.Context, clientSet *kubernetes.Clientset, + name, operation, path, value string) { + patchLabels := []patchStringLabel{{ + Op: operation, + Path: path, + Value: value, + }} + patchData, err := json.Marshal(patchLabels) + if err != nil { + log.Errorf("node patch marshaling failed. error: %v", 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) + return + } + log.Debugf("updated node %s labels: %+v", name, node.Labels) +} From d69a92f3120eddf81e2dc2363703fb288ca2ca0f Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 27 Sep 2023 09:20:31 +0000 Subject: [PATCH 429/542] This bumps the base images for vulnerabilities Signed-off-by: Dan Finneran --- Dockerfile | 2 +- Dockerfile_iptables | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b3d8649b..378c0c23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.20.6-alpine3.17 as dev +FROM golang:1.20.8-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 01e236b7..00394d9d 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.19.2-alpine3.16 as dev +FROM golang:1.20.8-alpine3.18 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ @@ -11,7 +11,7 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ CGO_ENABLED=0 GOOS=linux make build -FROM alpine:3.16.2 +FROM alpine:3.18.3 # Add Certificates into the image, for anything that does API calls RUN apk add --no-cache iptables # Add kube-vip binary From 219bc19bc2c16b3efdcc2af26956dac5526b0aa8 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 28 Sep 2023 11:39:46 +0100 Subject: [PATCH 430/542] Update ci.yaml Adds Trivy scanning --- .github/workflows/ci.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c9a1dff2..23b7e525 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,3 +24,12 @@ jobs: run: make dockerx86ActionIPTables - name: e2e services run: DOCKERTAG=action make service-tests + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'plndr/kube-vip:action' + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' From 0ad1ccbf2fde02f28aa9b889568bf8c1e341f493 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 28 Sep 2023 12:38:54 +0000 Subject: [PATCH 431/542] Adds logic and debugging around fqdn endpoints Signed-off-by: Dan Finneran --- pkg/manager/watch_endpoints.go | 45 ++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index c6a69fed..fccb1411 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -3,6 +3,7 @@ package manager import ( "context" "fmt" + "strings" "sync" log "github.com/sirupsen/logrus" @@ -81,11 +82,33 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser var localendpoints []string for subset := range ep.Subsets { for address := range ep.Subsets[subset].Addresses { - log.Debugf("[endpoint] %s", ep.Subsets[subset].Addresses[address].IP) - // Check the node is populated - if ep.Subsets[subset].Addresses[address].NodeName != nil { - if id == *ep.Subsets[subset].Addresses[address].NodeName { - localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + // 1. Compare the hostname on the endpoint to the hostname + // 2. Compare the nodename on the endpoint to the hostname + // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint + + // 1. Compare the Hostname first (should be FQDN) + if id == ep.Subsets[subset].Addresses[address].Hostname { + log.Debugf("[endpoint] address: %s, hostname: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname) + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } else { + // 2. Compare the Nodename (from testing could be FQDN or short) + if ep.Subsets[subset].Addresses[address].NodeName != nil { + log.Debugf("[endpoint] address: %s, hostname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname, *ep.Subsets[subset].Addresses[address].NodeName) + if id == *ep.Subsets[subset].Addresses[address].NodeName { + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } else { + // 3. Compare to shortname + shortname, err := getShortname(id) + if err != nil { + log.Errorf("[endpoint] %v", err) + } else { + log.Debugf("[endpoint] address: %s, shortname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, shortname, *ep.Subsets[subset].Addresses[address].NodeName) + + if shortname == *ep.Subsets[subset].Addresses[address].NodeName { + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } + } + } } } } @@ -208,3 +231,15 @@ func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1. } return nil } + +// returns just the shortname (or first bit) of a FQDN +func getShortname(hostname string) (string, error) { + if len(hostname) == 0 { + return "", fmt.Errorf("unable to find shortname from %s", hostname) + } + hostParts := strings.Split(hostname, ".") + if len(hostParts) > 1 { + return hostParts[0], nil + } + return "", fmt.Errorf("unable to find shortname from %s", hostname) +} From e41abf0f88ef3556c3400abfb68572559ba1fe0a Mon Sep 17 00:00:00 2001 From: Guillaume Villena Date: Sun, 1 Oct 2023 01:01:14 +0200 Subject: [PATCH 432/542] Allow svc lock name to be configurable in arp mode. Signed-off-by: Guillaume Villena --- cmd/kube-vip.go | 1 + pkg/kubevip/config_environment.go | 6 ++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 4 ++++ pkg/kubevip/config_types.go | 3 +++ pkg/manager/manager_arp.go | 4 ++-- 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 975830d8..221fd7ab 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -134,6 +134,7 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.LoadBalancerClassName, "lbClassName", "kube-vip.io/kube-vip-class", "Name of load balancer class for kube-VIP, defaults to \"kube-vip.io/kube-vip-class\"") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index afaefbd7..0e7a338d 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -189,6 +189,12 @@ func ParseEnvironment(c *Config) error { if env != "" { c.ServiceNamespace = env } + + // Gets the leaseName for services in arp mode + env = os.Getenv(svcLeaseName) + if env != "" { + c.ServicesLeaseName = env + } } // Find vip address cidr range diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 96661231..e8ccfff5 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -136,6 +136,9 @@ const ( // svcElection enables election per Kubernetes service svcElection = "svc_election" + // svcLeaseName Name of the lease that is used for leader election for services (in arp mode) + svcLeaseName = "svc_leasename" + // lbClassOnly enables load-balancer for class "kube-vip.io/kube-vip-class" only lbClassOnly = "lb_class_only" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index d442fd85..b4882819 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -107,6 +107,10 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: svcEnable, Value: strconv.FormatBool(c.EnableServices), }, + { + Name: svcLeaseName, + Value: c.ServicesLeaseName, + }, } newEnvironment = append(newEnvironment, svc...) if c.EnableServicesElection { diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 8d4f8a35..5d8400db 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -140,6 +140,9 @@ type Config struct { // EgressWithNftables, this will use the iptables-nftables OVER iptables EgressWithNftables bool + + // ServicesLeaseName, this will set the lease name for services leader in arp mode + ServicesLeaseName string `yaml:"servicesLeaseName"` } // LeaderElection defines all of the settings for Kubernetes LeaderElection diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index ebb15ed4..0e0d54e1 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -124,12 +124,12 @@ func (sm *Manager) startARP() error { } } else { - log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, id) + log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, sm.config.ServicesLeaseName, 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{ LeaseMeta: metav1.ObjectMeta{ - Name: plunderLock, + Name: sm.config.ServicesLeaseName, Namespace: ns, }, Client: sm.clientSet.CoordinationV1(), From 36bccb723e2cc9f19b5f2e1ba38585bd27b7cfad Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 3 Oct 2023 14:47:44 +0000 Subject: [PATCH 433/542] Call fatal when interface fails Signed-off-by: Dan Finneran --- pkg/cluster/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 70463a7f..d3e31e07 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -48,7 +48,7 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co err = cluster.Network.AddIP() if err != nil { - log.Warnf("%v", err) + log.Fatalf("%v", err) } if c.EnableMetal { From 72410cc6f702b48eeaab2b69e4e4d390d9ebf4bf Mon Sep 17 00:00:00 2001 From: Guillermo Gaston Date: Tue, 3 Oct 2023 17:51:23 +0000 Subject: [PATCH 434/542] Enable unit and e2e tests in CI * Fix 2 broken tests * Fix e2e ARP tests: killing one node in a 2 CP node cluster makes etcd lose quorum. So it can't elect a new leader if the node we happen to kill was the etcd leader. * Separate unit tests, e2e tests, linter and scans in different jobs so they run concurrently. Signed-off-by: Guillermo Gaston --- .github/workflows/ci.yaml | 100 ++++++++++++++++++++++-------- .gitignore | 1 + Makefile | 5 +- pkg/kubevip/config_environment.go | 3 + pkg/manager/watcher_test.go | 6 +- testing/e2e/e2e_suite_test.go | 10 +-- testing/e2e/e2e_test.go | 3 +- 7 files changed, 93 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 23b7e525..53373bd7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,34 +2,80 @@ name: For each commit and PR on: push: pull_request: +env: + GO_VERSION: "1.20" jobs: validation: runs-on: ubuntu-latest - env: - CGO_ENABLED: 0 + name: Checks and linters steps: - - name: Init - run: sudo apt-get update && sudo apt-get install -y build-essential golint - - name: Checkout code - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: '1.20' - - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - - name: checks - run: make check - - name: test docker build (with iptables) - run: make dockerx86ActionIPTables - - name: e2e services - run: DOCKERTAG=action make service-tests - - name: Run Trivy vulnerability scanner - uses: aquasecurity/trivy-action@master - with: - image-ref: 'plndr/kube-vip:action' - format: 'table' - exit-code: '1' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' + - name: Init + run: sudo apt-get update && sudo apt-get install -y build-essential golint + - name: Install golangci-lint + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 + - name: Checkout code + uses: actions/checkout@v3 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: All checks + run: make check + unit-tests: + runs-on: ubuntu-latest + name: Unit tests + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Run tests + run: make unit-tests + e2e-tests: + runs-on: ubuntu-latest + name: E2E ARP tests + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Build image locally + run: make dockerx86Local + - name: Run tests + run: make e2e-tests + service-e2e-tests: + runs-on: ubuntu-latest + name: E2E service tests + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Build image with iptables + run: make dockerx86ActionIPTables + - name: Run tests + run: DOCKERTAG=action make service-tests + image-vul-check: + runs-on: ubuntu-latest + name: Image vulnerability scan + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Build image with iptables + run: make dockerx86ActionIPTables + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'plndr/kube-vip:action' + format: 'table' + exit-code: '1' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + diff --git a/.gitignore b/.gitignore index bea64a87..df4f3571 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .idea kube-vip +.vscode diff --git a/Makefile b/Makefile index 33e4b544..213a44fd 100644 --- a/Makefile +++ b/Makefile @@ -116,8 +116,11 @@ manifests: @./kube-vip manifest daemonset --interface eth0 --vip 192.168.0.1 --bgp --leaderElection --controlplane --services --inCluster --provider-config /etc/cloud-sa/cloud-sa.json > ./docs/manifests/$(VERSION)/kube-vip-bgp-em-ds.yaml @-rm ./kube-vip +unit-tests: + go test ./... + e2e-tests: - E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo -tags=e2e -v -p testing/e2e + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index afaefbd7..1517117b 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -11,6 +11,9 @@ import ( // ParseEnvironment - will popultate the configuration from environment variables func ParseEnvironment(c *Config) error { + if c == nil { + return nil + } // Ensure that logging is set through the environment variables env := os.Getenv(vipLogLevel) // Set default value diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index a2a18999..99149f2d 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -77,8 +77,8 @@ func TestParseNewBgpAnnotations(t *testing.T) { node.Annotations = map[string]string{ "bgp/bgp-peers-0-node-asn": "65000", "bgp/bgp-peers-0-peer-asn": "64000", - "bgp/bgp-peers-0-peer-ip": "10.0.0.254", - "bgp/bgp-peers-0-src-ip": "10.0.0.1,10.0.0.2,10.0.0.3", + "bgp/bgp-peers-0-peer-ip": "10.0.0.1,10.0.0.2,10.0.0.3", + "bgp/bgp-peers-0-src-ip": "10.0.0.254", "bgp/bgp-peers-0-bgp-pass": "cGFzc3dvcmQ=", // password } @@ -93,6 +93,8 @@ func TestParseNewBgpAnnotations(t *testing.T) { {Address: "10.0.0.3", AS: uint32(64000), Password: "password"}, } assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") + assert.Equal(t, "10.0.0.254", bgpConfig.SourceIP, "bgpConfig.SourceIP parsed incorrectly") + assert.Equal(t, "10.0.0.254", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") } diff --git a/testing/e2e/e2e_suite_test.go b/testing/e2e/e2e_suite_test.go index eb0e543b..cf054d4d 100644 --- a/testing/e2e/e2e_suite_test.go +++ b/testing/e2e/e2e_suite_test.go @@ -22,10 +22,12 @@ func TestE2E(t *testing.T) { RunSpecs(t, "E2E Suite") } -var _ = SynchronizedBeforeSuite(func() []byte { - ensureKindNetwork() - return []byte{} -}, func(_ []byte) {}) +var _ = SynchronizedBeforeSuite( + func() { + ensureKindNetwork() + }, + func() {}, +) func ensureKindNetwork() { By("checking if the Docker \"kind\" network exists") diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 714b9207..70c6db0f 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -98,7 +98,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4.yaml") - for i := 0; i < 2; i++ { + for i := 0; i < 3; i++ { clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ Role: kindconfigv1alpha4.ControlPlaneRole, ExtraMounts: []kindconfigv1alpha4.Mount{ @@ -217,6 +217,7 @@ func createKindCluster(logger log.Logger, config *v1alpha4.Cluster, clusterName Expect(provider.Create( clusterName, cluster.CreateWithV1Alpha4Config(config), + cluster.CreateWithRetain(os.Getenv("E2E_PRESERVE_CLUSTER") == "true"), // If create fails, we'll need the cluster alive to debug )).To(Succeed()) } From cbcc68e69d18bd594405f971dd9bc63d3668c752 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 4 Oct 2023 09:37:41 +0100 Subject: [PATCH 435/542] Update Makefile Bump for new release --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 213a44fd..b70a5061 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL := $(TARGET) # These will be provided to the target -VERSION := v0.6.2 +VERSION := v0.6.3 BUILD := `git rev-parse HEAD` From ae307f8cad11142da68cd1a58f0ba1c552645816 Mon Sep 17 00:00:00 2001 From: Guillermo Gaston Date: Sat, 30 Sep 2023 19:08:41 +0000 Subject: [PATCH 436/542] Add leader election using etcd as a backend This adds a new leader election mode that instead of using the kube api server to obtain a lease, it relies solely on etcd. By removing the dependency on the api server, we can use it even before the api server is up, before cluster creation. In an external etcd topology, this way we can make the api server point to the VIPs instead of to the etcd machines IPs. This configuration isolates the CP configuration from the etcd machine IPS. It's is super convenient to avoid having to roll new control plane nodes when the etcd nodes change. Signed-off-by: Guillermo Gaston --- .github/workflows/ci.yaml | 12 + .gitignore | 4 + Makefile | 7 +- cmd/kube-vip-start.go | 17 +- cmd/kube-vip.go | 7 + go.mod | 23 +- go.sum | 61 +++- pkg/cluster/clusterLeaderElection.go | 159 +++++++---- pkg/etcd/client.go | 26 ++ pkg/etcd/election.go | 226 +++++++++++++++ pkg/etcd/election_test.go | 169 +++++++++++ pkg/etcd/etcd_suite_test.go | 153 ++++++++++ pkg/kubevip/config_types.go | 23 +- pkg/manager/cluster.go | 29 ++ pkg/manager/manager.go | 2 + pkg/manager/manager_arp.go | 6 +- pkg/manager/manager_bgp.go | 6 +- testing/e2e/e2e_test.go | 134 +-------- testing/e2e/etcd/README.md | 32 +++ testing/e2e/etcd/cluster.go | 341 +++++++++++++++++++++++ testing/e2e/etcd/election_test.go | 114 ++++++++ testing/e2e/etcd/etcd_suite_test.go | 16 ++ testing/e2e/etcd/health.go | 121 ++++++++ testing/e2e/etcd/kube-etcd-vip.yaml.tmpl | 51 ++++ testing/e2e/etcd/kubelet-flags.env | 1 + testing/e2e/etcd/kubelet.yaml | 20 ++ testing/e2e/ip.go | 88 ++++++ testing/e2e/kind.go | 147 ++++++++++ testing/e2e/logger.go | 43 +++ testing/e2e/services/services.go | 1 - testing/e2e/template.go | 9 + 31 files changed, 1829 insertions(+), 219 deletions(-) create mode 100644 pkg/etcd/client.go create mode 100644 pkg/etcd/election.go create mode 100644 pkg/etcd/election_test.go create mode 100644 pkg/etcd/etcd_suite_test.go create mode 100644 pkg/manager/cluster.go create mode 100644 testing/e2e/etcd/README.md create mode 100644 testing/e2e/etcd/cluster.go create mode 100644 testing/e2e/etcd/election_test.go create mode 100644 testing/e2e/etcd/etcd_suite_test.go create mode 100644 testing/e2e/etcd/health.go create mode 100644 testing/e2e/etcd/kube-etcd-vip.yaml.tmpl create mode 100644 testing/e2e/etcd/kubelet-flags.env create mode 100644 testing/e2e/etcd/kubelet.yaml create mode 100644 testing/e2e/ip.go create mode 100644 testing/e2e/kind.go create mode 100644 testing/e2e/logger.go create mode 100644 testing/e2e/template.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 53373bd7..1525ba6e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,18 @@ jobs: go-version: ${{ env.GO_VERSION }} - name: Run tests run: make unit-tests + integration-tests: + name: Integration tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Set up Go ${{ env.GO_VERSION }} + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + - name: Run tests + run: make integration-tests e2e-tests: runs-on: ubuntu-latest name: E2E ARP tests diff --git a/.gitignore b/.gitignore index df4f3571..4d94032f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .idea kube-vip .vscode +bin +testing/e2e/etcd/certs +pkg/etcd/etcd.pid +pkg/etcd/etcd-data diff --git a/Makefile b/Makefile index b70a5061..33e3409b 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ TARGETOS=linux # Use linker flags to provide version/build settings to the target LDFLAGS=-ldflags "-s -w -X=main.Version=$(VERSION) -X=main.Build=$(BUILD) -extldflags -static" DOCKERTAG ?= $(VERSION) -REPOSITORY = plndr +REPOSITORY ?= plndr .PHONY: all build clean install uninstall fmt simplify check run e2e-tests @@ -119,8 +119,11 @@ manifests: unit-tests: go test ./... +integration-tests: + go test -tags=integration,e2e -v ./pkg/etcd + e2e-tests: - E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 94124e53..798e13a6 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -9,11 +9,13 @@ import ( ) // Start as a single node (no cluster), start as a leader in the cluster -var startConfig kubevip.Config -var startConfigLB kubevip.LoadBalancer -var startLocalPeer, startKubeConfigPath string -var startRemotePeers, startBackends []string -var inCluster bool +var ( + startConfig kubevip.Config + startConfigLB kubevip.LoadBalancer + startLocalPeer, startKubeConfigPath string + startRemotePeers, startBackends []string + inCluster bool +) func init() { // Get the configuration file @@ -65,6 +67,10 @@ var kubeVipStart = &cobra.Command{ log.Fatalln(err) } + if startConfig.LeaderElectionType == "etcd" { + log.Fatalln("Leader election with etcd not supported in start command, use manager") + } + newCluster, err := cluster.InitCluster(&startConfig, disableVIP) if err != nil { log.Fatalf("%v", err) @@ -109,6 +115,5 @@ var kubeVipStart = &cobra.Command{ } } } - }, } diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 221fd7ab..3d7010e2 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -87,6 +87,7 @@ func init() { // Clustering type (leaderElection) kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableLeaderElection, "leaderElection", false, "Use the Kubernetes leader election mechanism for clustering") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.LeaderElectionType, "leaderElectionType", "kubernetes", "Defines the backend to run the leader election: kubernetes or etcd. Defaults to kubernetes.") kubeVipCmd.PersistentFlags().StringVar(&initConfig.LeaseName, "leaseName", "plndr-cp-lock", "Name of the lease that is used for leader election") kubeVipCmd.PersistentFlags().IntVar(&initConfig.LeaseDuration, "leaseDuration", 5, "Length of time a Kubernetes leader lease can be held for") kubeVipCmd.PersistentFlags().IntVar(&initConfig.RenewDeadline, "leaseRenewDuration", 3, "Length of time a Kubernetes leader can attempt to renew its lease") @@ -139,6 +140,12 @@ func init() { // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") + // Etcd + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.CAFile, "etcdCACert", "", "Verify certificates of TLS-enabled secure servers using this CA bundle file") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.ClientCertFile, "etcdCert", "", "Identify secure client using this TLS certificate file") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.ClientKeyFile, "etcdKey", "", "Identify secure client using this TLS key file") + kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.Etcd.Endpoints, "etcdEndpoints", nil, "Etcd member endpoints") + kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) kubeVipCmd.AddCommand(kubeVipManager) diff --git a/go.mod b/go.mod index 709d42a7..399d2941 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 - github.com/onsi/ginkgo/v2 v2.11.0 + github.com/onsi/ginkgo/v2 v2.12.1 github.com/onsi/gomega v1.27.10 github.com/osrg/gobgp/v3 v3.17.0 github.com/packethost/packngo v0.30.0 @@ -21,7 +21,12 @@ require ( github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/sys v0.10.0 + go.etcd.io/etcd/api/v3 v3.5.9 + go.etcd.io/etcd/client/pkg/v3 v3.5.9 + go.etcd.io/etcd/client/v3 v3.5.9 + go.uber.org/zap v1.21.0 + golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 + golang.org/x/sys v0.12.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 k8s.io/api v0.27.4 k8s.io/apimachinery v0.27.4 @@ -36,6 +41,8 @@ require ( github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect @@ -88,14 +95,16 @@ require ( github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.1.0 // indirect - golang.org/x/tools v0.9.3 // indirect + golang.org/x/tools v0.13.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect diff --git a/go.sum b/go.sum index 43e40d9b..8c70354c 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -60,6 +62,10 @@ github.com/cloudflare/ipvs v0.9.1/go.mod h1:5H4icNJZ8T4H7bg0/THRew5BbNOkDgl2RC1t github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -107,6 +113,7 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -281,8 +288,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= +github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= @@ -359,13 +366,30 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -374,8 +398,8 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -386,6 +410,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 h1:9k5exFQKQglLo+RoP+4zMjOFE14P6+vyR0baDAi0Rcs= +golang.org/x/exp v0.0.0-20231005195138-3e424a577f31/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -411,7 +437,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -449,6 +475,7 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -456,8 +483,8 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -527,8 +554,10 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -541,11 +570,11 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -554,8 +583,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -610,9 +639,10 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -737,6 +767,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index c4f44bff..9d8501f3 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -12,6 +12,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/kube-vip/kube-vip/pkg/bgp" "github.com/kube-vip/kube-vip/pkg/equinixmetal" + "github.com/kube-vip/kube-vip/pkg/etcd" "github.com/kube-vip/kube-vip/pkg/k8s" "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/kube-vip/kube-vip/pkg/loadbalancer" @@ -19,6 +20,7 @@ import ( "github.com/packethost/packngo" log "github.com/sirupsen/logrus" + clientv3 "go.etcd.io/etcd/client/v3" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,6 +37,8 @@ type Manager struct { KubernetesClient *kubernetes.Clientset // This channel is used to signal a shutdown SignalChan chan os.Signal + + EtcdClient *clientv3.Client } // NewManager will create a new managing object @@ -79,20 +83,6 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * log.Infof("Beginning cluster membership, namespace [%s], lock name [%s], id [%s]", c.Namespace, c.LeaseName, 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{ - LeaseMeta: metav1.ObjectMeta{ - Name: c.LeaseName, - Namespace: c.Namespace, - Annotations: c.LeaseAnnotations, - }, - Client: sm.KubernetesClient.CoordinationV1(), - LockConfig: resourcelock.ResourceLockConfig{ - Identity: id, - }, - } - // use a Go context so we can tell the leaderelection code when we // want to step down ctx, cancel := context.WithCancel(context.Background()) @@ -177,6 +167,89 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * } } + run := &runConfig{ + config: c, + leaseID: id, + sm: sm, + onStartedLeading: func(ctx context.Context) { + // 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) + } + }, + onStoppedLeading: func() { + // we can do cleanup here + log.Info("This node is becoming a follower within the cluster") + + // Stop the dns context + cancelDNS() + // Stop the Arp context if it is running + cancelArp() + + // Stop the BGP server + if bgpServer != nil { + err := bgpServer.Close() + if err != nil { + log.Warnf("%v", err) + } + } + + err := cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) + } + + log.Fatal("lost leadership, restarting kube-vip") + }, + onNewLeader: func(identity string) { + // we're notified when new leader elected + log.Infof("Node [%s] is assuming leadership of the cluster", identity) + }, + } + + switch c.LeaderElectionType { + case "kubernetes", "": + cluster.runKubernetesLeaderElectionOrDie(ctx, run) + case "etcd": + cluster.runEtcdLeaderElectionOrDie(ctx, run) + default: + log.Info(fmt.Sprintf("LeaderElectionMode %s not supported, exiting", c.LeaderElectionType)) + } + + return nil +} + +type runConfig struct { + config *kubevip.Config + leaseID string + sm *Manager + + // onStartedLeading is called when this member starts leading. + onStartedLeading func(context.Context) + // onStoppedLeading is called when this member stops leading. + onStoppedLeading func() + // onNewLeader is called when the client observes a leader that is + // not the previously observed leader. This includes the first observed + // leader when the client starts. + onNewLeader func(identity string) +} + +func (cluster *Cluster) runKubernetesLeaderElectionOrDie(ctx context.Context, run *runConfig) { + // 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{ + LeaseMeta: metav1.ObjectMeta{ + Name: run.config.LeaseName, + Namespace: run.config.Namespace, + Annotations: run.config.LeaseAnnotations, + }, + Client: run.sm.KubernetesClient.CoordinationV1(), + LockConfig: resourcelock.ResourceLockConfig{ + Identity: run.leaseID, + }, + } + // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -187,49 +260,29 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * // get elected before your background loop finished, violating // the stated goal of the lease. ReleaseOnCancel: true, - LeaseDuration: time.Duration(c.LeaseDuration) * time.Second, - RenewDeadline: time.Duration(c.RenewDeadline) * time.Second, - RetryPeriod: time.Duration(c.RetryPeriod) * time.Second, + LeaseDuration: time.Duration(run.config.LeaseDuration) * time.Second, + RenewDeadline: time.Duration(run.config.RenewDeadline) * time.Second, + RetryPeriod: time.Duration(run.config.RetryPeriod) * time.Second, Callbacks: leaderelection.LeaderCallbacks{ - OnStartedLeading: func(ctx context.Context) { - // 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) - } - }, - OnStoppedLeading: func() { - // we can do cleanup here - log.Info("This node is becoming a follower within the cluster") - - // Stop the dns context - cancelDNS() - // Stop the Arp context if it is running - cancelArp() - - // Stop the BGP server - if bgpServer != nil { - err = bgpServer.Close() - if err != nil { - log.Warnf("%v", err) - } - } - - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - - log.Fatal("lost leadership, restarting kube-vip") - }, - OnNewLeader: func(identity string) { - // we're notified when new leader elected - log.Infof("Node [%s] is assuming leadership of the cluster", identity) - }, + OnStartedLeading: run.onStartedLeading, + OnStoppedLeading: run.onStoppedLeading, + OnNewLeader: run.onNewLeader, }, }) +} - return nil +func (cluster *Cluster) runEtcdLeaderElectionOrDie(ctx context.Context, run *runConfig) { + etcd.RunElectionOrDie(ctx, &etcd.LeaderElectionConfig{ + EtcdConfig: etcd.ClientConfig{Client: run.sm.EtcdClient}, + Name: run.config.LeaseName, + MemberID: run.leaseID, + LeaseDurationSeconds: int64(run.config.LeaseDuration), + Callbacks: etcd.LeaderCallbacks{ + OnStartedLeading: run.onStartedLeading, + OnStoppedLeading: run.onStoppedLeading, + OnNewLeader: run.onNewLeader, + }, + }) } func (sm *Manager) NodeWatcher(lb *loadbalancer.IPVSLoadBalancer, port int) error { diff --git a/pkg/etcd/client.go b/pkg/etcd/client.go new file mode 100644 index 00000000..bc0d7540 --- /dev/null +++ b/pkg/etcd/client.go @@ -0,0 +1,26 @@ +package etcd + +import ( + "go.etcd.io/etcd/client/pkg/v3/transport" + clientv3 "go.etcd.io/etcd/client/v3" + + "github.com/kube-vip/kube-vip/pkg/kubevip" +) + +func NewClient(c *kubevip.Config) (*clientv3.Client, error) { + tlsInfo := transport.TLSInfo{ + TrustedCAFile: c.Etcd.CAFile, + CertFile: c.Etcd.ClientCertFile, + KeyFile: c.Etcd.ClientKeyFile, + } + + clientTLS, err := tlsInfo.ClientConfig() + if err != nil { + return nil, err + } + + return clientv3.New(clientv3.Config{ + Endpoints: c.Etcd.Endpoints, + TLS: clientTLS, + }) +} diff --git a/pkg/etcd/election.go b/pkg/etcd/election.go new file mode 100644 index 00000000..a9b5d425 --- /dev/null +++ b/pkg/etcd/election.go @@ -0,0 +1,226 @@ +package etcd + +import ( + "context" + "hash/fnv" + "time" + + "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" +) + +// LeaderElectionConfig allows to configure the leader election params. +type LeaderElectionConfig struct { + // EtcdConfig contains the client to connect to the etcd cluster. + EtcdConfig ClientConfig + + // Name uniquely identifies this leader election. All members of the same election + // should use the same value here. + Name string + + // MemberID identifies uniquely this contestant from other in the leader election. + // It will be converted to an int64 using a hash, so theoretically collisions are possible + // when using a string. If you want to guarantee safety, us MemberUniqueID to specify a unique + // int64 directly. + // If two processes start a leader election using the same MemberID, one of them will + // fail. + MemberID string + + // MemberUniqueID is the int equivalent to MemberID that allows to override the default conversion + // from string to int using hashing. + MemberUniqueID *int64 + + // LeaseDurationSeconds is the duration that non-leader candidates will + // wait to force acquire leadership. + // This is just a request to the etcd server but it's not guaranteed, the server + // might decide to make the duration longer. + LeaseDurationSeconds int64 + + // Callbacks are callbacks that are triggered during certain lifecycle + // events of the LeaderElector + Callbacks LeaderCallbacks +} + +// LeaderCallbacks are callbacks that are triggered during certain +// lifecycle events of the election. +type LeaderCallbacks struct { + // OnStartedLeading is called when this member starts leading. + OnStartedLeading func(context.Context) + // OnStoppedLeading is called when this member stops leading. + OnStoppedLeading func() + // OnNewLeader is called when the client observes a leader that is + // not the previously observed leader. This includes the first observed + // leader when the client starts. + OnNewLeader func(identity string) +} + +// ClientConfig contains the client to connect to the etcd cluster. +type ClientConfig struct { + Client *clientv3.Client +} + +// RunElectionOrDie behaves the same way as RunElection but panics if there is an error. +func RunElectionOrDie(ctx context.Context, config *LeaderElectionConfig) { + if err := RunElection(ctx, config); err != nil { + panic(err) + } +} + +// RunElection starts a client with the provided config or panics. +// RunElection blocks until leader election loop is +// stopped by ctx or it has stopped holding the leader lease. +func RunElection(ctx context.Context, config *LeaderElectionConfig) error { + var memberID int64 + if config.MemberUniqueID != nil { + memberID = *config.MemberUniqueID + } else { + h := fnv.New64a() + if _, err := h.Write(append([]byte(config.Name), []byte(config.MemberID)...)); err != nil { + return err + } + memberID = int64(h.Sum64()) + } + + ttl := config.LeaseDurationSeconds + r := &pb.LeaseGrantRequest{TTL: ttl, ID: memberID} + lease, err := clientv3.RetryLeaseClient( + config.EtcdConfig.Client, + ).LeaseGrant(ctx, r) + if err != nil { + return errors.Wrap(err, "creating lease") + } + + leaseID := clientv3.LeaseID(lease.ID) + + s, err := concurrency.NewSession( + config.EtcdConfig.Client, + concurrency.WithTTL(int(lease.TTL)), + concurrency.WithLease(leaseID), + ) + if err != nil { + return err + } + + election := concurrency.NewElection(s, config.Name) + + m := &member{ + client: config.EtcdConfig.Client, + election: election, + callbacks: config.Callbacks, + memberID: config.MemberID, + weAreTheLeader: make(chan struct{}, 1), + leaseTTL: lease.TTL, + } + + go m.tryToBeLeader(ctx) + m.watchLeaderChanges(ctx) + + return nil +} + +type member struct { + key string + client *clientv3.Client + election *concurrency.Election + isLeader bool + currentLeaderKey string + callbacks LeaderCallbacks + memberID string + weAreTheLeader chan struct{} + leaseTTL int64 +} + +func (m *member) watchLeaderChanges(ctx context.Context) { + observeCtx, observeCancel := context.WithCancel(ctx) + defer observeCancel() + changes := m.election.Observe(observeCtx) + +watcher: + for { + select { + case <-ctx.Done(): + break watcher + case <-m.weAreTheLeader: + + 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) + case response := <-changes: + log.Debugf("[%s] Leader Changes: %+v\n", m.memberID, 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 + // just before the response channel is closed or the context is cancel + // In that case, just continue and let one of those two things happen + continue + } + newLeaderKey := response.Kvs[0].Key + if m.isLeader && m.key != string(newLeaderKey) { + // We stopped being leaders + + // exit the loop, so we cancel the observe context so we stop watching + // for new leaders. That will close the channel and make this function exit, + // which also makes the routine to finish and RunElection returns + break watcher + } + + if m.currentLeaderKey != string(newLeaderKey) { + // we observed a leader, this could be us or someone else + m.currentLeaderKey = string(newLeaderKey) + m.callbacks.OnNewLeader(string(response.Kvs[0].Value)) + } + } + } + + // If we are here, either we have stopped being leaders or we lost the watcher + // Make sure we call OnStoppedLeading if we were the leader. + if m.isLeader { + m.callbacks.OnStoppedLeading() + } + + log.Debugf("[%s] Exiting watcher\n", 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) + // 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) + } + return + // TODO: what to do here? + // We probably want watchLeaderChanges to exit as well, since Run + // is expecting us to try to become the leader, but if we are here, + // we won't. So if we don't panic, we need to signal it somehow + } + + // Inform the observer that we are the leader as soon as possible, + // so it can detect if we stop being it + m.weAreTheLeader <- struct{}{} + + // Once we are the leader, start the routine to resign if context is canceled + go m.resignOnCancel(ctx) + + // After becoming the leader, we wait for at least a lease TTL to wait for + // 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) + time.Sleep(time.Second * time.Duration(m.leaseTTL)) + + // We are the leader, execute our code + m.callbacks.OnStartedLeading(ctx) + + // Here the routine dies if OnStartedLeading doesn't block, there is nothing else to do +} + +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) + } +} diff --git a/pkg/etcd/election_test.go b/pkg/etcd/election_test.go new file mode 100644 index 00000000..1ecf0e54 --- /dev/null +++ b/pkg/etcd/election_test.go @@ -0,0 +1,169 @@ +//go:build integration +// +build integration + +package etcd_test + +import ( + "context" + "log" + "math/rand" + "sync" + "testing" + "time" + + "github.com/kube-vip/kube-vip/pkg/etcd" + . "github.com/onsi/gomega" + clientv3 "go.etcd.io/etcd/client/v3" + "go.uber.org/zap" +) + +func TestRunElectionWithMemberIDCollision(t *testing.T) { + t.Parallel() + g := NewWithT(t) + ctx := context.Background() + cli := client(g) + defer cli.Close() + + electionName := randomElectionNameForTest("memberIDConflict") + log.Printf("Election name %s\n", electionName) + memberCtx, cancelMember1 := context.WithCancel(ctx) + config := &etcd.LeaderElectionConfig{ + EtcdConfig: etcd.ClientConfig{ + Client: cli, + }, + Name: electionName, + MemberID: "my-host", + LeaseDurationSeconds: 1, + Callbacks: etcd.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + log.Println("I'm the leader!!!!") + log.Println("Renouncing as leader by canceling context") + cancelMember1() + }, + OnNewLeader: func(identity string) { + log.Printf("New leader: %s\n", identity) + }, + OnStoppedLeading: func() { + log.Println("I'm not the leader anymore") + }, + }, + } + + wg := &sync.WaitGroup{} + wg.Add(2) + + go func() { + defer wg.Done() + g.Expect(etcd.RunElection(memberCtx, config)).To(Succeed()) + }() + + go func() { + defer wg.Done() + time.Sleep(time.Millisecond * 50) // make sure the first one becomes leader + g.Expect(etcd.RunElection(ctx, config)).Should(MatchError(ContainSubstring("creating lease"))) + }() + + wg.Wait() +} + +func TestRunElectionWithTwoMembersAndReelection(t *testing.T) { + t.Parallel() + g := NewWithT(t) + ctx := context.Background() + cli := client(g) + defer cli.Close() + + cliMember1 := client(g) + defer cliMember1.Close() + + electionName := randomElectionNameForTest("steppingDown") + configBase := etcd.LeaderElectionConfig{ + EtcdConfig: etcd.ClientConfig{ + Client: cli, + }, + Name: electionName, + LeaseDurationSeconds: 1, + } + + member1Ctx, _ := context.WithCancel(ctx) + member2Ctx, cancelMember2 := context.WithCancel(ctx) + + config1 := configBase + config1.EtcdConfig.Client = cliMember1 + config1.MemberID = "my-host" + uniqueID := rand.Int63() + config1.MemberUniqueID = &uniqueID + config1.Callbacks = baseCallbacksForName(config1.MemberID) + config1.Callbacks.OnStartedLeading = func(_ context.Context) { + log.Println("I'm my-host, the new leader!!!!") + log.Println("Loosing the leadership on purpose by stopping renewing the lease") + g.Expect(cliMember1.Lease.Close()).To(Succeed()) + log.Println("Member1 leases closed") + } + + config2 := configBase + config2.MemberID = "my-other-host" + config2.Callbacks = baseCallbacksForName(config2.MemberID) + config2.Callbacks.OnStartedLeading = func(_ context.Context) { + log.Println("I'm my-other-host, the new leader!!!!") + log.Println("Renouncing as leader by canceling context") + cancelMember2() + } + + wg := &sync.WaitGroup{} + wg.Add(2) + + go func() { + defer wg.Done() + g.Expect(etcd.RunElection(member1Ctx, &config1)).To(Succeed()) + log.Println("Member1 routine done") + }() + + go func() { + defer wg.Done() + time.Sleep(time.Millisecond * 50) // Make sure member1 becomes leader + g.Expect(etcd.RunElection(member2Ctx, &config2)).To(Succeed()) + log.Println("Member2 routine done") + }() + + wg.Wait() +} + +func baseCallbacksForName(name string) etcd.LeaderCallbacks { + return etcd.LeaderCallbacks{ + OnStartedLeading: func(ctx context.Context) { + log.Printf("[%s] I'm the new leader!!!!\n", name) + }, + OnNewLeader: func(identity string) { + log.Printf("[%s] New leader: %s\n", name, identity) + }, + OnStoppedLeading: func() { + log.Printf("[%s] I'm not the leader anymore\n", name) + }, + } +} + +func randomElectionNameForTest(name string) string { + return name + "-" + randomString(6) +} + +const charSet = "0123456789abcdefghijklmnopqrstuvwxyz" + +var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) + +func randomString(n int) string { + result := make([]byte, n) + for i := range result { + result[i] = charSet[rnd.Intn(len(charSet))] + } + return string(result) +} + +func client(g Gomega) *clientv3.Client { + c, err := clientv3.New(clientv3.Config{ + Endpoints: []string{"localhost:2379"}, + Logger: zap.NewNop(), + }) + g.Expect(err).NotTo(HaveOccurred()) + return c +} diff --git a/pkg/etcd/etcd_suite_test.go b/pkg/etcd/etcd_suite_test.go new file mode 100644 index 00000000..0842d845 --- /dev/null +++ b/pkg/etcd/etcd_suite_test.go @@ -0,0 +1,153 @@ +//go:build integration +// +build integration + +package etcd_test + +import ( + "context" + "fmt" + "log" + "os" + "os/exec" + "path/filepath" + "strconv" + "testing" + "time" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + etcdVersion = "v3.5.9" + etcdBinDir = "bin" + etcdBinPath = etcdBinDir + "/etcd" + downloadURL = "https://storage.googleapis.com/etcd" + tmpDownloadFile = "etcd.tar.gz" + pidFile = "etcd.pid" +) + +func TestMain(m *testing.M) { + logrus.SetLevel(logrus.DebugLevel) + ctx := context.Background() + expectSuccess(startEtcd(ctx), "starting etcd") + + os.Exit(runTestsWithCleanup(m, func() { + expectSuccess(stopEtcd(), "stopping etcd") + })) +} + +func runTestsWithCleanup(m *testing.M, cleanup func()) int { + defer cleanup() + return m.Run() +} + +func expectSuccess(err error, msg string) { + if err != nil { + log.Fatalf("%s: %s\n", msg, err) + } +} + +func startEtcd(ctx context.Context) error { + if _, err := os.Stat(pidFile); err == nil { + log.Println("Etcd already running, reusing") + return nil + } + + etcdPath, err := installEtcd(ctx) + if err != nil { + errors.Wrap(err, "installing etcd for tests") + } + + etcdCmd := exec.Command(etcdPath, "--data-dir", "./etcd-data") + if os.Getenv("ETCD_SERVER_LOGS") == "true" { + log.Println("Enabling etcd server logs") + etcdCmd.Stdout = os.Stdout + etcdCmd.Stderr = os.Stderr + } + log.Println("Starting etcd") + if err := etcdCmd.Start(); err != nil { + errors.Wrap(err, "starting etcd for tests") + } + + if err := os.WriteFile(pidFile, []byte(strconv.Itoa(etcdCmd.Process.Pid)), 0o600); err != nil { + return err + } + + log.Println("Waiting for etcd to be up") + time.Sleep(time.Second) + + return nil +} + +func installEtcd(ctx context.Context) (string, error) { + projectRoot, err := filepath.Abs("../../") + if err != nil { + return "", err + } + binDir := filepath.Join(projectRoot, etcdBinDir) + etcdPath := filepath.Join(projectRoot, etcdBinPath) + + if _, err := os.Stat(etcdPath); err == nil { + log.Println("Etcd already installed, skipping") + return etcdPath, nil + } + + if err := os.MkdirAll(binDir, 0o755); err != nil { + return "", err + } + + download := fmt.Sprintf("%s/%s/etcd-%s-linux-amd64.tar.gz", downloadURL, etcdVersion, etcdVersion) + + // Hacky to run bash, but simplifies this code a lot + cmd := fmt.Sprintf("curl -sL %s | tar -xzvf - -C %s --strip-components=1", download, binDir) + out, err := exec.CommandContext(ctx, "bash", "-c", cmd).CombinedOutput() + if err != nil { + return "", errors.Wrapf(err, "downloading etcd: %s", string(out)) + } + + return etcdPath, nil +} + +func stopEtcd() error { + if os.Getenv("REUSE_ETCD") == "true" { + log.Println("REUSE_ETCD=true, leaving etcd running") + return nil + } + + if _, err := os.Stat(pidFile); os.IsNotExist(err) { + log.Println("Etcd pid file doesn't exit, skipping cleanup") + return nil + } + + dat, err := os.ReadFile(pidFile) + if err != nil { + return err + } + pid, err := strconv.Atoi(string(dat)) + if err != nil { + return err + } + + etcdProcess, err := os.FindProcess(pid) + if err != nil { + return err + } + + log.Println("Stopping etcd") + if err := etcdProcess.Kill(); err != nil { + return errors.Wrap(err, "Failed stopping etcd") + } + + log.Println("Deleting etcd data") + if err := os.RemoveAll("./etcd-data"); err != nil { + return errors.Wrap(err, "deleting etcd data") + } + + log.Println("Deleting etcd pid file") + if err := os.RemoveAll(pidFile); err != nil { + return errors.Wrap(err, "deleting pid file") + } + + return nil +} diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 5d8400db..acdb9f7b 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -50,8 +50,15 @@ type Config struct { // Annotations will define if we're going to wait and lookup configuration from Kubernetes node annotations Annotations string - // LeaderElection defines the settings around Kubernetes LeaderElection - LeaderElection + // LeaderElectionType defines the backend to run the leader election: kubernetes or etcd. Defaults to kubernetes. + // Etcd doesn't support load balancer mode (EnableLoadBalancer=true) or any other feature that depends on the kube-api server. + LeaderElectionType string `yaml:"leaderElectionType"` + + // KubernetesLeaderElection defines the settings around Kubernetes KubernetesLeaderElection + KubernetesLeaderElection + + // Etcd defines all the settings for the etcd client. + Etcd Etcd // AddPeersAsBackends, this will automatically add RAFT peers as backends to a loadbalancer AddPeersAsBackends bool `yaml:"addPeersAsBackends"` @@ -145,8 +152,8 @@ type Config struct { ServicesLeaseName string `yaml:"servicesLeaseName"` } -// LeaderElection defines all of the settings for Kubernetes LeaderElection -type LeaderElection struct { +// KubernetesLeaderElection defines all of the settings for Kubernetes KubernetesLeaderElection +type KubernetesLeaderElection struct { // EnableLeaderElection will use the Kubernetes leader election algorithm EnableLeaderElection bool `yaml:"enableLeaderElection"` @@ -166,6 +173,14 @@ type LeaderElection struct { LeaseAnnotations map[string]string } +// Etcd defines all the settings for the etcd client. +type Etcd struct { + CAFile string + ClientCertFile string + ClientKeyFile string + Endpoints []string +} + // LoadBalancer contains the configuration of a load balancing instance type LoadBalancer struct { // Name of a LoadBalancer diff --git a/pkg/manager/cluster.go b/pkg/manager/cluster.go new file mode 100644 index 00000000..da2222de --- /dev/null +++ b/pkg/manager/cluster.go @@ -0,0 +1,29 @@ +package manager + +import ( + "github.com/pkg/errors" + + "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/etcd" +) + +func initClusterManager(sm *Manager) (*cluster.Manager, error) { + m := &cluster.Manager{ + SignalChan: sm.signalChan, + } + + switch sm.config.LeaderElectionType { + case "kubernetes", "": + m.KubernetesClient = sm.clientSet + case "etcd": + client, err := etcd.NewClient(sm.config) + if err != nil { + return nil, err + } + m.EtcdClient = client + default: + return nil, errors.Errorf("invalid LeaderElectionMode %s not supported", sm.config.LeaderElectionType) + } + + return m, nil +} diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index d9998bf6..fdec7d73 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -67,6 +67,8 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") switch { + case config.LeaderElectionType == "etcd": + // Do nothing, we don't construct a k8s client for etcd leader election case fileExists(adminConfigPath): if config.EnableControlPlane { // If this is a control plane host it will likely have started as a static pod or won't have the diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 0e0d54e1..11dc88f2 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -47,9 +47,9 @@ func (sm *Manager) startARP() error { return err } - clusterManager := &cluster.Manager{ - KubernetesClient: sm.clientSet, - SignalChan: sm.signalChan, + clusterManager, err := initClusterManager(sm) + if err != nil { + return err } go func() { diff --git a/pkg/manager/manager_bgp.go b/pkg/manager/manager_bgp.go index bb9cd6cb..edc2d8db 100644 --- a/pkg/manager/manager_bgp.go +++ b/pkg/manager/manager_bgp.go @@ -103,9 +103,9 @@ func (sm *Manager) startBGP() error { return err } - clusterManager := &cluster.Manager{ - KubernetesClient: sm.clientSet, - SignalChan: sm.signalChan, + clusterManager, err := initClusterManager(sm) + if err != nil { + return err } go func() { diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 70c6db0f..1de6d5f7 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -4,14 +4,10 @@ package e2e_test import ( - "bufio" "bytes" "crypto/tls" - "encoding/binary" "fmt" - "io" "io/ioutil" - "net" "net/http" "os" "os/exec" @@ -24,20 +20,15 @@ import ( "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" "sigs.k8s.io/kind/pkg/cluster" - "sigs.k8s.io/kind/pkg/cmd" - load "sigs.k8s.io/kind/pkg/cmd/kind/load/docker-image" "sigs.k8s.io/kind/pkg/log" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/format" "github.com/onsi/gomega/gexec" -) -type kubevipManifestValues struct { - ControlPlaneVIP string - ImagePath string -} + "github.com/kube-vip/kube-vip/testing/e2e" +) var _ = Describe("kube-vip broadcast neighbor", func() { var ( @@ -50,7 +41,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { BeforeEach(func() { klog.SetOutput(GinkgoWriter) - logger = TestLogger{} + logger = e2e.TestLogger{} imagePath = os.Getenv("E2E_IMAGE_PATH") @@ -115,9 +106,9 @@ var _ = Describe("kube-vip broadcast neighbor", func() { defer manifestFile.Close() - ipv4VIP = generateIPv4VIP() + ipv4VIP = e2e.GenerateIPv4VIP() - Expect(kubeVIPManifestTemplate.Execute(manifestFile, kubevipManifestValues{ + Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ ControlPlaneVIP: ipv4VIP, ImagePath: imagePath, })).To(Succeed()) @@ -128,7 +119,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { createKindCluster(logger, &clusterConfig, clusterName) By(withTimestamp("loading local docker image to kind cluster")) - loadDockerImageToKind(logger, imagePath, clusterName) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv4 VIP")) // Allow enough time for control plane nodes to load the docker image and @@ -173,14 +164,14 @@ var _ = Describe("kube-vip broadcast neighbor", func() { }) } - ipv6VIP = generateIPv6VIP() + ipv6VIP = e2e.GenerateIPv6VIP() manifestFile, err := os.Create(manifestPath) Expect(err).NotTo(HaveOccurred()) defer manifestFile.Close() - Expect(kubeVIPManifestTemplate.Execute(manifestFile, kubevipManifestValues{ + Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ ControlPlaneVIP: ipv6VIP, ImagePath: imagePath, })).To(Succeed()) @@ -191,7 +182,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { createKindCluster(logger, &clusterConfig, clusterName) By(withTimestamp("loading local docker image to kind cluster")) - loadDockerImageToKind(logger, imagePath, clusterName) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) // Allow enough time for control plane nodes to load the docker image and @@ -221,12 +212,6 @@ func createKindCluster(logger log.Logger, config *v1alpha4.Cluster, clusterName )).To(Succeed()) } -func loadDockerImageToKind(logger log.Logger, imagePath string, clusterName string) { - loadImageCmd := load.NewCommand(logger, cmd.StandardIOStreams()) - loadImageCmd.SetArgs([]string{"--name", clusterName, imagePath}) - Expect(loadImageCmd.Execute()).To(Succeed()) -} - func assertControlPlaneIsRoutable(controlPlaneVIP string, transportTimeout, eventuallyTimeout time.Duration) { if strings.Contains(controlPlaneVIP, ":") { controlPlaneVIP = fmt.Sprintf("[%s]", controlPlaneVIP) @@ -281,104 +266,3 @@ func killLeader(leaderIPAddr string, clusterName string) { func withTimestamp(text string) string { return fmt.Sprintf("%s: %s", time.Now(), text) } - -func getKindNetworkSubnetCIDRs() []string { - cmd := exec.Command( - "docker", "inspect", "kind", - "--format", `{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}`, - ) - cmdOut := new(bytes.Buffer) - cmd.Stdout = cmdOut - Expect(cmd.Run()).To(Succeed(), "The Docker \"kind\" network was not found.") - reader := bufio.NewReader(cmdOut) - - cidrs := []string{} - for { - line, readErr := reader.ReadString('\n') - if readErr != nil && readErr != io.EOF { - Expect(readErr).NotTo(HaveOccurred(), "Error finding subnet CIDRs in the Docker \"kind\" network") - } - - cidrs = append(cidrs, strings.TrimSpace(line)) - if readErr == io.EOF { - break - } - } - - return cidrs -} - -func generateIPv4VIP() string { - cidrs := getKindNetworkSubnetCIDRs() - - for _, cidr := range cidrs { - ip, ipNet, parseErr := net.ParseCIDR(cidr) - Expect(parseErr).NotTo(HaveOccurred()) - - if ip.To4() != nil { - mask := binary.BigEndian.Uint32(ipNet.Mask) - start := binary.BigEndian.Uint32(ipNet.IP) - end := (start & mask) | (^mask) - - chosenVIP := make([]byte, 4) - binary.BigEndian.PutUint32(chosenVIP, end-5) - return net.IP(chosenVIP).String() - } - } - Fail("Could not find any IPv4 CIDRs in the Docker \"kind\" network") - return "" -} - -func generateIPv6VIP() string { - cidrs := getKindNetworkSubnetCIDRs() - - for _, cidr := range cidrs { - ip, ipNet, parseErr := net.ParseCIDR(cidr) - Expect(parseErr).NotTo(HaveOccurred()) - - if ip.To4() == nil { - lowerMask := binary.BigEndian.Uint64(ipNet.Mask[8:]) - lowerStart := binary.BigEndian.Uint64(ipNet.IP[8:]) - lowerEnd := (lowerStart & lowerMask) | (^lowerMask) - - chosenVIP := make([]byte, 16) - // Copy upper half into chosenVIP - copy(chosenVIP, ipNet.IP[0:8]) - // Copy lower half into chosenVIP - binary.BigEndian.PutUint64(chosenVIP[8:], lowerEnd-5) - return net.IP(chosenVIP).String() - } - } - Fail("Could not find any IPv6 CIDRs in the Docker \"kind\" network") - return "" -} - -type TestLogger struct{} - -func (t TestLogger) Warnf(format string, args ...interface{}) { - klog.Warningf(format, args...) -} - -func (t TestLogger) Warn(message string) { - klog.Warning(message) -} - -func (t TestLogger) Error(message string) { - klog.Error(message) -} - -func (t TestLogger) Errorf(format string, args ...interface{}) { - klog.Errorf(format, args...) -} - -func (t TestLogger) V(level log.Level) log.InfoLogger { - return TestInfoLogger{Verbose: klog.V(klog.Level(level))} -} - -type TestInfoLogger struct { - klog.Verbose -} - -func (t TestInfoLogger) Info(message string) { - t.Verbose.Info(message) -} diff --git a/testing/e2e/etcd/README.md b/testing/e2e/etcd/README.md new file mode 100644 index 00000000..d7e0f3c5 --- /dev/null +++ b/testing/e2e/etcd/README.md @@ -0,0 +1,32 @@ +# Running etcd Tests +## Prerequisites: +* Docker + +If you want to use an image that only exists in your local docker cache, use this env var (modify registry and tag accordingly): +```sh +export E2E_IMAGE_PATH=plndr/kube-vip:v0.6.2 +``` + +If you want to preserve the etcd nodes after a test run, use the following: +```sh +export E2E_PRESERVE_CLUSTER=true +``` + +Note that you'll need to delete them before being able to run the test again, this is only for debugging. You can use `kind delete cluster` or just `docker rm` the containers. + +Tu run the tests: +```sh +ginkgo -vv --tags=e2e testing/e2e/etcd + +``` + +The E2E tests: +1. Start 3 kind nodes (using docker) +2. Load the local docker image into kind +3. Init the etcd cluster and join all nodes +4. Verify the etcd API can be accessed through the VIP + 1. This proves leader election through etcd in kube-vip is working. +5. Removes the first node (which is probably the VIP leader) +4. Verify the etcd API can be accessed through the VIP + +> Note: this has only been tested on Linux but it might work on Mac \ No newline at end of file diff --git a/testing/e2e/etcd/cluster.go b/testing/e2e/etcd/cluster.go new file mode 100644 index 00000000..0cf68673 --- /dev/null +++ b/testing/e2e/etcd/cluster.go @@ -0,0 +1,341 @@ +//go:build e2e +// +build e2e + +package etcd + +import ( + "context" + "path/filepath" + "strings" + "time" + + . "github.com/onsi/gomega" + "go.etcd.io/etcd/client/pkg/v3/transport" + clientv3 "go.etcd.io/etcd/client/v3" + "golang.org/x/exp/slices" + kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/kind/pkg/cluster" + "sigs.k8s.io/kind/pkg/cluster/nodes" + "sigs.k8s.io/kind/pkg/cluster/nodeutils" + + "github.com/kube-vip/kube-vip/testing/e2e" +) + +type ClusterSpec struct { + Nodes int + Name string + VIP string + KubeVIPImage string + KubeVIPpManifestPath string + KubeletManifestPath string + KubeletFlagsPath string + EtcdCertsFolder string + Logger e2e.TestLogger +} + +type Cluster struct { + *ClusterSpec + Nodes []nodes.Node + + provider *cluster.Provider +} + +func CreateCluster(ctx context.Context, spec *ClusterSpec) *Cluster { + c := &Cluster{ + ClusterSpec: spec, + } + + c.provider = cluster.NewProvider( + cluster.ProviderWithLogger(spec.Logger), + cluster.ProviderWithDocker(), + ) + + c.Logger.Printf("Creating kind nodes") + c.initKindCluster() + + c.Logger.Printf("Loading kube-vip image into nodes") + e2e.LoadDockerImageToKind(spec.Logger, spec.KubeVIPImage, spec.Name) + + c.Logger.Printf("Starting etcd cluster") + c.initEtcd(ctx) + + c.Logger.Printf("Checking 1 node etcd is available through VIP") + c.VerifyEtcdThroughVIP(ctx, 15*time.Second) + + c.Logger.Printf("Adding the rest of the nodes to the etcd cluster") + c.joinRestOfNodes(ctx) + + c.Logger.Printf("Checking health for all nodes") + for _, node := range c.Nodes { + c.expectEtcdNodeHealthy(ctx, node, 15*time.Second) + } + + c.Logger.Printf("Checking %d nodes etcd is available through VIP", c.ClusterSpec.Nodes) + c.VerifyEtcdThroughVIP(ctx, 15*time.Second) + + return c +} + +func (c *Cluster) initKindCluster() { + kindCluster := &kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv4Family, + }, + } + + for i := 0; i < c.ClusterSpec.Nodes; i++ { + kindCluster.Nodes = append(kindCluster.Nodes, kindconfigv1alpha4.Node{ + Role: kindconfigv1alpha4.ControlPlaneRole, + ExtraMounts: []kindconfigv1alpha4.Mount{ + { + HostPath: c.ClusterSpec.KubeVIPpManifestPath, + ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + }, + { + HostPath: c.ClusterSpec.KubeletManifestPath, + ContainerPath: "/var/lib/kubelet/config.yaml", + }, + { + HostPath: c.ClusterSpec.KubeletFlagsPath, + ContainerPath: "/etc/default/kubelet", + }, + }, + }) + } + + Expect(c.provider.Create( + c.Name, + cluster.CreateWithV1Alpha4Config(kindCluster), + cluster.CreateWithRetain(true), + cluster.CreateWithStopBeforeSettingUpKubernetes(true), + cluster.CreateWithWaitForReady(2*time.Minute), + cluster.CreateWithNodeImage("public.ecr.aws/eks-anywhere/kubernetes-sigs/kind/node:v1.26.7-eks-d-1-26-16-eks-a-47"), + )).To(Succeed()) +} + +func (c *Cluster) initEtcd(ctx context.Context) { + var err error + c.Nodes, err = c.provider.ListInternalNodes(c.Name) + slices.SortFunc(c.Nodes, func(a, b nodes.Node) int { + aName := a.String() + bName := b.String() + if aName < bName { + return 1 + } else if aName > bName { + return -1 + } + + return 0 + }) + + Expect(err).NotTo(HaveOccurred()) + firstNode := c.Nodes[0] + + createCerts(firstNode) + + // We need to run all phases individually to be able to re-run the health phase + // In CI it can take longer than the 30 seconds timeout that is hardcoded in etcdadm + // If etcdadm added the option to configure this timeout, we could change this to just + // call etcdadm init to run all phases. + + flags := []string{ + "--init-system", "kubelet", + "--certs-dir", "/etc/kubernetes/pki/etcd", + "--server-cert-extra-sans", strings.Join([]string{"etcd", c.VIP, e2e.NodeIPv4(firstNode)}, ","), + "--version", "3.5.8-eks-1-26-16", + "--image-repository", "public.ecr.aws/eks-distro/etcd-io/etcd", + } + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "install", flags)..., + ) + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "certificates", flags)..., + ) + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "snapshot", flags)..., + ) + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "configure", flags)..., + ) + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "start", flags)..., + ) + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "etcdctl", flags)..., + ) + + Eventually(func() error { + return runInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "health", flags)..., + ) + }, 3*time.Minute).Should(Succeed(), "etcd should become healthy in node in less than 3 minutes") + + e2e.RunInNode(firstNode, + "etcdadm", + initArgsForPhase("init", "post-init-instructions", flags)..., + ) + + bindEtcdListenerToAllIPs(firstNode) + + e2e.CopyFolderFromNodeToDisk(firstNode, "/etc/kubernetes/pki/etcd", c.EtcdCertsFolder) + + c.expectEtcdNodeHealthy(ctx, firstNode, 15*time.Second) +} + +func runInNode(node nodes.Node, command string, args ...string) error { + return e2e.PrintCommandOutputIfErr(node.Command(command, args...).Run()) +} + +func initArgsForPhase(command, phaseName string, flags []string) []string { + c := make([]string, 0, 3+len(flags)) + c = append(c, command, "phase", phaseName) + c = append(c, flags...) + return c +} + +func (c *Cluster) joinRestOfNodes(ctx context.Context) { + for _, node := range c.Nodes[1:] { + c.joinNode(ctx, c.Nodes[0], node) + } +} + +func (c *Cluster) joinNode(ctx context.Context, firstNode, node nodes.Node) { + nodeutils.CopyNodeToNode(firstNode, node, "/etc/kubernetes/pki/ca.crt") + nodeutils.CopyNodeToNode(firstNode, node, "/etc/kubernetes/pki/ca.key") + nodeutils.CopyNodeToNode(firstNode, node, "/etc/kubernetes/pki/etcd/ca.crt") + nodeutils.CopyNodeToNode(firstNode, node, "/etc/kubernetes/pki/etcd/ca.key") + + e2e.RunInNode(node, + "etcdadm", + "join", + "https://"+e2e.NodeIPv4(firstNode)+":2379", + "--init-system", "kubelet", + "--certs-dir", "/etc/kubernetes/pki/etcd", + "--server-cert-extra-sans", strings.Join([]string{"etcd", c.VIP, e2e.NodeIPv4(node)}, ","), + "--version", "3.5.8-eks-1-26-16", + "--image-repository", "public.ecr.aws/eks-distro/etcd-io/etcd", + ) + + bindEtcdListenerToAllIPs(node) + + c.expectEtcdNodeHealthy(ctx, node, 30*time.Second) +} + +func (c *Cluster) DeleteEtcdMember(ctx context.Context, toDelete, toKeep nodes.Node) { + // point client to the node we are keeping because we are going to use it to remove the other node + // and vip is possibly pointing to that node + client := c.newEtcdClient(e2e.NodeIPv4(toDelete)) + defer client.Close() + members, err := client.MemberList(ctx) + Expect(err).NotTo(HaveOccurred()) + c.Logger.Printf("Members: %v", members.Members) + + nodeName := toDelete.String() + for _, m := range members.Members { + if m.Name == nodeName { + c.Logger.Printf("Removing node %s with memberID %d", m.Name, m.ID) + // We need to retry this request because etcd will reject it if the + // server doesn't have recent connections to enough active members + // to protect the quorum. (active - 1) >= 1+((members-1)/2) + Eventually(func() error { + _, err := client.MemberRemove(ctx, m.ID) + return err + }).WithPolling(time.Second).WithTimeout(10*time.Second).Should( + Succeed(), "removing member should succeed once all members have connections to each other", + ) + + break + } + } + + e2e.DeleteNodes(toDelete) +} + +func (c *Cluster) Delete() { + Expect(c.provider.Delete(c.Name, "")).To(Succeed()) +} + +func startKubeletForEtcd(node nodes.Node) { + e2e.RunInNode(node, + "kubeadm", "init", "phase", "kubeconfig", "admin", "--config", "/kind/kubeadm.conf", + ) + e2e.RunInNode(node, + "kubeadm", "init", "phase", "kubelet-start", "--config", "/kind/kubeadm.conf", + ) +} + +func createCerts(node nodes.Node) { + e2e.RunInNode(node, + "kubeadm", + "init", + "phase", "certs", "ca", "--config", "/kind/kubeadm.conf", + ) + + e2e.RunInNode(node, + "kubeadm", + "init", + "phase", "certs", "etcd-ca", "--config", "/kind/kubeadm.conf", + ) +} + +func bindEtcdListenerToAllIPs(node nodes.Node) { + // There is no easy way to make etcdadm configure etcd to bind to 0.0.0.0 + // so we just manually update the manifest after it's created and restart it + // We want to listen in 0.0.0.0 so our kube-vip can connect to it. + e2e.RunInNode(node, + "sed", "-i", `s/https:\/\/.*,https:\/\/127.0.0.1:2379/https:\/\/0.0.0.0:2379/g`, "/etc/kubernetes/manifests/etcd.manifest", + ) + + e2e.StopPodInNode(node, "etcd") + + e2e.RunInNode(node, + "systemctl", "restart", "kubelet", + ) +} + +func (c *Cluster) newEtcdClient(serverIPs ...string) *clientv3.Client { + tlsInfo := transport.TLSInfo{ + TrustedCAFile: filepath.Join(c.EtcdCertsFolder, "ca.crt"), + CertFile: filepath.Join(c.EtcdCertsFolder, "etcdctl-etcd-client.crt"), + KeyFile: filepath.Join(c.EtcdCertsFolder, "etcdctl-etcd-client.key"), + } + + clientTLS, err := tlsInfo.ClientConfig() + Expect(err).NotTo(HaveOccurred()) + + endpoints := make([]string, 0, len(serverIPs)) + for _, ip := range serverIPs { + endpoints = append(endpoints, ip+":2379") + } + + client, err := clientv3.New(clientv3.Config{ + Endpoints: endpoints, + TLS: clientTLS, + DialTimeout: time.Second, + }) + Expect(err).NotTo(HaveOccurred()) + + return client +} + +func (c *Cluster) VerifyEtcdThroughVIP(ctx context.Context, timeout time.Duration) { + etcdClient := c.newEtcdClient(c.VIP) + defer etcdClient.Close() + rCtx, cancel := context.WithTimeout(ctx, timeout) + _, err := etcdClient.MemberList(rCtx) + Expect(err).NotTo(HaveOccurred()) + cancel() +} diff --git a/testing/e2e/etcd/election_test.go b/testing/e2e/etcd/election_test.go new file mode 100644 index 00000000..aa14d137 --- /dev/null +++ b/testing/e2e/etcd/election_test.go @@ -0,0 +1,114 @@ +//go:build e2e +// +build e2e + +package etcd_test + +import ( + "context" + "os" + "path/filepath" + "text/template" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" + "k8s.io/klog/v2" + + "github.com/kube-vip/kube-vip/testing/e2e" + "github.com/kube-vip/kube-vip/testing/e2e/etcd" +) + +type testConfig struct { + logger e2e.TestLogger + kubeVipImage string + kubeVipManifestPath string + clusterName string + tempDirPath string + vip string + etcdCertsFolder string + currentDir string + cluster *etcd.Cluster +} + +func (t *testConfig) cleanup() { + if os.Getenv("E2E_PRESERVE_CLUSTER") == "true" { + return + } + + t.cluster.Delete() + Expect(os.RemoveAll(t.tempDirPath)).To(Succeed()) + Expect(os.RemoveAll(t.etcdCertsFolder)).To(Succeed()) +} + +var _ = Describe("kube-vip with etcd leader election", func() { + ctx := context.Background() + test := &testConfig{} + + AfterEach(func() { + test.cleanup() + }) + + BeforeEach(func() { + By("configuring test", func() { + var err error + format.UseStringerRepresentation = true // Otherwise error stacks have binary format. + klog.SetOutput(GinkgoWriter) + + test.clusterName = "kube-vip-etcd-test" // this needs to unique per it block + test.logger = e2e.TestLogger{} + test.etcdCertsFolder = "certs" + + test.kubeVipImage = os.Getenv("E2E_IMAGE_PATH") + + test.vip = e2e.GenerateIPv4VIP() + test.logger.Printf("Selected VIP %s", test.vip) + + test.currentDir, err = os.Getwd() + Expect(err).NotTo(HaveOccurred()) + + test.tempDirPath, err = os.MkdirTemp("", "kube-vip-test") + Expect(err).NotTo(HaveOccurred()) + + test.kubeVipManifestPath = filepath.Join(test.tempDirPath, "etcd-vip-ipv4.yaml") + manifestFile, err := os.Create(test.kubeVipManifestPath) + Expect(err).NotTo(HaveOccurred()) + defer manifestFile.Close() + + templatePath := filepath.Join(test.currentDir, "kube-etcd-vip.yaml.tmpl") + kubeVIPManifestTemplate, err := template.New("kube-etcd-vip.yaml.tmpl").ParseFiles(templatePath) + Expect(err).NotTo(HaveOccurred()) + Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ + ControlPlaneVIP: test.vip, + ImagePath: test.kubeVipImage, + })).To(Succeed()) + }) + + By("creating etcd cluster", func() { + spec := &etcd.ClusterSpec{ + Name: test.clusterName, + Nodes: 2, + VIP: test.vip, + KubeVIPImage: test.kubeVipImage, + KubeVIPpManifestPath: test.kubeVipManifestPath, + KubeletManifestPath: filepath.Join(test.currentDir, "kubelet.yaml"), + KubeletFlagsPath: filepath.Join(test.currentDir, "kubelet-flags.env"), + EtcdCertsFolder: filepath.Join(test.currentDir, test.etcdCertsFolder), + Logger: test.logger, + } + + test.cluster = etcd.CreateCluster(ctx, spec) + }) + }) + + When("an etcd node is removed", func() { + It("elects a new kube-vip leader and provides a VIP to the second node", func() { + By("removing as member and killing the first node", func() { + test.cluster.DeleteEtcdMember(ctx, test.cluster.Nodes[0], test.cluster.Nodes[1]) + }) + By("verifying etcd is up and accessible through the vip", func() { + test.cluster.VerifyEtcdThroughVIP(ctx, 40*time.Second) + }) + }) + }) +}) diff --git a/testing/e2e/etcd/etcd_suite_test.go b/testing/e2e/etcd/etcd_suite_test.go new file mode 100644 index 00000000..3cbec044 --- /dev/null +++ b/testing/e2e/etcd/etcd_suite_test.go @@ -0,0 +1,16 @@ +//go:build e2e +// +build e2e + +package etcd_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestEtcd(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Etcd Suite") +} diff --git a/testing/e2e/etcd/health.go b/testing/e2e/etcd/health.go new file mode 100644 index 00000000..8cbda7ea --- /dev/null +++ b/testing/e2e/etcd/health.go @@ -0,0 +1,121 @@ +//go:build e2e +// +build e2e + +package etcd + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "path/filepath" + "time" + + "github.com/kube-vip/kube-vip/testing/e2e" + . "github.com/onsi/gomega" + "github.com/pkg/errors" + "go.etcd.io/etcd/client/pkg/v3/transport" + "sigs.k8s.io/kind/pkg/cluster/nodes" +) + +func (c *Cluster) expectEtcdNodeHealthy(ctx context.Context, node nodes.Node, timeout time.Duration) { + httpClient := c.newEtcdHTTPClient() + client := c.newEtcdClient(e2e.NodeIPv4(node)) + nodeEtcdEndpoint := etcdEndpointForNode(node) + Eventually(func(g Gomega) error { + health, err := getEtcdHealth(httpClient, node) + g.Expect(err).NotTo(HaveOccurred()) + if !health.Healthy() { + c.Logger.Printf("Member %s is not healthy with reason: %s", node.String(), health.Reason) + } + g.Expect(health.Healthy()).To(BeTrue(), "member is not healthy with reason: %s", health.Reason) + statusCtx, statusCancel := context.WithTimeout(ctx, 2*time.Second) + defer statusCancel() + status, err := client.Status(statusCtx, nodeEtcdEndpoint) + g.Expect(err).NotTo(HaveOccurred()) + + g.Expect(status.Errors).To(BeEmpty(), "member should not have any errors in status") + g.Expect(status.IsLearner).To(BeFalse(), "member should not be a learner") + + alarmsCtx, alarmsCancel := context.WithTimeout(ctx, 2*time.Second) + defer alarmsCancel() + alarms, err := client.AlarmList(alarmsCtx) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(alarms.Alarms).To(BeEmpty(), "cluster should not have any alarms") + + return nil + }, timeout).Should(Succeed(), "node %s should eventually be healthy", node.String()) +} + +func (c *Cluster) newEtcdHTTPClient() *http.Client { + tlsInfo := transport.TLSInfo{ + TrustedCAFile: filepath.Join(c.EtcdCertsFolder, "ca.crt"), + CertFile: filepath.Join(c.EtcdCertsFolder, "etcdctl-etcd-client.crt"), + KeyFile: filepath.Join(c.EtcdCertsFolder, "etcdctl-etcd-client.key"), + } + + clientTLS, err := tlsInfo.ClientConfig() + Expect(err).NotTo(HaveOccurred()) + + return &http.Client{ + Timeout: 2 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: clientTLS, + }, + } +} + +type etcdHealthCheckResponse struct { + Health string `json:"health"` + Reason string `json:"reason"` +} + +func (h *etcdHealthCheckResponse) Healthy() bool { + return h.Health == "true" +} + +func getEtcdHealth(c *http.Client, node nodes.Node) (*etcdHealthCheckResponse, error) { + req, err := http.NewRequest("GET", etcdHealthEndpoint(node), nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + return nil, errors.Wrapf(err, "etcd member not ready, returned http status %d", resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + health, err := parseEtcdHealthResponse(body) + if err != nil { + return nil, err + } + + return health, nil +} + +func etcdEndpointForNode(node nodes.Node) string { + return e2e.NodeIPv4(node) + ":2379" +} + +func etcdHealthEndpoint(node nodes.Node) string { + return fmt.Sprintf("https://%s:2379/health", e2e.NodeIPv4(node)) +} + +func parseEtcdHealthResponse(data []byte) (*etcdHealthCheckResponse, error) { + obj := &etcdHealthCheckResponse{} + if err := json.Unmarshal(data, obj); err != nil { + return nil, err + } + return obj, nil +} diff --git a/testing/e2e/etcd/kube-etcd-vip.yaml.tmpl b/testing/e2e/etcd/kube-etcd-vip.yaml.tmpl new file mode 100644 index 00000000..a5257c91 --- /dev/null +++ b/testing/e2e/etcd/kube-etcd-vip.yaml.tmpl @@ -0,0 +1,51 @@ +--- +apiVersion: v1 +kind: Pod +metadata: + name: kube-vip + namespace: kube-system +spec: + containers: + - name: kube-vip + args: + - manager + - --leaderElectionType=etcd + - --etcdCACert=/etc/kubernetes/pki/etcd/ca.crt + - --etcdCert=/etc/kubernetes/pki/etcd/server.crt + - --etcdKey=/etc/kubernetes/pki/etcd/server.key + - --etcdEndpoints=127.0.0.1:2379 + env: + - name: vip_arp + value: "true" + - name: vip_interface + value: eth0 + - name: vip_leaderelection + value: "true" + - name: address + value: "{{ .ControlPlaneVIP }}" + - name: vip_leaseduration + value: "2" + - name: vip_renewdeadline + value: "3" + - name: vip_retryperiod + value: "1" + - name: cp_enable + value: "true" + - name: vip_loglevel + value: "5" + image: "{{ .ImagePath }}" + imagePullPolicy: Never + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + volumeMounts: + # force kube-vip to use CP ip from admin.conf instead of localhost + - mountPath: /etc/kubernetes/pki/etcd + name: etcd-certs + hostNetwork: true + volumes: + - hostPath: + path: /etc/kubernetes/pki/etcd + name: etcd-certs diff --git a/testing/e2e/etcd/kubelet-flags.env b/testing/e2e/etcd/kubelet-flags.env new file mode 100644 index 00000000..12833606 --- /dev/null +++ b/testing/e2e/etcd/kubelet-flags.env @@ -0,0 +1 @@ +KUBELET_EXTRA_ARGS="--kubeconfig='' --bootstrap-kubeconfig='' --container-runtime-endpoint=unix:///run/containerd/containerd.sock --node-labels= --pod-infra-container-image=registry.k8s.io/pause:3.9" \ No newline at end of file diff --git a/testing/e2e/etcd/kubelet.yaml b/testing/e2e/etcd/kubelet.yaml new file mode 100644 index 00000000..fb4d7bdd --- /dev/null +++ b/testing/e2e/etcd/kubelet.yaml @@ -0,0 +1,20 @@ +apiVersion: kubelet.config.k8s.io/v1beta1 +kind: KubeletConfiguration +authentication: + anonymous: + enabled: true + webhook: + enabled: false +authorization: + mode: AlwaysAllow +enableServer: false +logging: + flushFrequency: 0 + options: + json: + infoBufferSize: "0" + verbosity: 0 +podCIDR: 10.241.1.0/24 +staticPodPath: /etc/kubernetes/manifests +cgroupDriver: systemd +cgroupRoot: /kubelet diff --git a/testing/e2e/ip.go b/testing/e2e/ip.go new file mode 100644 index 00000000..52aa661b --- /dev/null +++ b/testing/e2e/ip.go @@ -0,0 +1,88 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "bufio" + "bytes" + "encoding/binary" + "io" + "net" + "os/exec" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func GenerateIPv6VIP() string { + cidrs := getKindNetworkSubnetCIDRs() + + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + Expect(parseErr).NotTo(HaveOccurred()) + + if ip.To4() == nil { + lowerMask := binary.BigEndian.Uint64(ipNet.Mask[8:]) + lowerStart := binary.BigEndian.Uint64(ipNet.IP[8:]) + lowerEnd := (lowerStart & lowerMask) | (^lowerMask) + + chosenVIP := make([]byte, 16) + // Copy upper half into chosenVIP + copy(chosenVIP, ipNet.IP[0:8]) + // Copy lower half into chosenVIP + binary.BigEndian.PutUint64(chosenVIP[8:], lowerEnd-5) + return net.IP(chosenVIP).String() + } + } + Fail("Could not find any IPv6 CIDRs in the Docker \"kind\" network") + return "" +} + +func GenerateIPv4VIP() string { + cidrs := getKindNetworkSubnetCIDRs() + + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + Expect(parseErr).NotTo(HaveOccurred()) + + if ip.To4() != nil { + mask := binary.BigEndian.Uint32(ipNet.Mask) + start := binary.BigEndian.Uint32(ipNet.IP) + end := (start & mask) | (^mask) + + chosenVIP := make([]byte, 4) + binary.BigEndian.PutUint32(chosenVIP, end-5) + return net.IP(chosenVIP).String() + } + } + Fail("Could not find any IPv4 CIDRs in the Docker \"kind\" network") + return "" +} + +func getKindNetworkSubnetCIDRs() []string { + cmd := exec.Command( + "docker", "inspect", "kind", + "--format", `{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}`, + ) + cmdOut := new(bytes.Buffer) + cmd.Stdout = cmdOut + Expect(cmd.Run()).To(Succeed(), "The Docker \"kind\" network was not found.") + reader := bufio.NewReader(cmdOut) + + cidrs := []string{} + for { + line, readErr := reader.ReadString('\n') + if readErr != nil && readErr != io.EOF { + Expect(readErr).NotTo(HaveOccurred(), "Error finding subnet CIDRs in the Docker \"kind\" network") + } + + cidrs = append(cidrs, strings.TrimSpace(line)) + if readErr == io.EOF { + break + } + } + + return cidrs +} diff --git a/testing/e2e/kind.go b/testing/e2e/kind.go new file mode 100644 index 00000000..59f0798d --- /dev/null +++ b/testing/e2e/kind.go @@ -0,0 +1,147 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "bufio" + "bytes" + "fmt" + "os" + "path/filepath" + + . "github.com/onsi/gomega" + "github.com/pkg/errors" + "k8s.io/klog/v2" + "sigs.k8s.io/kind/pkg/cluster/nodes" + "sigs.k8s.io/kind/pkg/cluster/nodeutils" + "sigs.k8s.io/kind/pkg/cmd" + load "sigs.k8s.io/kind/pkg/cmd/kind/load/docker-image" + "sigs.k8s.io/kind/pkg/exec" + kindlog "sigs.k8s.io/kind/pkg/log" +) + +func DeleteNodes(n ...nodes.Node) { + Expect(deleteNodes(n...)).To(Succeed()) +} + +func deleteNodes(n ...nodes.Node) error { + if len(n) == 0 { + return nil + } + const command = "docker" + args := make([]string, 0, len(n)+3) // allocate once + args = append(args, + "rm", + "-f", // force the container to be delete now + "-v", // delete volumes + ) + for _, node := range n { + args = append(args, node.String()) + } + if err := exec.Command(command, args...).Run(); err != nil { + return errors.Wrap(err, "failed to delete nodes") + } + return nil +} + +func NodeIPv4(node nodes.Node) string { + ip, _, err := node.IP() + Expect(err).NotTo(HaveOccurred()) + return ip +} + +func LoadDockerImageToKind(logger kindlog.Logger, imagePath, clusterName string) { + loadImageCmd := load.NewCommand(logger, cmd.StandardIOStreams()) + loadImageCmd.SetArgs([]string{"--name", clusterName, imagePath}) + Expect(loadImageCmd.Execute()).To(Succeed()) +} + +func RunInNode(node nodes.Node, command string, args ...string) { + Expect(PrintCommandOutputIfErr( + node.Command(command, args...).Run(), + )).To(Succeed()) +} + +func StopPodInNode(node nodes.Node, containerName string) { + RunInNode(node, + "bash", "-c", + fmt.Sprintf( + "crictl pods --output json --name %s-%s | jq -r \".items[0].id\" | xargs crictl stopp", + containerName, + node.String(), + ), + ) +} + +func CopyFromNodeToDisk(node nodes.Node, org, dst string) { + dstFile, err := os.Create(dst) + Expect(err).NotTo(HaveOccurred()) + defer dstFile.Close() + + Expect(node.Command("cat", org).SetStdout(dstFile).Run()).To(Succeed()) +} + +func CopyFolderFromNodeToDisk(node nodes.Node, org, dst string) { + Expect(os.MkdirAll(dst, 0o755)).To(Succeed()) + + for _, file := range filesInNodeFolder(node, org) { + CopyFromNodeToDisk(node, file, filepath.Join(dst, filepath.Base(file))) + } +} + +func CopyFolderFromNodeToNode(org, dst nodes.Node, folder string) { + for _, folder := range foldersInNodeFolder(org, folder) { + CopyFolderFromNodeToNode(org, dst, folder) + } + + for _, file := range filesInNodeFolder(org, folder) { + Expect(nodeutils.CopyNodeToNode(org, dst, file)).To(Succeed()) + } +} + +func filesInNodeFolder(node nodes.Node, folder string) []string { + return commandOutputInLines( + node, + "find", folder, "-maxdepth", "1", "-mindepth", "1", "-type", "f", + ) +} + +func foldersInNodeFolder(node nodes.Node, folder string) []string { + return commandOutputInLines( + node, + "find", folder, "-maxdepth", "1", "-mindepth", "1", "-type", "d", + ) +} + +func commandOutputInLines(node nodes.Node, command string, args ...string) []string { + var linesB bytes.Buffer + Expect(node.Command( + command, args..., + ).SetStdout(&linesB).Run()).To(Succeed()) + + var lines []string + scanner := bufio.NewScanner(&linesB) + for scanner.Scan() { + if l := scanner.Text(); l != "" { + lines = append(lines, l) + } + } + Expect(scanner.Err()).To(Succeed()) + + return lines +} + +func PrintCommandOutputIfErr(err error) error { + tErr := err + for tErr != nil { + runErrP := &exec.RunError{} + runErr := &runErrP + if errors.As(tErr, runErr) { + klog.Errorf("Command failed %s:\n%s", (*runErr).Command, string((*runErr).Output)) + break + } + } + + return tErr +} diff --git a/testing/e2e/logger.go b/testing/e2e/logger.go new file mode 100644 index 00000000..865ecbe8 --- /dev/null +++ b/testing/e2e/logger.go @@ -0,0 +1,43 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "k8s.io/klog/v2" + "sigs.k8s.io/kind/pkg/log" +) + +type TestLogger struct{} + +func (t TestLogger) Warnf(format string, args ...interface{}) { + klog.Warningf(format, args...) +} + +func (t TestLogger) Warn(message string) { + klog.Warning(message) +} + +func (t TestLogger) Error(message string) { + klog.Error(message) +} + +func (t TestLogger) Errorf(format string, args ...interface{}) { + klog.Errorf(format, args...) +} + +func (t TestLogger) Printf(format string, args ...interface{}) { + klog.Infof(format, args...) +} + +func (t TestLogger) V(level log.Level) log.InfoLogger { + return TestInfoLogger{Verbose: klog.V(klog.Level(level))} +} + +type TestInfoLogger struct { + klog.Verbose +} + +func (t TestInfoLogger) Info(message string) { + t.Verbose.Info(message) +} diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index ed815235..7bb0df99 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -23,7 +23,6 @@ import ( // 1. Create a deployment // 2. Expose the deployment - func (config *testConfig) startServiceTest(ctx context.Context, clientset *kubernetes.Clientset) { nodeTolerate := os.Getenv("NODE_TOLERATE") diff --git a/testing/e2e/template.go b/testing/e2e/template.go new file mode 100644 index 00000000..43fc9582 --- /dev/null +++ b/testing/e2e/template.go @@ -0,0 +1,9 @@ +//go:build e2e +// +build e2e + +package e2e + +type KubevipManifestValues struct { + ControlPlaneVIP string + ImagePath string +} From 04bdc574349810b895145d326cb9384d9c4b493b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Oct 2023 11:20:58 +0000 Subject: [PATCH 437/542] Bump golang.org/x/net from 0.12.0 to 0.17.0 Bumps [golang.org/x/net](https://github.com/golang/net) from 0.12.0 to 0.17.0. - [Commits](https://github.com/golang/net/compare/v0.12.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 399d2941..3b40639b 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( go.etcd.io/etcd/client/v3 v3.5.9 go.uber.org/zap v1.21.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 - golang.org/x/sys v0.12.0 + golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 k8s.io/api v0.27.4 k8s.io/apimachinery v0.27.4 @@ -97,11 +97,11 @@ require ( github.com/vishvananda/netns v0.0.4 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/term v0.12.0 // indirect + golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.13.0 // indirect diff --git a/go.sum b/go.sum index 8c70354c..5d00d0f0 100644 --- a/go.sum +++ b/go.sum @@ -398,8 +398,8 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -483,8 +483,8 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -570,11 +570,11 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From b5bf5075468327d4c6da59cac7c60e8ad472e780 Mon Sep 17 00:00:00 2001 From: Guillermo Gaston Date: Mon, 16 Oct 2023 23:07:41 +0000 Subject: [PATCH 438/542] Fix etcd e2e tests in GitHub actions In order to run the kubelet in kind containers on the vms provided by github, the kubelet needed some extra configuration. Signed-off-by: Guillermo Gaston --- testing/e2e/e2e_suite_test.go | 47 ++--------------------------- testing/e2e/etcd/election_test.go | 7 ++--- testing/e2e/etcd/etcd_suite_test.go | 9 ++++++ testing/e2e/etcd/kubelet.yaml | 6 ++++ testing/e2e/ip.go | 41 +++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 48 deletions(-) diff --git a/testing/e2e/e2e_suite_test.go b/testing/e2e/e2e_suite_test.go index cf054d4d..a9092081 100644 --- a/testing/e2e/e2e_suite_test.go +++ b/testing/e2e/e2e_suite_test.go @@ -4,17 +4,12 @@ package e2e_test import ( - "fmt" - "os/exec" "testing" - "time" - - kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" - "sigs.k8s.io/kind/pkg/cluster" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/onsi/gomega/gexec" + + "github.com/kube-vip/kube-vip/testing/e2e" ) func TestE2E(t *testing.T) { @@ -24,43 +19,7 @@ func TestE2E(t *testing.T) { var _ = SynchronizedBeforeSuite( func() { - ensureKindNetwork() + e2e.EnsureKindNetwork() }, func() {}, ) - -func ensureKindNetwork() { - By("checking if the Docker \"kind\" network exists") - cmd := exec.Command("docker", "inspect", "kind") - session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - Eventually(session).Should(gexec.Exit()) - if session.ExitCode() == 0 { - return - } - - By("Docker \"kind\" network was not found. Creating dummy Kind cluster to ensure creation") - clusterConfig := kindconfigv1alpha4.Cluster{ - Networking: kindconfigv1alpha4.Networking{ - IPFamily: kindconfigv1alpha4.IPv6Family, - }, - } - - provider := cluster.NewProvider( - cluster.ProviderWithDocker(), - ) - dummyClusterName := fmt.Sprintf("dummy-cluster-%d", time.Now().Unix()) - Expect(provider.Create( - dummyClusterName, - cluster.CreateWithV1Alpha4Config(&clusterConfig), - )).To(Succeed()) - - By("deleting dummy Kind cluster") - Expect(provider.Delete(dummyClusterName, "")) - - By("checking if the Docker \"kind\" network was successfully created") - cmd = exec.Command("docker", "inspect", "kind") - session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - Eventually(session).Should(gexec.Exit(0)) -} diff --git a/testing/e2e/etcd/election_test.go b/testing/e2e/etcd/election_test.go index aa14d137..c415d383 100644 --- a/testing/e2e/etcd/election_test.go +++ b/testing/e2e/etcd/election_test.go @@ -24,7 +24,6 @@ type testConfig struct { kubeVipImage string kubeVipManifestPath string clusterName string - tempDirPath string vip string etcdCertsFolder string currentDir string @@ -37,7 +36,7 @@ func (t *testConfig) cleanup() { } t.cluster.Delete() - Expect(os.RemoveAll(t.tempDirPath)).To(Succeed()) + Expect(os.RemoveAll(t.kubeVipManifestPath)).To(Succeed()) Expect(os.RemoveAll(t.etcdCertsFolder)).To(Succeed()) } @@ -67,10 +66,10 @@ var _ = Describe("kube-vip with etcd leader election", func() { test.currentDir, err = os.Getwd() Expect(err).NotTo(HaveOccurred()) - test.tempDirPath, err = os.MkdirTemp("", "kube-vip-test") + tempDirPath, err := os.MkdirTemp("", "kube-vip-test") Expect(err).NotTo(HaveOccurred()) - test.kubeVipManifestPath = filepath.Join(test.tempDirPath, "etcd-vip-ipv4.yaml") + test.kubeVipManifestPath = filepath.Join(tempDirPath, "etcd-vip-ipv4.yaml") manifestFile, err := os.Create(test.kubeVipManifestPath) Expect(err).NotTo(HaveOccurred()) defer manifestFile.Close() diff --git a/testing/e2e/etcd/etcd_suite_test.go b/testing/e2e/etcd/etcd_suite_test.go index 3cbec044..365a09df 100644 --- a/testing/e2e/etcd/etcd_suite_test.go +++ b/testing/e2e/etcd/etcd_suite_test.go @@ -8,9 +8,18 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + + "github.com/kube-vip/kube-vip/testing/e2e" ) func TestEtcd(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Etcd Suite") } + +var _ = SynchronizedBeforeSuite( + func() { + e2e.EnsureKindNetwork() + }, + func() {}, +) diff --git a/testing/e2e/etcd/kubelet.yaml b/testing/e2e/etcd/kubelet.yaml index fb4d7bdd..952a250d 100644 --- a/testing/e2e/etcd/kubelet.yaml +++ b/testing/e2e/etcd/kubelet.yaml @@ -18,3 +18,9 @@ podCIDR: 10.241.1.0/24 staticPodPath: /etc/kubernetes/manifests cgroupDriver: systemd cgroupRoot: /kubelet +failSwapOn: false +imageGCHighThresholdPercent: 100 +evictionHard: + nodefs.available: "0%" + nodefs.inodesFree: "0%" + imagefs.available: "0%" diff --git a/testing/e2e/ip.go b/testing/e2e/ip.go index 52aa661b..df4a3d80 100644 --- a/testing/e2e/ip.go +++ b/testing/e2e/ip.go @@ -7,15 +7,56 @@ import ( "bufio" "bytes" "encoding/binary" + "fmt" "io" "net" "os/exec" "strings" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/onsi/gomega/gexec" + kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" + "sigs.k8s.io/kind/pkg/cluster" ) +func EnsureKindNetwork() { + By("checking if the Docker \"kind\" network exists") + cmd := exec.Command("docker", "inspect", "kind") + session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session).Should(gexec.Exit()) + if session.ExitCode() == 0 { + return + } + + By("Docker \"kind\" network was not found. Creating dummy Kind cluster to ensure creation") + clusterConfig := kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.IPv6Family, + }, + } + + provider := cluster.NewProvider( + cluster.ProviderWithDocker(), + ) + dummyClusterName := fmt.Sprintf("dummy-cluster-%d", time.Now().Unix()) + Expect(provider.Create( + dummyClusterName, + cluster.CreateWithV1Alpha4Config(&clusterConfig), + )).To(Succeed()) + + By("deleting dummy Kind cluster") + Expect(provider.Delete(dummyClusterName, "")) + + By("checking if the Docker \"kind\" network was successfully created") + cmd = exec.Command("docker", "inspect", "kind") + session, err = gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session).Should(gexec.Exit(0)) +} + func GenerateIPv6VIP() string { cidrs := getKindNetworkSubnetCIDRs() From 31955fedf799902dfef44d75adda572f5e1c0628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Mon, 23 Oct 2023 19:19:35 +0200 Subject: [PATCH 439/542] .github: Add a dependabot config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..c25ee7a4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + - package-ecosystem: gomod + directory: / + schedule: + interval: weekly + - package-ecosystem: docker + directory: / + schedule: + interval: weekly From a8914af861ba1b90efb8a4656e97fe75e12c2ee1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:29:23 +0000 Subject: [PATCH 440/542] Bump golang from 1.20.8-alpine3.18 to 1.21.3-alpine3.18 Bumps golang from 1.20.8-alpine3.18 to 1.21.3-alpine3.18. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile_iptables | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 378c0c23..c3f35da4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.20.8-alpine3.18 as dev +FROM golang:1.21.3-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 00394d9d..bb1cddb1 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.20.8-alpine3.18 as dev +FROM golang:1.21.3-alpine3.18 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ From 70e94d24f4406d0f37f3277efe799cee2243123f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:29:24 +0000 Subject: [PATCH 441/542] Bump docker/setup-qemu-action from 1 to 3 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 7b75ff58..9bee0470 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -13,7 +13,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f0b16ccf..ffd7c0d5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,7 +13,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to DockerHub From f20fa9df3ece851b9b0c5ca5475e9299a0c5769c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:29:29 +0000 Subject: [PATCH 442/542] Bump github/codeql-action from 1 to 2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1...v2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 87fd2e2b..23a50cf9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. From 202274d4f11cc4ff45a561451be0b4eba53d8e52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:29:32 +0000 Subject: [PATCH 443/542] Bump anchore/sbom-action from 0.12.0 to 0.14.3 Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.12.0 to 0.14.3. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Commits](https://github.com/anchore/sbom-action/compare/v0.12.0...v0.14.3) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 3711de4f..0390b439 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -26,6 +26,6 @@ jobs: with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action - uses: anchore/sbom-action@v0.12.0 + uses: anchore/sbom-action@v0.14.3 with: format: cyclonedx-json From 4e88e32e56c715fc998cf6be8646ddec1466477e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:29:36 +0000 Subject: [PATCH 444/542] Bump docker/build-push-action from 2 to 5 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v2...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/main.yaml | 4 ++-- .github/workflows/release.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 7b75ff58..78e4303d 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -29,7 +29,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build standard version id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x @@ -39,7 +39,7 @@ jobs: ghcr.io/kube-vip/kube-vip:${{ github.ref_name }} - name: Build iptables version id: docker_build_iptables - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: context: . file: Dockerfile_iptables diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f0b16ccf..03658fd4 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,7 +29,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push main branch id: docker_build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x @@ -41,7 +41,7 @@ jobs: ghcr.io/kube-vip/kube-vip:latest - name: Build iptables version and push main branch id: docker_build_iptables - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: Dockerfile_iptables From 52bacaa03c673da76fb496b63955cff46555b9ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:31:39 +0000 Subject: [PATCH 445/542] Bump github.com/onsi/ginkgo/v2 from 2.12.1 to 2.13.0 Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.12.1 to 2.13.0. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.12.1...v2.13.0) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3b40639b..f633fbd4 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 - github.com/onsi/ginkgo/v2 v2.12.1 + github.com/onsi/ginkgo/v2 v2.13.0 github.com/onsi/gomega v1.27.10 github.com/osrg/gobgp/v3 v3.17.0 github.com/packethost/packngo v0.30.0 diff --git a/go.sum b/go.sum index 5d00d0f0..993a3c64 100644 --- a/go.sum +++ b/go.sum @@ -288,8 +288,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA= -github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= From 1cde04e8a1d4b94991e37fa4067b369aaabda646 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:33:46 +0000 Subject: [PATCH 446/542] Bump github.com/osrg/gobgp/v3 from 3.17.0 to 3.19.0 Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.17.0 to 3.19.0. - [Release notes](https://github.com/osrg/gobgp/releases) - [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml) - [Commits](https://github.com/osrg/gobgp/compare/v3.17.0...v3.19.0) --- updated-dependencies: - dependency-name: github.com/osrg/gobgp/v3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 22 ++++++++++++---------- go.sum | 47 ++++++++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 3b40639b..20769b4b 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/mdlayher/ndp v1.0.1 github.com/onsi/ginkgo/v2 v2.12.1 github.com/onsi/gomega v1.27.10 - github.com/osrg/gobgp/v3 v3.17.0 + github.com/osrg/gobgp/v3 v3.19.0 github.com/packethost/packngo v0.30.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.16.0 @@ -37,7 +37,7 @@ require ( ) require ( - github.com/BurntSushi/toml v1.2.1 // indirect + github.com/BurntSushi/toml v1.3.2 // indirect github.com/alessio/shellescape v1.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -60,7 +60,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -81,17 +81,17 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.15.0 // indirect + github.com/spf13/viper v1.16.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect @@ -99,7 +99,7 @@ require ( go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.5.0 // indirect + golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect @@ -107,9 +107,11 @@ require ( golang.org/x/tools v0.13.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/grpc v1.57.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 5d00d0f0..7ade34cd 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= @@ -95,7 +95,7 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -185,8 +185,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -292,15 +292,15 @@ github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= -github.com/osrg/gobgp/v3 v3.17.0/go.mod h1:tSUXn/s9uggSRTKP3IBeT5zI4ayOUX3O7fG5+n+SHPc= +github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= +github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CTN21W18= github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= @@ -326,8 +326,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= @@ -335,8 +335,8 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= -github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -351,6 +351,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= @@ -494,8 +495,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -715,8 +716,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M= +google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -733,8 +738,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -747,8 +752,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 2a8e981b4965fc6053b90e4ed4b0369eddd49459 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:34:02 +0000 Subject: [PATCH 447/542] Bump go.uber.org/zap from 1.21.0 to 1.26.0 Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.21.0 to 1.26.0. - [Release notes](https://github.com/uber-go/zap/releases) - [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber-go/zap/compare/v1.21.0...v1.26.0) --- updated-dependencies: - dependency-name: go.uber.org/zap dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 5 ++--- go.sum | 23 +++++------------------ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 3b40639b..6d95761d 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( go.etcd.io/etcd/api/v3 v3.5.9 go.etcd.io/etcd/client/pkg/v3 v3.5.9 go.etcd.io/etcd/client/v3 v3.5.9 - go.uber.org/zap v1.21.0 + go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 @@ -95,8 +95,7 @@ require ( github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.8.0 // indirect + go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.5.0 // indirect diff --git a/go.sum b/go.sum index 5d00d0f0..d7f89b6a 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,6 @@ github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -366,7 +364,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= @@ -380,16 +377,11 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -475,7 +467,6 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -554,10 +545,8 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -639,7 +628,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= @@ -767,7 +755,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= From 12ab991048dea2400a5b4dbab93a3b0a9fb0b6a2 Mon Sep 17 00:00:00 2001 From: Amr Ragaey Date: Thu, 26 Oct 2023 11:52:37 +0300 Subject: [PATCH 448/542] update Go version --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 378c0c23..e4b8a7f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.20.8-alpine3.18 as dev +FROM golang:1.20.9-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ From 305572359d71624893c1e32394f2e61ca0292890 Mon Sep 17 00:00:00 2001 From: Amr Ragaey Date: Thu, 26 Oct 2023 11:57:20 +0300 Subject: [PATCH 449/542] update go-restful version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3b40639b..c37488ca 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect From 3ea0b629acda5776f2cdc13e9ffa4a123cdf1fe2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:46:42 +0000 Subject: [PATCH 450/542] Bump actions/checkout from 2 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- .github/workflows/ci.yaml | 12 ++++++------ .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index 3711de4f..1a78f3c5 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1525ba6e..8dc1d49e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ jobs: - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -26,7 +26,7 @@ jobs: name: Unit tests steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -50,7 +50,7 @@ jobs: name: E2E ARP tests steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -64,7 +64,7 @@ jobs: name: E2E service tests steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v4 with: @@ -78,7 +78,7 @@ jobs: name: Image vulnerability scan steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build image with iptables run: make dockerx86ActionIPTables - name: Run Trivy vulnerability scanner diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 23a50cf9..f640e08d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 9bee0470..96ac2f80 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ffd7c0d5..7231d11c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx From 1eb9bddb9c6b2d1c5867f9e1302499847e314658 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:47:13 +0000 Subject: [PATCH 451/542] Bump alpine from 3.18.3 to 3.18.4 Bumps alpine from 3.18.3 to 3.18.4. --- updated-dependencies: - dependency-name: alpine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile_iptables | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile_iptables b/Dockerfile_iptables index bb1cddb1..a4617a89 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -11,7 +11,7 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ CGO_ENABLED=0 GOOS=linux make build -FROM alpine:3.18.3 +FROM alpine:3.18.4 # Add Certificates into the image, for anything that does API calls RUN apk add --no-cache iptables # Add kube-vip binary From 08d71536e963ee55a12811bcd10849cc8a097750 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:51:00 +0000 Subject: [PATCH 452/542] Bump google.golang.org/grpc from 1.57.0 to 1.57.1 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.57.0 to 1.57.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.57.0...v1.57.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index db31a9ff..59f161d6 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/grpc v1.57.1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 3e2eb50d..3d3cfce0 100644 --- a/go.sum +++ b/go.sum @@ -726,8 +726,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= +google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From a25cc92daaf234e6c5622e0efc51c7ccd3dc5d00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 09:51:15 +0000 Subject: [PATCH 453/542] Bump k8s.io/client-go from 0.27.4 to 0.28.3 Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.4 to 0.28.3. - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.27.4...v0.28.3) --- updated-dependencies: - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 18 +++++++++--------- go.sum | 45 +++++++++++++++++++-------------------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index db31a9ff..808f144f 100644 --- a/go.mod +++ b/go.mod @@ -28,9 +28,9 @@ require ( golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - k8s.io/api v0.27.4 - k8s.io/apimachinery v0.27.4 - k8s.io/client-go v0.27.4 + k8s.io/api v0.28.3 + k8s.io/apimachinery v0.28.3 + k8s.io/client-go v0.28.3 k8s.io/klog/v2 v2.100.1 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.3.0 @@ -51,11 +51,11 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect @@ -98,11 +98,11 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.1.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.13.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect @@ -115,8 +115,8 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 3e2eb50d..3d87d389 100644 --- a/go.sum +++ b/go.sum @@ -74,7 +74,6 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= @@ -104,8 +103,8 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -141,13 +140,12 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -232,7 +230,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -318,7 +315,7 @@ github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -335,7 +332,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -486,8 +482,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -578,8 +574,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -697,7 +693,6 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -744,7 +739,6 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -759,7 +753,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= @@ -772,18 +765,18 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= -k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= -k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= -k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= -k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= +k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= +k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= +k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= +k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= +k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 14c27ff8395d83b0f5dd00f280ff4ccbdb0eb23f Mon Sep 17 00:00:00 2001 From: Anthony ARNAUD Date: Thu, 26 Oct 2023 12:09:52 -0400 Subject: [PATCH 454/542] Add doc for static pods on k0s using k0sctl Signed-off-by: Anthony ARNAUD --- docs/install_static/index.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/install_static/index.md b/docs/install_static/index.md index ad01c7f7..a5a97b7a 100644 --- a/docs/install_static/index.md +++ b/docs/install_static/index.md @@ -4,6 +4,7 @@ [Static Pods](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) are Kubernetes Pods that are run by the `kubelet` on a single node and are not managed by the Kubernetes cluster itself. This means that whilst the Pod can appear within Kubernetes, it can't make use of a variety of Kubernetes functionality (such as the Kubernetes token or ConfigMap resources). The static Pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) as this is due to the sequence of actions performed by `kubeadm`. Ideally, we want `kube-vip` to be part of the Kubernetes cluster, but for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. +### with kubeadm The sequence of events for building a highly available Kubernetes cluster with `kubeadm` and `kube-vip` are as follows: 1. Generate a `kube-vip` manifest in the static Pods manifest directory (see the [generating a manifest](#generating-a-manifest) section below). @@ -15,6 +16,34 @@ The sequence of events for building a highly available Kubernetes cluster with ` 7. Using the output from the `kubeadm init` command on the first control plane, run the `kubeadm join` command on the remainder of the control planes. 8. Copy the generated `kube-vip` manifest to the remainder of the control planes and place in their static Pods manifest directory (default of `/etc/kubernetes/manifests/`). +### with k0sctl +The sequence of events for building a highly available Kubernetes cluster with `k0sctl` and `kube-vip` are as follows: + + +1. Generate a `kube-vip` manifest in the static Pods manifest directory (see the [generating a manifest](#generating-a-manifest) section below). +2. Run `k0sctl init > k0sctl.yaml` edit the manifest to change and add your host IPs. Controller need to have both role by using `role: controller+worker` +3. Add in `installFlags` option `--kubelet-extra-args=--pod-manifest-path=/etc/k0s/manifests/` and `--disable-components=konnectivity-server` +4. On the first controller in the list add a `hooks` options like bellow and replace value: + ```yaml + hooks: + apply: + before: + - /usr/sbin/ip addr add ${VIP} dev ${INTERFACE} || exit 0 + after: + - /usr/sbin/ip addr del ${VIP} dev ${INTERFACE} || exit 0 + ``` +5. On every controller in the list configure the `files` options to upload the `kube-vip` manifest into `/etc/k0s/manifests/` + ```yaml + files: + - name: kube-vip.yaml + src: kube-vip.yaml + dstDir: /etc/k0s/manifests/ + perm: 0655 + ``` +6. Configure the `k0s.config.spec.api.externalAddress` in the `k0s` config section in `k0sctl.yaml` +7. Deploy your cluster with `k0sctl apply` + + ## Kube-Vip as HA, Load Balancer, or both The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. From 6e528fef905af66a3ec660e5fa2e8a25a1804bf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:58:13 +0000 Subject: [PATCH 455/542] Bump sigs.k8s.io/yaml from 1.3.0 to 1.4.0 Bumps [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) from 1.3.0 to 1.4.0. - [Release notes](https://github.com/kubernetes-sigs/yaml/releases) - [Changelog](https://github.com/kubernetes-sigs/yaml/blob/master/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/yaml/compare/v1.3.0...v1.4.0) --- updated-dependencies: - dependency-name: sigs.k8s.io/yaml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d0ce8d96..92e9f9f6 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( k8s.io/client-go v0.28.3 k8s.io/klog/v2 v2.100.1 sigs.k8s.io/kind v0.20.0 - sigs.k8s.io/yaml v1.3.0 + sigs.k8s.io/yaml v1.4.0 ) require ( diff --git a/go.sum b/go.sum index a9f3ca00..e4633e3d 100644 --- a/go.sum +++ b/go.sum @@ -786,5 +786,6 @@ sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From 864bacfb134a7cf2d3309152aee896216e4c19d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:58:25 +0000 Subject: [PATCH 456/542] Bump go.etcd.io/etcd/client/pkg/v3 from 3.5.9 to 3.5.10 Bumps [go.etcd.io/etcd/client/pkg/v3](https://github.com/etcd-io/etcd) from 3.5.9 to 3.5.10. - [Release notes](https://github.com/etcd-io/etcd/releases) - [Commits](https://github.com/etcd-io/etcd/compare/v3.5.9...v3.5.10) --- updated-dependencies: - dependency-name: go.etcd.io/etcd/client/pkg/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d0ce8d96..28b4f7b5 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 go.etcd.io/etcd/api/v3 v3.5.9 - go.etcd.io/etcd/client/pkg/v3 v3.5.9 + go.etcd.io/etcd/client/pkg/v3 v3.5.10 go.etcd.io/etcd/client/v3 v3.5.9 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 diff --git a/go.sum b/go.sum index a9f3ca00..7f2b3681 100644 --- a/go.sum +++ b/go.sum @@ -364,8 +364,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= -go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= From f0987424ef82f34b149f6df35eb8d3e3bdc7fc03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:58:36 +0000 Subject: [PATCH 457/542] Bump go.etcd.io/etcd/client/v3 from 3.5.9 to 3.5.10 Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.9 to 3.5.10. - [Release notes](https://github.com/etcd-io/etcd/releases) - [Commits](https://github.com/etcd-io/etcd/compare/v3.5.9...v3.5.10) --- updated-dependencies: - dependency-name: go.etcd.io/etcd/client/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index d0ce8d96..ec50fa37 100644 --- a/go.mod +++ b/go.mod @@ -21,9 +21,9 @@ require ( github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 - go.etcd.io/etcd/api/v3 v3.5.9 - go.etcd.io/etcd/client/pkg/v3 v3.5.9 - go.etcd.io/etcd/client/v3 v3.5.9 + go.etcd.io/etcd/api/v3 v3.5.10 + go.etcd.io/etcd/client/pkg/v3 v3.5.10 + go.etcd.io/etcd/client/v3 v3.5.10 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.13.0 @@ -98,7 +98,7 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect @@ -106,10 +106,10 @@ require ( golang.org/x/tools v0.13.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.1 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.58.3 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index a9f3ca00..a03b1930 100644 --- a/go.sum +++ b/go.sum @@ -362,12 +362,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= -go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= -go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= -go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= -go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -482,8 +482,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -699,12 +699,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 h1:9NWlQfY2ePejTmfwUH1OWwmznFa+0kKcHGPDvcPza9M= -google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= -google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -721,8 +721,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg= -google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 334590b88cd1683a5311f64a68379b752f4d03ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:58:58 +0000 Subject: [PATCH 458/542] Bump docker/login-action from 1 to 3 Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v1...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/main.yaml | 4 ++-- .github/workflows/release.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 85f5cc7a..b56733c2 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -17,12 +17,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Github Packages - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 93cd10b6..dc63123c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -17,12 +17,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Github Packages - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} From cf9fa5b30b35bc4c3b786c8f28827999986db54c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 02:59:03 +0000 Subject: [PATCH 459/542] Bump docker/setup-buildx-action from 1 to 3 Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 3. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v3) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/main.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 85f5cc7a..5b79b366 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v1 with: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 93cd10b6..b68c517f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v2 with: From 16c8deb0fe1e43e01e9e9ca968578ec6390b4206 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 02:25:42 +0000 Subject: [PATCH 460/542] Bump golang from 1.21.3-alpine3.18 to 1.21.4-alpine3.18 Bumps golang from 1.21.3-alpine3.18 to 1.21.4-alpine3.18. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile_iptables | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index c3f35da4..279ed318 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.3-alpine3.18 as dev +FROM golang:1.21.4-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index a4617a89..979289aa 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.3-alpine3.18 as dev +FROM golang:1.21.4-alpine3.18 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ From 259b31cef2cda66f7c0abc6847512cad20d0df3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 02:36:55 +0000 Subject: [PATCH 461/542] Bump github.com/onsi/gomega from 1.27.10 to 1.30.0 Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.27.10 to 1.30.0. - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.27.10...v1.30.0) --- updated-dependencies: - dependency-name: github.com/onsi/gomega dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d0ce8d96..f7660e95 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 github.com/onsi/ginkgo/v2 v2.13.0 - github.com/onsi/gomega v1.27.10 + github.com/onsi/gomega v1.30.0 github.com/osrg/gobgp/v3 v3.19.0 github.com/packethost/packngo v0.30.0 github.com/pkg/errors v0.9.1 @@ -56,7 +56,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect diff --git a/go.sum b/go.sum index a9f3ca00..600ef647 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -285,8 +285,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CTN21W18= github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= From a295b44d8356cd8516943adde1b3501bafe09716 Mon Sep 17 00:00:00 2001 From: Nicolas JENDROWIAK Date: Thu, 16 Nov 2023 12:16:03 +0100 Subject: [PATCH 462/542] [svc] Add annotation to specify DHCP lease host Signed-off-by: Nicolas JENDROWIAK --- Makefile | 2 +- docs/usage/on-prem/index.md | 21 +++++++++++++++++++++ pkg/manager/instance.go | 8 ++++++++ pkg/manager/services.go | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 33e3409b..97b736f6 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL := $(TARGET) # These will be provided to the target -VERSION := v0.6.3 +VERSION := v0.6.4 BUILD := `git rev-parse HEAD` diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md index 08b57d33..18dbcc34 100644 --- a/docs/usage/on-prem/index.md +++ b/docs/usage/on-prem/index.md @@ -142,6 +142,27 @@ kubernetes ClusterIP 10.96.0.1 443/TCP 17m nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s ``` +You can also specify a hostname used for the DHCP lease by adding an annotation to your service. + +``` +apiVersion: v1 +kind: Service +metadata: + name: nginx-dhcp + annotations: + kube-vip.io/loadbalancerHostname: mydhcp-test +spec: + loadBalancerIP: 0.0.0.0 + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: hello-world + type: LoadBalancer +``` + ### Using UPnP to expose a Service to the outside world With `kube-vip` > 0.2.1, it is possible to expose a Service of type `LoadBalancer` on a specific port to the Internet by using UPnP (on a supported gateway). diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 1fa96e17..6c1e587f 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -26,6 +26,7 @@ type Instance struct { dhcpInterface string dhcpInterfaceHwaddr string dhcpInterfaceIP string + dhcpHostname string dhcpClient *vip.DHCPClient // Kubernetes service mapping @@ -78,6 +79,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { if svc.Annotations != nil { instance.dhcpInterfaceHwaddr = svc.Annotations[hwAddrKey] instance.dhcpInterfaceIP = svc.Annotations[requestedIP] + instance.dhcpHostname = svc.Annotations[loadbalancerHostname] } // Generate Load Balancer config @@ -179,6 +181,12 @@ func (i *Instance) startDHCP() error { client := vip.NewDHCPClient(iface, initRebootFlag, i.dhcpInterfaceIP) + // Add hostname to dhcp client if annotated + if i.dhcpHostname != "" { + log.Infof("Hostname specified for dhcp lease: [%s] - [%s]", interfaceName, i.dhcpHostname) + client.WithHostName(i.dhcpHostname) + } + go client.Start() // Set that DHCP is enabled diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9a416d01..32b1757d 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -27,6 +27,7 @@ const ( endpoint = "kube-vip.io/active-endpoint" flushContrack = "kube-vip.io/flush-conntrack" loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" + loadbalancerHostname = "kube-vip.io/loadbalancerHostname" ) func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.WaitGroup) error { From f0de6767a3c123981fb2f403c0e44094c01033cb Mon Sep 17 00:00:00 2001 From: Nicolas JENDROWIAK Date: Fri, 24 Nov 2023 17:05:06 +0100 Subject: [PATCH 463/542] lint Signed-off-by: Nicolas JENDROWIAK --- pkg/manager/instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 6c1e587f..db9dc29b 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -26,7 +26,7 @@ type Instance struct { dhcpInterface string dhcpInterfaceHwaddr string dhcpInterfaceIP string - dhcpHostname string + dhcpHostname string dhcpClient *vip.DHCPClient // Kubernetes service mapping From 08abd3812a2a16d8cc5be1fa8dcbed1a1e03a334 Mon Sep 17 00:00:00 2001 From: Nicolas JENDROWIAK Date: Sat, 25 Nov 2023 18:16:41 +0100 Subject: [PATCH 464/542] Added trivy command in makefile Signed-off-by: Nicolas JENDROWIAK <75165555+shkuviak@users.noreply.github.com> --- Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile b/Makefile index 97b736f6..24579904 100644 --- a/Makefile +++ b/Makefile @@ -127,3 +127,14 @@ e2e-tests: service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services + +trivy: dockerx86ActionIPTables + docker run -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.47.0 \ + image \ + --format table \ + --exit-code 1 \ + --ignore-unfixed \ + --vuln-type 'os,library' \ + --severity 'CRITICAL,HIGH' \ + $(REPOSITORY)/$(TARGET):action + From e7b68cfd3a53d2b62772caddb6e33b382968b624 Mon Sep 17 00:00:00 2001 From: Nicolas JENDROWIAK <75165555+shkuviak@users.noreply.github.com> Date: Sat, 25 Nov 2023 18:21:13 +0100 Subject: [PATCH 465/542] Add upgrade command in Dockerfile_iptables Fix trivy warning on vulnerable libcrypto package -> No newer alpine image on dockerhub Signed-off-by: Nicolas JENDROWIAK <75165555+shkuviak@users.noreply.github.com> --- Dockerfile_iptables | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile_iptables b/Dockerfile_iptables index a4617a89..e9861151 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -12,8 +12,10 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ CGO_ENABLED=0 GOOS=linux make build FROM alpine:3.18.4 -# Add Certificates into the image, for anything that does API calls -RUN apk add --no-cache iptables +# Update pkgs and add iptables +RUN apk upgrade && \ + apk add --no-cache iptables + # Add kube-vip binary COPY --from=dev /src/kube-vip / ENTRYPOINT ["/kube-vip"] From 0f29b97dd44d64380e1b8f908b386e82518d3f60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 02:25:46 +0000 Subject: [PATCH 466/542] Bump anchore/sbom-action from 0.14.3 to 0.15.0 Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.14.3 to 0.15.0. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Commits](https://github.com/anchore/sbom-action/compare/v0.14.3...v0.15.0) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index db3b9def..b820853a 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -26,6 +26,6 @@ jobs: with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action - uses: anchore/sbom-action@v0.14.3 + uses: anchore/sbom-action@v0.15.0 with: format: cyclonedx-json From 1f1c7fe8191213ea0be6a2416ed99ca8ddf4a949 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 2 Dec 2023 16:32:12 +0000 Subject: [PATCH 467/542] Tidies up logging messages and redundant logic Signed-off-by: Dan Finneran --- cmd/kube-vip-start.go | 15 +++++---------- pkg/kubevip/config_types.go | 23 ----------------------- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/cmd/kube-vip-start.go b/cmd/kube-vip-start.go index 798e13a6..51f34e7f 100644 --- a/cmd/kube-vip-start.go +++ b/cmd/kube-vip-start.go @@ -9,13 +9,10 @@ import ( ) // Start as a single node (no cluster), start as a leader in the cluster -var ( - startConfig kubevip.Config - startConfigLB kubevip.LoadBalancer - startLocalPeer, startKubeConfigPath string - startRemotePeers, startBackends []string - inCluster bool -) +var startConfig kubevip.Config +var startConfigLB kubevip.LoadBalancer +var startLocalPeer, startKubeConfigPath string +var inCluster bool func init() { // Get the configuration file @@ -32,14 +29,12 @@ func init() { kubeVipStart.Flags().BoolVar(&startConfig.StartAsLeader, "startAsLeader", false, "Start this instance as the cluster leader") kubeVipStart.Flags().BoolVar(&startConfig.EnableARP, "arp", false, "Use ARP broadcasts to improve VIP re-allocations") kubeVipStart.Flags().StringVar(&startLocalPeer, "localPeer", "server1:192.168.0.1:10000", "Settings for this peer, format: id:address:port") - kubeVipStart.Flags().StringSliceVar(&startRemotePeers, "remotePeers", []string{"server2:192.168.0.2:10000", "server3:192.168.0.3:10000"}, "Comma separated remotePeers, format: id:address:port") + // Load Balancer flags kubeVipStart.Flags().BoolVar(&startConfigLB.BindToVip, "lbBindToVip", false, "Bind example load balancer to VIP") kubeVipStart.Flags().StringVar(&startConfigLB.Type, "lbType", "tcp", "Type of load balancer instance (TCP/HTTP)") kubeVipStart.Flags().StringVar(&startConfigLB.Name, "lbName", "Example Load Balancer", "The name of a load balancer instance") kubeVipStart.Flags().IntVar(&startConfigLB.Port, "lbPort", 8080, "Port that load balancer will expose on") - kubeVipStart.Flags().IntVar(&startConfigLB.BackendPort, "lbBackEndPort", 6443, "A port that all backends may be using (optional)") - kubeVipStart.Flags().StringSliceVar(&startBackends, "lbBackends", []string{"192.168.0.1:8080", "192.168.0.2:8080"}, "Comma separated backends, format: address:port") kubeVipStart.Flags().StringVar(&startConfigLB.ForwardingMethod, "lbForwardingMethod", "local", "The forwarding method of a load balancer instance") // Cluster configuration diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index acdb9f7b..f122ec26 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -1,8 +1,6 @@ package kubevip import ( - "net/url" - "github.com/kube-vip/kube-vip/pkg/bgp" ) @@ -195,27 +193,6 @@ type LoadBalancer struct { // BindToVip will bind the load balancer port to the VIP itself BindToVip bool `yaml:"bindToVip"` - // BackendPort, is a port that all backends are listening on (To be used to simplify building a list of backends) - BackendPort int `yaml:"backendPort"` - - // Backends, is an array of backend servers - Backends []BackEnd `yaml:"backends"` - // Forwarding method of LoadBalancer, either Local, Tunnel, DirectRoute or Bypass ForwardingMethod string `yaml:"forwardingMethod"` } - -// BackEnd is a server we will load balance over -type BackEnd struct { - // Backend Port to Load Balance to - Port int `yaml:"port"` - - // Address of a server/service - Address string `yaml:"address"` - - // URL is a raw URL to a backend service - RawURL string `yaml:"url,omitempty"` - - // ParsedURL - A validated URL to a backend - ParsedURL *url.URL `yaml:"parsedURL,omitempty"` -} From cfa2e93c76335e5f52400a767e4b28d096aef2ef Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 2 Dec 2023 16:32:30 +0000 Subject: [PATCH 468/542] Further cleaning Signed-off-by: Dan Finneran --- pkg/cluster/service.go | 32 +++++++++++++------------------- pkg/cluster/singleNode.go | 24 +++++++++--------------- pkg/manager/manager_arp.go | 5 +++-- pkg/manager/services.go | 2 +- pkg/manager/servicesLeader.go | 8 ++++---- pkg/manager/watch_services.go | 34 +++++++++++++++++++++++----------- pkg/vip/address.go | 27 +++++++++++++++++++++++++++ 7 files changed, 80 insertions(+), 52 deletions(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index d3e31e07..9bd896a8 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -182,11 +182,12 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser if ndp != nil { defer ndp.Close() } - log.Debugf("Broadcasting ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) + log.Debugf("(svcs) broadcasting ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) for { select { case <-ctx.Done(): // if cancel() execute + log.Debugf("(svcs) ending ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) return default: cluster.ensureIPAndSendGratuitous(c.Interface, ndp) @@ -198,13 +199,12 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser time.Sleep(time.Duration(c.ArpBroadcastRate) * time.Millisecond) } }(ctxArp) - log.Debugf("ending ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) } 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.IP(), c.VIPCIDR) - log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) + log.Debugf("(svcs) attempting to advertise the address [%s] over BGP", cidrVip) err = bgp.AddHost(cidrVip) if err != nil { log.Error(err) @@ -212,24 +212,18 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } go func() { - //nolint - for { - select { - case <-cluster.stop: - // Stop the Arp context if it is running - cancelArp() - - log.Info("[LOADBALANCER] Stopping load balancers") - log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } + <-cluster.stop + // Stop the Arp context if it is running + cancelArp() - close(cluster.completed) - return - } + log.Info("[LOADBALANCER] Stopping load balancers") + log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) + err = cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) } + + close(cluster.completed) }() } diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index c8440b38..e7d871d3 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -45,23 +45,17 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro } go func() { - //nolint - for { - select { - case <-cluster.stop: - - if !disableVIP { - - log.Info("[VIP] Releasing the Virtual IP") - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) - } - } - close(cluster.completed) - return + <-cluster.stop + + if !disableVIP { + + log.Info("[VIP] Releasing the Virtual IP") + err := cluster.Network.DeleteIP() + if err != nil { + log.Warnf("%v", err) } } + close(cluster.completed) }() log.Infoln("Started Load Balancer and Virtual IP") return nil diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 11dc88f2..1860589c 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -104,9 +104,10 @@ func (sm *Manager) startARP() error { if os.Getenv("EGRESS_CLEAN") != "" { i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, sm.config.ServiceNamespace) if err != nil { - log.Warnf("[egress] Unable to clean any dangling egress rules [%v]", err) + log.Warnf("(egress) Unable to clean any dangling egress rules [%v]", 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") + log.Info("(egress) Cleaning any dangling kube-vip egress rules") cleanErr := i.CleanIPtables() if cleanErr != nil { log.Errorf("Error cleaning rules [%v]", cleanErr) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 9a416d01..a97a29a5 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -90,7 +90,7 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - log.Infof("[service] adding VIP [%s] for [%s/%s]", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + log.Infof("(svcs) adding VIP [%s] for [%s/%s]", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 46ad0275..1328439a 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -40,7 +40,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. } serviceLease := fmt.Sprintf("kubevip-%s", service.Name) - log.Infof("[services election] for service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, id) + log.Infof("(svc election) service [%s], namespace [%s], lock name [%s], host id [%s]", service.Name, service.Namespace, serviceLease, 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{ @@ -82,7 +82,7 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. }, OnStoppedLeading: func() { // we can do cleanup here - log.Infof("[services election] service [%s] leader lost: [%s]", service.Name, id) + log.Infof("(svc election) service [%s] leader lost: [%s]", service.Name, id) if activeService[string(service.UID)] { if err := sm.deleteService(string(service.UID)); err != nil { log.Errorln(err) @@ -97,10 +97,10 @@ func (sm *Manager) StartServicesLeaderElection(ctx context.Context, service *v1. // I just got the lock return } - log.Infof("[services election] new leader elected: %s", identity) + log.Infof("(svc election) new leader elected: %s", identity) }, }, }) - log.Infof("[services election] for service [%s] stopping", service.Name) + log.Infof("(svc election) for service [%s] stopping", service.Name) return nil } diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 0dbf4f4f..e086fb2e 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -7,6 +7,7 @@ import ( "sync" "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" @@ -51,9 +52,9 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context 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("starting services watcher for all namespaces") + log.Infof("(svcs) starting services watcher for all namespaces") } else { - log.Infof("starting services watcher for services in namespace [%s]", sm.config.ServiceNamespace) + log.Infof("(svcs) starting services watcher for services in namespace [%s]", sm.config.ServiceNamespace) } // Use a restartable watcher, as this should help in the event of etcd or timeout issues @@ -69,12 +70,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context go func() { select { case <-sm.shutdownChan: - log.Debug("[services] shutdown called") + log.Debug("(svcs) shutdown called") // Stop the retry watcher rw.Stop() return case <-exitFunction: - log.Debug("[services] function ending") + log.Debug("(svcs) function ending") // Stop the retry watcher rw.Stop() return @@ -109,26 +110,37 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context 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("service [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass) + log.Infof("(svcs) [%s] specified the loadBalancer class [%s], ignoring", svc.Name, *svc.Spec.LoadBalancerClass) break } } 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("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.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) break } // Check if we ignore this service if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) + log.Infof("(svcs) [%s] has an ignore annotation for kube-vip", svc.Name) break } - log.Debugf("service [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddress(svc)) - + // The modified event should only be triggered if the service has been modified (i.e. moved somewhere else) + if event.Type == watch.Modified { + //log.Debugf("(svcs) Retreiving local addresses, to ensure that this modified address doesn't exist") + f, err := vip.GarbageCollect(sm.config.Interface, svc.Spec.LoadBalancerIP) + if err != nil { + log.Errorf("(svcs) cleaning existing address error: [%s]", err.Error()) + } + if f { + log.Warnf("(svcs) already found existing address [%s] on adapter [%s]", svc.Spec.LoadBalancerIP, sm.config.Interface) + } + } // Scenarios: // 1. if !activeService[string(svc.UID)] { + log.Debugf("(svcs) [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddress(svc)) + wg.Add(1) activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) // Background the services election @@ -187,7 +199,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("service [%s] has an ignore annotation for kube-vip", svc.Name) + log.Infof("(svcs) [%s] has an ignore annotation for kube-vip", svc.Name) break } // If this is an active service then and additional leaderElection will handle stopping @@ -204,7 +216,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context activeService[string(svc.UID)] = false watchedService[string(svc.UID)] = false } - log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) + log.Infof("(svcs) [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used case watch.Error: diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 98e27991..c916fca5 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -422,3 +422,30 @@ func (configurator *network) DDNSHostName() string { func (configurator *network) Interface() string { return configurator.link.Attrs().Name } + +func GarbageCollect(adapter, address string) (found bool, err error) { + + // Get adapter + link, err := netlink.LinkByName(adapter) + if err != nil { + return true, errors.Wrapf(err, "could not get link for interface '%s'", adapter) + } + + // Get addresses on adapter + addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL) + if err != nil { + return false, err + } + + // Compare all addresses to new service address, and remove if needed + for _, existing := range addrs { + if existing.IP.String() == address { + found = true + if err = netlink.AddrDel(link, &existing); err != nil { + return true, errors.Wrap(err, "could not delete ip") + } + } + } + + return false, nil // Didn't find the address on the adapter +} From 68c9e4948036270addba5630293976f7d1c9d23c Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 2 Dec 2023 16:38:56 +0000 Subject: [PATCH 469/542] linting fixes. Signed-off-by: Dan Finneran --- pkg/vip/address.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/vip/address.go b/pkg/vip/address.go index c916fca5..fc2c15c5 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -440,12 +440,14 @@ func GarbageCollect(adapter, address string) (found bool, err error) { // Compare all addresses to new service address, and remove if needed for _, existing := range addrs { if existing.IP.String() == address { + // We've found the existing address found = true + // linting issue + existing := existing if err = netlink.AddrDel(link, &existing); err != nil { return true, errors.Wrap(err, "could not delete ip") } } } - - return false, nil // Didn't find the address on the adapter + return // Didn't find the address on the adapter } From b0f7aa169860a4022329bb5be0f883a1830d89f9 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 3 Dec 2023 10:32:51 +0000 Subject: [PATCH 470/542] Fixes to linting for routing table Signed-off-by: Dan Finneran --- go.sum | 1 + pkg/cluster/service.go | 18 +++++++++--------- pkg/vip/address.go | 12 ++++++------ 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/go.sum b/go.sum index 052cc0fb..1795cd49 100644 --- a/go.sum +++ b/go.sum @@ -157,6 +157,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 84c6c01d..d57264ba 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -216,16 +216,16 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // Stop the Arp context if it is running cancelArp() - if c.EnableRoutingTable { - err = cluster.Network.DeleteRoute() - if err != nil { - log.Warnf("%v", err) - } - } - - close(cluster.completed) - return + if c.EnableRoutingTable { + err = cluster.Network.DeleteRoute() + if err != nil { + log.Warnf("%v", err) } + + close(cluster.completed) + return + } + log.Info("[LOADBALANCER] Stopping load balancers") log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) err = cluster.Network.DeleteIP() diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 193c11ec..086b76a3 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -124,12 +124,12 @@ func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID // AddRoute - Add an IP address to a route table func (configurator *network) AddRoute() error { - route_scope := netlink.SCOPE_UNIVERSE + routeScope := netlink.SCOPE_UNIVERSE if configurator.routingTableType == unix.RTN_LOCAL { - route_scope = netlink.SCOPE_LINK + routeScope = netlink.SCOPE_LINK } route := &netlink.Route{ - Scope: route_scope, + Scope: routeScope, Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, @@ -140,12 +140,12 @@ func (configurator *network) AddRoute() error { // DeleteRoute - Delete an IP address from a route table func (configurator *network) DeleteRoute() error { - route_scope := netlink.SCOPE_UNIVERSE + routeScope := netlink.SCOPE_UNIVERSE if configurator.routingTableType == unix.RTN_LOCAL { - route_scope = netlink.SCOPE_LINK + routeScope = netlink.SCOPE_LINK } route := &netlink.Route{ - Scope: route_scope, + Scope: routeScope, Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, From 100da0a3a51d84c393b87b726a486e3a4c3f1675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Dec 2023 10:35:14 +0000 Subject: [PATCH 471/542] Bump github.com/cloudflare/ipvs from 0.9.1 to 0.10.1 Bumps [github.com/cloudflare/ipvs](https://github.com/cloudflare/ipvs) from 0.9.1 to 0.10.1. - [Release notes](https://github.com/cloudflare/ipvs/releases) - [Commits](https://github.com/cloudflare/ipvs/compare/v0.9.1...v0.10.1) --- updated-dependencies: - dependency-name: github.com/cloudflare/ipvs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 16 +++++++++++++--- go.sum | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index fddfe3c7..92bf2b56 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/kube-vip/kube-vip go 1.19 require ( - github.com/cloudflare/ipvs v0.9.1 + github.com/cloudflare/ipvs v0.10.1 github.com/davecgh/go-spew v1.1.1 github.com/florianl/go-conntrack v0.4.0 github.com/golang/protobuf v1.5.3 @@ -87,23 +87,28 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.16.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect + github.com/tj/go-spin v1.1.0 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect + github.com/xlab/c-for-go v0.0.0-20230906092656-a1822f0a09c1 // indirect + github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.14.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sync v0.3.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect @@ -117,6 +122,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + modernc.org/cc/v4 v4.1.0 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.1.3 // indirect + modernc.org/token v1.0.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 052cc0fb..4554275b 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/ipvs v0.9.1 h1:4azDqbWqNAkcuD78yK9y9rxZoQfW2OnC9DFo+y7HPgk= -github.com/cloudflare/ipvs v0.9.1/go.mod h1:5H4icNJZ8T4H7bg0/THRew5BbNOkDgl2RC1twjeSOHU= +github.com/cloudflare/ipvs v0.10.1 h1:rRP+HtkATKJd62iGulRq3hg+oh/kJyttFLizGO4aB3I= +github.com/cloudflare/ipvs v0.10.1/go.mod h1:HBnpmdbOqfYEz7Qkix+IdMfu+7lnPL/5o8iWTXrc5ZQ= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -74,6 +74,7 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= @@ -157,6 +158,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -291,6 +293,7 @@ github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CTN21W18= github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -314,6 +317,8 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -350,6 +355,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= @@ -357,6 +364,10 @@ github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhg github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xlab/c-for-go v0.0.0-20230906092656-a1822f0a09c1 h1:d9k72yL7DUmIZJPaqsh+mMWlKOfv+drGA2D8I55SnjA= +github.com/xlab/c-for-go v0.0.0-20230906092656-a1822f0a09c1/go.mod h1:NYjqfg762bzbQeElSH5apzukcCvK3Vxa8pA2jci6T4s= +github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 h1:Sw125DKxZhPUI4JLlWugkzsrlB50jR9v2khiD9FxuSo= +github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245/go.mod h1:C+diUUz7pxhNY6KAoLgrTYARGWnt82zWTylZlxT92vk= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -426,7 +437,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -495,8 +507,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -626,8 +638,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -777,6 +789,17 @@ k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5Ohx k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/cc/v4 v4.1.0 h1:PlApAKux1sNvreOGs1Hr04FFz35QmAWoa98YFjcdH94= +modernc.org/cc/v4 v4.1.0/go.mod h1:T6KFXc8WI0m9k6IOHuRe9+vB+Pb/AaV8BMZoVqHLm1I= +modernc.org/ccorpus2 v1.1.0 h1:r/Z2+wOD5Tmcs1AMVXJgslE9HgRRROVWo0qUox1kJIo= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 9835fd44102831862bb0fca4becfe6fcceb1f5f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 02:34:43 +0000 Subject: [PATCH 472/542] Bump golang.org/x/sys from 0.13.0 to 0.15.0 Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.15.0. - [Commits](https://github.com/golang/sys/compare/v0.13.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fddfe3c7..d96ea782 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( go.etcd.io/etcd/client/v3 v3.5.10 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 - golang.org/x/sys v0.13.0 + golang.org/x/sys v0.15.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 k8s.io/api v0.28.3 k8s.io/apimachinery v0.28.3 diff --git a/go.sum b/go.sum index 1795cd49..82884122 100644 --- a/go.sum +++ b/go.sum @@ -557,8 +557,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= From b72ae63060bfc4a78d022e82ef38a15cd9bc7162 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 02:35:08 +0000 Subject: [PATCH 473/542] Bump github.com/prometheus/client_golang from 1.16.0 to 1.17.0 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.16.0 to 1.17.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.16.0...v1.17.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index fddfe3c7..04fd3ea3 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/osrg/gobgp/v3 v3.19.0 github.com/packethost/packngo v0.30.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.16.0 + github.com/prometheus/client_golang v1.17.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 @@ -84,9 +84,9 @@ require ( github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect diff --git a/go.sum b/go.sum index 1795cd49..6e81c802 100644 --- a/go.sum +++ b/go.sum @@ -306,15 +306,15 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= From c79fff8d86d121c34ceb354e1da5e574738c3731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:30:58 +0000 Subject: [PATCH 474/542] Bump anchore/sbom-action from 0.15.0 to 0.15.1 Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.0 to 0.15.1. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Commits](https://github.com/anchore/sbom-action/compare/v0.15.0...v0.15.1) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index b820853a..b4fb5af5 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -26,6 +26,6 @@ jobs: with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action - uses: anchore/sbom-action@v0.15.0 + uses: anchore/sbom-action@v0.15.1 with: format: cyclonedx-json From b0c344298c7fa4e7075b0464b109b4a1eb9a61a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:31:01 +0000 Subject: [PATCH 475/542] Bump actions/setup-go from 4 to 5 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8dc1d49e..3aa75088 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: All checks @@ -28,7 +28,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run tests @@ -40,7 +40,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run tests @@ -52,7 +52,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Build image locally @@ -66,7 +66,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Build image with iptables From 5b48797f8af37f122ac689eea2cc6ffdf01520b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:36:30 +0000 Subject: [PATCH 476/542] Bump golang from 1.21.4-alpine3.18 to 1.21.5-alpine3.18 Bumps golang from 1.21.4-alpine3.18 to 1.21.5-alpine3.18. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile_iptables | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 279ed318..6092cb05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.4-alpine3.18 as dev +FROM golang:1.21.5-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 10935230..8d3d1b17 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.4-alpine3.18 as dev +FROM golang:1.21.5-alpine3.18 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ From be404237bdd9682231002e9a195034d85200d6e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 02:36:33 +0000 Subject: [PATCH 477/542] Bump alpine from 3.18.4 to 3.19.0 Bumps alpine from 3.18.4 to 3.19.0. --- updated-dependencies: - dependency-name: alpine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Dockerfile_iptables | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 10935230..8a282a28 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -11,7 +11,7 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ CGO_ENABLED=0 GOOS=linux make build -FROM alpine:3.18.4 +FROM alpine:3.19.0 # Update pkgs and add iptables RUN apk upgrade && \ apk add --no-cache iptables From dfd8b382684932242ec156b0640c20223f892235 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:07:59 +0000 Subject: [PATCH 478/542] Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.2 Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.0 to 2.13.2. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.0...v2.13.2) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 8 ++++---- go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index d96ea782..14304a90 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 - github.com/onsi/ginkgo/v2 v2.13.0 + github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 github.com/osrg/gobgp/v3 v3.19.0 github.com/packethost/packngo v0.30.0 @@ -49,7 +49,7 @@ require ( github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -99,11 +99,11 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sync v0.3.0 // indirect + golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect diff --git a/go.sum b/go.sum index 82884122..037f5a16 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -284,8 +284,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= +github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= @@ -427,7 +427,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,8 +496,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -627,8 +627,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 079423f2184886692330f84c8199523f6054eabc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:09:01 +0000 Subject: [PATCH 479/542] Bump k8s.io/api from 0.28.3 to 0.28.4 Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.28.3 to 0.28.4. - [Commits](https://github.com/kubernetes/api/compare/v0.28.3...v0.28.4) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index d96ea782..44b207f2 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,8 @@ require ( golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.15.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - k8s.io/api v0.28.3 - k8s.io/apimachinery v0.28.3 + k8s.io/api v0.28.4 + k8s.io/apimachinery v0.28.4 k8s.io/client-go v0.28.3 k8s.io/klog/v2 v2.100.1 sigs.k8s.io/kind v0.20.0 diff --git a/go.sum b/go.sum index 82884122..f48ed383 100644 --- a/go.sum +++ b/go.sum @@ -766,10 +766,10 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= -k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= -k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= -k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= From 9c79e88ccbb34b50a6d1d8fbc74f4ee292f3b3c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 02:19:34 +0000 Subject: [PATCH 480/542] Bump github/codeql-action from 2 to 3 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2...v3) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f640e08d..d40b2915 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,7 +53,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +67,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From d21ce886a2c88b534d88816946c671dc2580a3c6 Mon Sep 17 00:00:00 2001 From: Edwin Xie Date: Thu, 14 Dec 2023 05:31:53 +0000 Subject: [PATCH 481/542] Preliminary support for dualstack loadbalancer services Signed-off-by: Edwin Xie --- pkg/manager/instance.go | 78 ++++++++++++++++------------ pkg/manager/manager_arp.go | 6 ++- pkg/manager/manager_table.go | 6 ++- pkg/manager/manager_wireguard.go | 6 ++- pkg/manager/services.go | 88 ++++++++++++++++++++++---------- pkg/manager/servicesLeader.go | 6 ++- pkg/manager/watch_services.go | 5 +- 7 files changed, 124 insertions(+), 71 deletions(-) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 004f6992..488d6f18 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -13,13 +13,13 @@ import ( "github.com/kube-vip/kube-vip/pkg/vip" ) -// Instance defines an instance of everything needed to manage a vip +// Instance defines an instance of everything needed to manage vips type Instance struct { // Virtual IP / Load Balancer configuration - vipConfig *kubevip.Config + vipConfigs []*kubevip.Config - // cluster instance - cluster *cluster.Cluster + // cluster instances + clusters []*cluster.Cluster // Service uses DHCP isDHCP bool @@ -30,7 +30,7 @@ type Instance struct { dhcpClient *vip.DHCPClient // Kubernetes service mapping - Vip string + VIPs []string Port int32 UID string Type string @@ -39,7 +39,7 @@ type Instance struct { } func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { - instanceAddress := fetchServiceAddress(svc) + instanceAddresses := fetchServiceAddresses(svc) instanceUID := string(svc.UID) // Detect if we're using a specific interface for services @@ -50,26 +50,30 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { serviceInterface = config.Interface } - // Generate new Virtual IP configuration - newVip := &kubevip.Config{ - VIP: instanceAddress, // TODO support more than one vip? - Interface: serviceInterface, - SingleNode: true, - EnableARP: config.EnableARP, - EnableBGP: config.EnableBGP, - VIPCIDR: config.VIPCIDR, - VIPSubnet: config.VIPSubnet, - EnableRoutingTable: config.EnableRoutingTable, - RoutingTableID: config.RoutingTableID, - RoutingTableType: config.RoutingTableType, - ArpBroadcastRate: config.ArpBroadcastRate, - EnableServiceSecurity: config.EnableServiceSecurity, + var newVips []*kubevip.Config + + for _, address := range instanceAddresses { + // Generate new Virtual IP configuration + newVips = append(newVips, &kubevip.Config{ + VIP: address, + Interface: serviceInterface, + SingleNode: true, + EnableARP: config.EnableARP, + EnableBGP: config.EnableBGP, + VIPCIDR: config.VIPCIDR, + VIPSubnet: config.VIPSubnet, + EnableRoutingTable: config.EnableRoutingTable, + RoutingTableID: config.RoutingTableID, + RoutingTableType: config.RoutingTableType, + ArpBroadcastRate: config.ArpBroadcastRate, + EnableServiceSecurity: config.EnableServiceSecurity, + }) } // Create new service instance := &Instance{ UID: instanceUID, - Vip: instanceAddress, + VIPs: instanceAddresses, serviceSnapshot: svc, } if len(svc.Spec.Ports) > 0 { @@ -90,14 +94,17 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { Type: instance.Type, BindToVip: true, } - // Add Load Balancer Configuration - newVip.LoadBalancers = append(newVip.LoadBalancers, newLB) + for _, vip := range newVips { + // Add Load Balancer Configuration + vip.LoadBalancers = append(vip.LoadBalancers, newLB) + } // Create Add configuration to the new service - instance.vipConfig = newVip + instance.vipConfigs = newVips // If this was purposely created with the address 0.0.0.0, // we will create a macvlan on the main interface and a DHCP client - if instanceAddress == "0.0.0.0" { + // TODO: Consider how best to handle DHCP with multiple addresses + if len(instanceAddresses) == 1 && instanceAddresses[0] == "0.0.0.0" { err := instance.startDHCP() if err != nil { return nil, err @@ -107,24 +114,29 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { return nil, fmt.Errorf("error starting DHCP for %s/%s: error: %s", instance.serviceSnapshot.Namespace, instance.serviceSnapshot.Name, err) case ip := <-instance.dhcpClient.IPChannel(): - instance.vipConfig.VIP = ip + instance.vipConfigs[0].VIP = ip instance.dhcpInterfaceIP = ip } } + 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) + return nil, err + } + c.Network.SetServicePorts(svc) + instance.clusters = append(instance.clusters, c) - c, err := cluster.InitCluster(instance.vipConfig, false) - if err != nil { - log.Errorf("Failed to add Service %s/%s", svc.Namespace, svc.Name) - return nil, err } - c.Network.SetServicePorts(svc) - instance.cluster = c return instance, nil } func (i *Instance) startDHCP() error { - parent, err := netlink.LinkByName(i.vipConfig.Interface) + if len(i.vipConfigs) != 1 { + return fmt.Errorf("DHCP requires exactly 1 VIP config, got: %v", len(i.vipConfigs)) + } + parent, err := netlink.LinkByName(i.vipConfigs[0].Interface) if err != nil { return fmt.Errorf("error finding VIP Interface, for building DHCP Link : %v", err) } diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 1860589c..477fc5b8 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -162,8 +162,10 @@ func (sm *Manager) startARP() error { OnStoppedLeading: func() { // we can do cleanup here log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + for _, instance := range sm.serviceInstances { + for _, cluster := range instance.clusters { + cluster.Stop() + } } log.Fatal("lost leadership, restarting kube-vip") diff --git a/pkg/manager/manager_table.go b/pkg/manager/manager_table.go index eb16b11f..274bbb67 100644 --- a/pkg/manager/manager_table.go +++ b/pkg/manager/manager_table.go @@ -89,8 +89,10 @@ func (sm *Manager) startTableMode() error { OnStoppedLeading: func() { // we can do cleanup here log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + for _, instance := range sm.serviceInstances { + for _, cluster := range instance.clusters { + cluster.Stop() + } } log.Fatal("lost leadership, restarting kube-vip") diff --git a/pkg/manager/manager_wireguard.go b/pkg/manager/manager_wireguard.go index a17c2c97..0f84b957 100644 --- a/pkg/manager/manager_wireguard.go +++ b/pkg/manager/manager_wireguard.go @@ -121,8 +121,10 @@ func (sm *Manager) startWireguard() error { OnStoppedLeading: func() { // we can do cleanup here log.Infof("leader lost: %s", id) - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + for _, instance := range sm.serviceInstances { + for _, cluster := range instance.clusters { + cluster.Stop() + } } log.Fatal("lost leadership, restarting kube-vip") diff --git a/pkg/manager/services.go b/pkg/manager/services.go index f0d3dbfe..440b29ab 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -37,17 +37,22 @@ func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.Wai // Iterate through the synchronising services foundInstance := false - newServiceAddress := fetchServiceAddress(svc) + newServiceAddresses := fetchServiceAddresses(svc) newServiceUID := string(svc.UID) + firstServiceAddress := "" + if len(newServiceAddresses) > 0 { + firstServiceAddress = newServiceAddresses[0] + } + for x := range sm.serviceInstances { if sm.serviceInstances[x].UID == newServiceUID { - log.Debugf("isDHCP: %t, newServiceAddress: %s", sm.serviceInstances[x].isDHCP, newServiceAddress) + log.Debugf("isDHCP: %t, newServiceAddresses: %s", sm.serviceInstances[x].isDHCP, newServiceAddresses) // 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") || - (!sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0") || + if (sm.serviceInstances[x].isDHCP && firstServiceAddress != "0.0.0.0") || + (!sm.serviceInstances[x].isDHCP && firstServiceAddress == "0.0.0.0") || (!sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && - newServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP) || + firstServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP) || (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) || (sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && sm.serviceInstances[x].dhcpInterfaceIP != svc.Status.LoadBalancer.Ingress[0].IP) { @@ -61,7 +66,7 @@ func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.Wai } // This instance wasn't found, we need to add it to the manager - if !foundInstance && newServiceAddress != "" { + if !foundInstance && firstServiceAddress != "" { if err := sm.addService(svc); err != nil { return err } @@ -91,17 +96,19 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - log.Infof("(svcs) adding VIP [%s] for [%s/%s]", newService.Vip, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + log.Infof("(svcs) adding VIP(s) [%s] for [%s/%s]", newService.VIPs, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) - newService.cluster.StartLoadBalancerService(newService.vipConfig, sm.bgpServer) + for x := range newService.vipConfigs { + newService.clusters[x].StartLoadBalancerService(newService.vipConfigs[x], sm.bgpServer) + } sm.upnpMap(newService) - if newService.isDHCP { + if newService.isDHCP && len(newService.vipConfigs) == 1 { go func() { for ip := range newService.dhcpClient.IPChannel() { log.Debugf("IP %s may have changed", ip) - newService.vipConfig.VIP = ip + newService.vipConfigs[0].VIP = ip newService.dhcpInterfaceIP = ip if err := sm.updateStatus(newService); err != nil { log.Warnf("error updating svc: %s", err) @@ -121,11 +128,14 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - serviceIP := fetchServiceAddress(svc) + // TODO: Currently this only implements egress for the primary load balancer + // IP of the service + serviceIPs := fetchServiceAddresses(svc) // Check if we need to flush any conntrack connections (due to some dangling conntrack connections) - if svc.Annotations[flushContrack] == "true" { + if svc.Annotations[flushContrack] == "true" && len(serviceIPs) > 0 { log.Debugf("Flushing conntrack rules for service [%s]", svc.Name) + serviceIP := serviceIPs[0] err = vip.DeleteExistingSessions(serviceIP, false) if err != nil { log.Errorf("Error flushing any remaining egress connections [%s]", err) @@ -137,8 +147,9 @@ func (sm *Manager) addService(svc *v1.Service) error { } // Check if egress is enabled on the service, if so we'll need to configure some rules - if svc.Annotations[egress] == "true" { + if svc.Annotations[egress] == "true" && len(serviceIPs) > 0 { log.Debugf("Enabling egress for the service [%s]", svc.Name) + serviceIP := serviceIPs[0] if svc.Annotations[endpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() @@ -156,6 +167,7 @@ func (sm *Manager) addService(svc *v1.Service) error { } } } + finishTime := time.Since(startTime) log.Infof("[service] synchronised in %dms", finishTime.Milliseconds()) @@ -188,13 +200,21 @@ func (sm *Manager) deleteService(uid string) error { return nil } shared := false + vipSet := make(map[string]interface{}) for x := range updatedInstances { - if updatedInstances[x].Vip == serviceInstance.Vip { + for _, vip := range updatedInstances[x].VIPs { + vipSet[vip] = nil + } + } + for _, vip := range serviceInstance.VIPs { + if _, found := vipSet[vip]; found { shared = true } } if !shared { - serviceInstance.cluster.Stop() + for x := range serviceInstance.clusters { + serviceInstance.clusters[x].Stop() + } if serviceInstance.isDHCP { serviceInstance.dhcpClient.Stop() macvlan, err := netlink.LinkByName(serviceInstance.dhcpInterface) @@ -207,8 +227,9 @@ func (sm *Manager) deleteService(uid string) error { return fmt.Errorf("error deleting DHCP Link : %v", err) } } - if serviceInstance.vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfig.VIP, serviceInstance.vipConfig.VIPCIDR) + // TODO: Implement dual-stack loadbalancer support if BGP is enabled + if serviceInstance.vipConfigs[0].EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfigs[0].VIP, serviceInstance.vipConfigs[0].VIPCIDR) err := sm.bgpServer.DelHost(cidrVip) return err } @@ -237,9 +258,10 @@ func (sm *Manager) deleteService(uid string) error { func (sm *Manager) upnpMap(s *Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() - if sm.upnp != nil { - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.Vip, s.Port, s.serviceSnapshot.Name) - if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.Vip, strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { + // TODO: Handle upnp in the dualstack case + if sm.upnp != nil && len(s.VIPs) == 1 { + log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.VIPs[0], s.Port, s.serviceSnapshot.Name) + if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.VIPs[0], strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { log.Infof("service should be accessible externally on port [%d]", s.Port) } else { sm.upnp.Reclaim() @@ -290,10 +312,14 @@ func (sm *Manager) updateStatus(i *Instance) error { Protocol: port.Protocol, }) } - updatedService.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{ - IP: i.vipConfig.VIP, - Ports: ports, - }} + var ingresses []v1.LoadBalancerIngress + for _, vipConfig := range i.vipConfigs { + ingresses = append(ingresses, v1.LoadBalancerIngress{ + IP: vipConfig.VIP, + Ports: ports, + }) + } + updatedService.Status.LoadBalancer.Ingress = ingresses _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) if err != nil { log.Errorf("Error updating Service %s/%s Status: %v", i.serviceSnapshot.Namespace, i.serviceSnapshot.Name, err) @@ -309,13 +335,19 @@ func (sm *Manager) updateStatus(i *Instance) error { return nil } -// fetchServiceAddress tries to get the address from annotations +// fetchServiceAddresses tries to get the addresses from annotations // kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP -func fetchServiceAddress(s *v1.Service) string { +// May return []string{""} (with length 1) if neither exist. +func fetchServiceAddresses(s *v1.Service) []string { if s.Annotations != nil { if v, ok := s.Annotations[loadbalancerIPAnnotation]; ok { - return v + ips := strings.Split(v, ",") + var trimmedIPs []string + for _, ip := range ips { + trimmedIPs = append(trimmedIPs, strings.TrimSpace(ip)) + } + return trimmedIPs } } - return s.Spec.LoadBalancerIP + return []string{s.Spec.LoadBalancerIP} } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 1328439a..4161afed 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -22,8 +22,10 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro return err } - for x := range sm.serviceInstances { - sm.serviceInstances[x].cluster.Stop() + for _, instance := range sm.serviceInstances { + for _, cluster := range instance.clusters { + cluster.Stop() + } } log.Infof("Shutting down kube-Vip") diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index e086fb2e..7b406140 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -102,7 +102,8 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } // We only care about LoadBalancer services that have been allocated an address - if fetchServiceAddress(svc) == "" { + serviceAddresses := fetchServiceAddresses(svc) + if len(serviceAddresses) == 0 || serviceAddresses[0] == "" { break } @@ -139,7 +140,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Scenarios: // 1. if !activeService[string(svc.UID)] { - log.Debugf("(svcs) [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddress(svc)) + log.Debugf("(svcs) [%s] has been added/modified with addresses [%s]", svc.Name, fetchServiceAddresses(svc)) wg.Add(1) activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) From e22ee4de74cf10bc184ce3f24f92cc61cead8258 Mon Sep 17 00:00:00 2001 From: Edwin Xie Date: Fri, 15 Dec 2023 23:46:12 +0000 Subject: [PATCH 482/542] Add service test for dualstack LB services Signed-off-by: Edwin Xie --- testing/e2e/services/kind.go | 4 ++ testing/e2e/services/kubernetes.go | 46 ++++++++++++++++------ testing/e2e/services/services.go | 63 +++++++++++++++++++++++++++--- testing/e2e/services/tests.go | 7 ++++ 4 files changed, 104 insertions(+), 16 deletions(-) diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index 78310349..28db707a 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -42,6 +42,10 @@ func (config *testConfig) createKind() error { // Change Networking Family clusterConfig.Networking.IPFamily = kindconfigv1alpha4.IPv6Family } + if config.Dualstack { + // Change Networking Family + clusterConfig.Networking.IPFamily = kindconfigv1alpha4.DualStackFamily + } if config.ControlPlane { err := config.manifestGen() diff --git a/testing/e2e/services/kubernetes.go b/testing/e2e/services/kubernetes.go index 114c204c..d97d4835 100644 --- a/testing/e2e/services/kubernetes.go +++ b/testing/e2e/services/kubernetes.go @@ -18,10 +18,11 @@ import ( // service defines the settings for a new service type service struct { - name string - egress bool // enable egress - policyLocal bool // set the policy to local pods - testHTTP bool + name string + egress bool // enable egress + policyLocal bool // set the policy to local pods + testHTTP bool + testDualstack bool // test dualstack loadbalancer services } type deployment struct { @@ -193,7 +194,7 @@ func (d *deployment) createDeployment(ctx context.Context, clientset *kubernetes return nil } -func (s *service) createService(ctx context.Context, clientset *kubernetes.Clientset) (currentLeader string, loadBalancerAddress string, err error) { +func (s *service) createService(ctx context.Context, clientset *kubernetes.Clientset) (currentLeader string, loadBalancerAddresses []string, err error) { svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: s.name, @@ -227,6 +228,25 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyTypeLocal } + if s.testDualstack { + if svc.Annotations == nil { + svc.Annotations = make(map[string]string) + } + ipv4VIP, err := generateIPv4VIP() + if err != nil { + log.Fatal(err) + } + ipv6VIP, err := generateIPv6VIP() + if err != nil { + log.Fatal(err) + } + svc.Annotations["kube-vip.io/loadbalancerIPs"] = fmt.Sprintf("%s,%s", ipv4VIP, ipv6VIP) + svc.Labels["implementation"] = "kube-vip" + svc.Spec.IPFamilies = []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol} + ipfPolicy := v1.IPFamilyPolicyRequireDualStack + svc.Spec.IPFamilyPolicy = &ipfPolicy + } + log.Infof("🌍 creating service [%s]", svc.Name) _, err = clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, svc, metav1.CreateOptions{}) if err != nil { @@ -261,9 +281,11 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien } if svc.Name == s.name { if len(svc.Status.LoadBalancer.Ingress) != 0 { - log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) + for _, ingress := range svc.Status.LoadBalancer.Ingress { + loadBalancerAddresses = append(loadBalancerAddresses, ingress.IP) + } + log.Infof("🔎 found load balancer addresses [%s] on node [%s]", loadBalancerAddresses, svc.Annotations["kube-vip.io/vipHost"]) ready = true - loadBalancerAddress = svc.Status.LoadBalancer.Ingress[0].IP currentLeader = svc.Annotations["kube-vip.io/vipHost"] } } @@ -275,11 +297,13 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien } } if s.testHTTP { - err = httpTest(loadBalancerAddress) - if err != nil { - return "", "", fmt.Errorf("web retrieval timeout ") + for _, lbAddress := range loadBalancerAddresses { + err = httpTest(lbAddress) + if err != nil { + return "", nil, fmt.Errorf("web retrieval timeout ") + } } } - return currentLeader, loadBalancerAddress, nil + return currentLeader, loadBalancerAddresses, nil } diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 7bb0df99..7e181320 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -3,6 +3,7 @@ package main import ( "context" + "errors" "fmt" "net" "net/http" @@ -124,10 +125,11 @@ func (config *testConfig) startServiceTest(ctx context.Context, clientset *kuber policyLocal: true, testHTTP: true, } - leader, lbAddress, err := svc.createService(ctx, clientset) + leader, lbAddresses, err := svc.createService(ctx, clientset) if err != nil { log.Error(err) } + lbAddress := lbAddresses[0] err = leaderFailover(ctx, &s, &leader, clientset) if err != nil { @@ -218,10 +220,12 @@ func (config *testConfig) startServiceTest(ctx context.Context, clientset *kuber name: fmt.Sprintf("%s-%d", s, i), testHTTP: true, } - _, lbAddress, err := svc.createService(ctx, clientset) + _, lbAddresses, err := svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } + lbAddress := lbAddresses[0] + config.successCounter++ nodes, err := getAddressesOnNodes() if err != nil { @@ -282,10 +286,11 @@ func (config *testConfig) startServiceTest(ctx context.Context, clientset *kuber testHTTP: false, } - _, egress, err = svc.createService(ctx, clientset) + _, lbAddresses, err := svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } + egress = lbAddresses[0] for i := 1; i < 5; i++ { if found { @@ -308,18 +313,66 @@ func (config *testConfig) startServiceTest(ctx context.Context, clientset *kuber if err != nil { log.Fatal(err) } - log.Infof("🏆 Testing Complete [%d] passed", config.successCounter) } + + if !config.ignoreDualStack { + // Dualstack loadbalancer test + log.Infof("🧪 ---> testing dualstack loadbalancer service <---") + deploy := deployment{ + name: d, + nodeAffinity: nodeTolerate, + replicas: 2, + server: true, + } + err := deploy.createDeployment(ctx, clientset) + if err != nil { + log.Fatal(err) + } + svc := service{ + name: s, + testHTTP: true, + testDualstack: true, + } + _, _, err = svc.createService(ctx, clientset) + if err != nil { + log.Error(err) + } else { + config.successCounter++ + } + + log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) + err = clientset.CoreV1().Services(v1.NamespaceDefault).Delete(ctx, s, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + err = clientset.AppsV1().Deployments(v1.NamespaceDefault).Delete(ctx, d, metav1.DeleteOptions{}) + if err != nil { + log.Fatal(err) + } + + } + + log.Infof("🏆 Testing Complete [%d] passed", config.successCounter) } func httpTest(address string) error { + log.Infof("🕷️ testing HTTP request against [%s]", address) Client := http.Client{ Timeout: 1 * time.Second, } + ip := net.ParseIP(address) + if ip == nil { + return errors.New("invalid address") + } + if ip.To4() == nil { + // use brackets for IPv6 address + address = fmt.Sprintf("[%s]", address) + } var err error for i := 0; i < 5; i++ { + var r *http.Response //nolint - r, err := Client.Get(fmt.Sprintf("http://%s", address)) //nolint + r, err = Client.Get(fmt.Sprintf("http://%s", address)) //nolint if err == nil { log.Infof("🕸️ successfully retrieved web data in [%ds]", i) diff --git a/testing/e2e/services/tests.go b/testing/e2e/services/tests.go index a5400fa9..a6103689 100644 --- a/testing/e2e/services/tests.go +++ b/testing/e2e/services/tests.go @@ -21,6 +21,7 @@ type testConfig struct { ControlPlaneAddress string ManifestPath string IPv6 bool + Dualstack bool Services bool // service tests @@ -29,6 +30,7 @@ type testConfig struct { ignoreLeaderFailover bool ignoreLeaderActive bool ignoreLocalDeploy bool + ignoreDualStack bool ignoreEgress bool retainCluster bool } @@ -44,6 +46,7 @@ func main() { _, t.ignoreLeaderActive = os.LookupEnv("IGNORE_ACTIVE") _, t.ignoreLocalDeploy = os.LookupEnv("IGNORE_LOCALDEPLOY") _, t.ignoreEgress = os.LookupEnv("IGNORE_EGRESS") + _, t.ignoreDualStack = os.LookupEnv("IGNORE_DUALSTACK") _, t.retainCluster = os.LookupEnv("RETAIN_CLUSTER") flag.StringVar(&t.ImagePath, "imagepath", "plndr/kube-vip:action", "") @@ -54,6 +57,10 @@ func main() { log.Infof("🔬 beginning e2e tests, image: [%s]", t.ImagePath) + if !t.ignoreDualStack { + t.Dualstack = true + } + if t.ControlPlane { err := t.createKind() if !t.retainCluster { From 20b3a3c00bba6d5d1428fd48691bf1dcdaae0898 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 20 Dec 2023 16:07:53 +0000 Subject: [PATCH 483/542] Adds capability to use your own images for e2e Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 45 +++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 1de6d5f7..532d5ebd 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -34,6 +34,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { var ( logger log.Logger imagePath string + k8sImagePath string kubeVIPManifestTemplate *template.Template clusterName string tempDirPath string @@ -44,6 +45,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { logger = e2e.TestLogger{} imagePath = os.Getenv("E2E_IMAGE_PATH") + k8sImagePath = os.Getenv("K8S_IMAGE_PATH") curDir, err := os.Getwd() Expect(err).NotTo(HaveOccurred()) @@ -90,7 +92,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4.yaml") for i := 0; i < 3; i++ { - clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ + nodeConfig := kindconfigv1alpha4.Node{ Role: kindconfigv1alpha4.ControlPlaneRole, ExtraMounts: []kindconfigv1alpha4.Mount{ { @@ -98,7 +100,12 @@ var _ = Describe("kube-vip broadcast neighbor", func() { ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", }, }, - }) + } + // Override the kind image version + if k8sImagePath != "" { + nodeConfig.Image = k8sImagePath + } + clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) } manifestFile, err := os.Create(manifestPath) @@ -115,23 +122,26 @@ var _ = Describe("kube-vip broadcast neighbor", func() { }) It("provides an IPv4 VIP address for the Kubernetes control plane nodes", func() { + go func() { + time.Sleep(30 * time.Second) + By(withTimestamp("loading local docker image to kind cluster")) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + }() + By(withTimestamp("creating a kind cluster with multiple control plane nodes")) createKindCluster(logger, &clusterConfig, clusterName) - By(withTimestamp("loading local docker image to kind cluster")) - e2e.LoadDockerImageToKind(logger, imagePath, clusterName) - By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv4 VIP")) // Allow enough time for control plane nodes to load the docker image and // use the default timeout for establishing a connection to the VIP - assertControlPlaneIsRoutable(ipv4VIP, time.Duration(0), 10*time.Second) + assertControlPlaneIsRoutable(ipv4VIP, time.Duration(0), 20*time.Second) By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv4VIP, clusterName) By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv4 VIP with little downtime")) // Allow at most 20 seconds of downtime when polling the control plane nodes - assertControlPlaneIsRoutable(ipv4VIP, 1*time.Second, 20*time.Second) + assertControlPlaneIsRoutable(ipv4VIP, 1*time.Second, 30*time.Second) }) }) @@ -154,14 +164,20 @@ var _ = Describe("kube-vip broadcast neighbor", func() { manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv6.yaml") for i := 0; i < 3; i++ { - clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ + nodeConfig := kindconfigv1alpha4.Node{ + Role: kindconfigv1alpha4.ControlPlaneRole, ExtraMounts: []kindconfigv1alpha4.Mount{ { HostPath: manifestPath, ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", }, }, - }) + } + // Override the kind image version + if k8sImagePath != "" { + nodeConfig.Image = k8sImagePath + } + clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) } ipv6VIP = e2e.GenerateIPv6VIP() @@ -178,16 +194,19 @@ var _ = Describe("kube-vip broadcast neighbor", func() { }) It("provides an IPv6 VIP address for the Kubernetes control plane nodes", func() { + go func() { + time.Sleep(30 * time.Second) + By(withTimestamp("loading local docker image to kind cluster")) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + }() + By(withTimestamp("creating a kind cluster with multiple control plane nodes")) createKindCluster(logger, &clusterConfig, clusterName) - By(withTimestamp("loading local docker image to kind cluster")) - e2e.LoadDockerImageToKind(logger, imagePath, clusterName) - By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) // Allow enough time for control plane nodes to load the docker image and // use the default timeout for establishing a connection to the VIP - assertControlPlaneIsRoutable(ipv6VIP, time.Duration(0), 10*time.Second) + assertControlPlaneIsRoutable(ipv6VIP, time.Duration(0), 20*time.Second) By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv6VIP, clusterName) From 5b63e4a181b1e8854e9f9431c45a872676aed7b4 Mon Sep 17 00:00:00 2001 From: marc-cerebras Date: Thu, 21 Dec 2023 12:44:50 -0800 Subject: [PATCH 484/542] add cfg opts for bgp timers --- docs/flags/index.md | 2 ++ pkg/bgp/peers.go | 4 +++- pkg/bgp/types.go | 3 +++ pkg/kubevip/config_environment.go | 18 ++++++++++++++++++ pkg/kubevip/config_envvar.go | 4 ++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 613b3786..9217309f 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -92,6 +92,8 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `bgp_multihop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | | | `bgp_sourceif` | Source Interface | Determines which interface BGP should peer _from_ | | | `bgp_sourceip` | Source Address | Determines which IP address BGP should peer _from_ | +| | `bgp_hold_time` | default 0 | BGP timer HoldTime config. Defaults to 0, using the peer's default | +| | `bgp_keepalive_interval`| default 0 | BGP timer KeepaliveInterval config. Defaults to 0, using peer's default | | | `annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | | **Equinix Metal** | | | (May be deprecated) | | | `vip_packet` | Enables Equinix Metal API calls | | diff --git a/pkg/bgp/peers.go b/pkg/bgp/peers.go index 640c88bc..e78b9906 100644 --- a/pkg/bgp/peers.go +++ b/pkg/bgp/peers.go @@ -23,7 +23,9 @@ func (b *Server) AddPeer(peer Peer) (err error) { Timers: &api.Timers{ Config: &api.TimersConfig{ - ConnectRetry: 10, + ConnectRetry: 10, + HoldTime: b.c.HoldTime, + KeepaliveInterval: b.c.KeepaliveInterval, }, }, diff --git a/pkg/bgp/types.go b/pkg/bgp/types.go index e97bc8c8..b11a0b41 100644 --- a/pkg/bgp/types.go +++ b/pkg/bgp/types.go @@ -17,6 +17,9 @@ type Config struct { SourceIP string SourceIF string + HoldTime uint64 + KeepaliveInterval uint64 + Peers []Peer } diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index fd2c48a6..f1d6c66b 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -395,6 +395,24 @@ func ParseEnvironment(c *Config) error { c.BGPConfig.Peers = append(c.BGPConfig.Peers, c.BGPPeerConfig) } + // BGP Timers options + env = os.Getenv(bgpHoldTime) + if env != "" { + u64, err := strconv.ParseUint(env, 10, 32) + if err != nil { + return err + } + c.BGPConfig.HoldTime = u64 + } + env = os.Getenv(bgpKeepaliveInterval) + if env != "" { + u64, err := strconv.ParseUint(env, 10, 32) + if err != nil { + return err + } + c.BGPConfig.KeepaliveInterval = u64 + } + // Enable the Equinix Metal API calls env = os.Getenv(vipPacket) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 3f4a82be..9e2a37fd 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -114,6 +114,10 @@ const ( bgpSourceIF = "bgp_sourceif" // bgpSourceIP defines the source address for BGP peering bgpSourceIP = "bgp_sourceip" + // bgpHoldTime defines bgp timers hold time + bgpHoldTime = "bgp_hold_time" + // bgpKeepaliveInterval defines bgp timers keepalive interval + bgpKeepaliveInterval = "bgp_keepalive_interval" // vipWireguard - defines if wireguard will be used for vips vipWireguard = "vip_wireguard" //nolint From fb062f7a55e01b6bee45e63f61b7acde569e6136 Mon Sep 17 00:00:00 2001 From: marc-cerebras Date: Thu, 21 Dec 2023 14:36:07 -0800 Subject: [PATCH 485/542] add overlay for annotation driven cfg --- pkg/manager/watch_annotations.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/manager/watch_annotations.go b/pkg/manager/watch_annotations.go index 93bc7f35..9488f78c 100644 --- a/pkg/manager/watch_annotations.go +++ b/pkg/manager/watch_annotations.go @@ -49,7 +49,7 @@ func (sm *Manager) annotationsWatcher() error { // there's probably bigger problems node := nodeList.Items[0] - bgpConfig, bgpPeer, err := parseBgpAnnotations(&node, sm.config.Annotations) + bgpConfig, bgpPeer, err := parseBgpAnnotations(sm.config.BGPConfig, &node, sm.config.Annotations) if err == nil { // No error, the annotations already exist sm.config.BGPConfig = bgpConfig @@ -97,7 +97,7 @@ func (sm *Manager) annotationsWatcher() error { return fmt.Errorf("unable to parse Kubernetes Node from Annotation watcher") } - bgpConfig, bgpPeer, err := parseBgpAnnotations(node, sm.config.Annotations) + bgpConfig, bgpPeer, err := parseBgpAnnotations(sm.config.BGPConfig, node, sm.config.Annotations) if err != nil { log.Error(err) continue @@ -143,6 +143,9 @@ func (sm *Manager) annotationsWatcher() error { // returning an error if the annotations are not valid or missing; and nil if everything is OK // to continue // +// Parsed annotation config overlays config in passed bgpConfig in order to preserve configs +// set by other means with the exception that bgpConfig.Peers is overwritten. +// // The regex expression for each annotation ensures (at least in terms of annotations) backwards // compatibility with the Equinix Metal annotation format changed in // https://github.com/equinix/cloud-provider-equinix-metal/releases/tag/v3.3.0 @@ -151,8 +154,7 @@ func (sm *Manager) annotationsWatcher() error { // * `` is the relevant information, such as `node-asn` or `peer-ip` // * `{{n}}` is the number of the peer, always starting with `0` // * kube-vip is only designed to manage one peer, just look for {{n}} == 0 -func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { - bgpConfig := bgp.Config{} +func parseBgpAnnotations(bgpConfig bgp.Config, node *v1.Node, prefix string) (bgp.Config, bgp.Peer, error) { bgpPeer := bgp.Peer{} nodeASN := "" @@ -217,6 +219,7 @@ func parseBgpAnnotations(node *v1.Node, prefix string) (bgp.Config, bgp.Peer, er peerIPs := strings.Split(peerIPString, ",") + bgpConfig.Peers = make([]bgp.Peer, 0, len(peerIPs)) for _, peerIP := range peerIPs { ipAddr := strings.TrimSpace(peerIP) From 06285210d0e9ee489f9073b2b36b5eee172cf278 Mon Sep 17 00:00:00 2001 From: marc-cerebras Date: Thu, 21 Dec 2023 14:58:37 -0800 Subject: [PATCH 486/542] update tests --- pkg/manager/watcher_test.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/pkg/manager/watcher_test.go b/pkg/manager/watcher_test.go index 99149f2d..69ace11b 100644 --- a/pkg/manager/watcher_test.go +++ b/pkg/manager/watcher_test.go @@ -15,7 +15,11 @@ func TestParseBgpAnnotations(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{}}, } - _, _, err := parseBgpAnnotations(node, "bgp") + bgpConfigBase := bgp.Config{ + HoldTime: 15, + KeepaliveInterval: 5, + } + _, _, err := parseBgpAnnotations(bgpConfigBase, node, "bgp") if err == nil { t.Fatal("Parsing BGP annotations should return an error when no annotations exist") } @@ -26,7 +30,7 @@ func TestParseBgpAnnotations(t *testing.T) { "bgp/src-ip": "10.0.0.254", } - bgpConfig, bgpPeer, err := parseBgpAnnotations(node, "bgp") + bgpConfig, bgpPeer, err := parseBgpAnnotations(bgpConfigBase, node, "bgp") if err != nil { t.Fatal("Parsing BGP annotations should return nil when minimum config is met") } @@ -34,6 +38,8 @@ func TestParseBgpAnnotations(t *testing.T) { assert.Equal(t, uint32(65000), bgpConfig.AS, "bgpConfig.AS parsed incorrectly") assert.Equal(t, uint32(64000), bgpPeer.AS, "bgpPeer.AS parsed incorrectly") assert.Equal(t, "10.0.0.254", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") + assert.EqualValues(t, 15, bgpConfig.HoldTime, "base bgpConfig.HoldTime should not be overwritten") + assert.EqualValues(t, 5, bgpConfig.KeepaliveInterval, "base bgpConfig.KeepaliveInterval should not be overwritten") node.Annotations = map[string]string{ "bgp/node-asn": "65000", @@ -43,7 +49,7 @@ func TestParseBgpAnnotations(t *testing.T) { "bgp/bgp-pass": "cGFzc3dvcmQ=", // password } - bgpConfig, bgpPeer, err = parseBgpAnnotations(node, "bgp") + bgpConfig, bgpPeer, err = parseBgpAnnotations(bgpConfigBase, node, "bgp") if err != nil { t.Fatal("Parsing BGP annotations should return nil when minimum config is met") } @@ -56,6 +62,8 @@ func TestParseBgpAnnotations(t *testing.T) { assert.Equal(t, bgpPeers, bgpConfig.Peers, "bgpConfig.Peers parsed incorrectly") assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") + assert.EqualValues(t, 15, bgpConfig.HoldTime, "base bgpConfig.HoldTime should not be overwritten") + assert.EqualValues(t, 5, bgpConfig.KeepaliveInterval, "base bgpConfig.KeepaliveInterval should not be overwritten") } // Node, or local, ASN, default annotation metal.equinix.com/bgp-peers-{{n}}-node-asn @@ -69,7 +77,11 @@ func TestParseNewBgpAnnotations(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{}}, } - _, _, err := parseBgpAnnotations(node, "bgp") + bgpConfigBase := bgp.Config{ + HoldTime: 15, + KeepaliveInterval: 5, + } + _, _, err := parseBgpAnnotations(bgpConfigBase, node, "bgp") if err == nil { t.Fatal("Parsing BGP annotations should return an error when no annotations exist") } @@ -82,7 +94,7 @@ func TestParseNewBgpAnnotations(t *testing.T) { "bgp/bgp-peers-0-bgp-pass": "cGFzc3dvcmQ=", // password } - bgpConfig, bgpPeer, err := parseBgpAnnotations(node, "bgp") + bgpConfig, bgpPeer, err := parseBgpAnnotations(bgpConfigBase, node, "bgp") if err != nil { t.Fatalf("Parsing BGP annotations should return nil when minimum config is met [%v]", err) } @@ -97,6 +109,8 @@ func TestParseNewBgpAnnotations(t *testing.T) { assert.Equal(t, "10.0.0.254", bgpConfig.RouterID, "bgpConfig.RouterID parsed incorrectly") assert.Equal(t, "10.0.0.3", bgpPeer.Address, "bgpPeer.Address parsed incorrectly") assert.Equal(t, "password", bgpPeer.Password, "bgpPeer.Password parsed incorrectly") + assert.EqualValues(t, 15, bgpConfig.HoldTime, "base bgpConfig.HoldTime should not be overwritten") + assert.EqualValues(t, 5, bgpConfig.KeepaliveInterval, "base bgpConfig.KeepaliveInterval should not be overwritten") } func Test_parseBgpAnnotations(t *testing.T) { @@ -115,7 +129,7 @@ func Test_parseBgpAnnotations(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, got1, err := parseBgpAnnotations(tt.args.node, tt.args.prefix) + got, got1, err := parseBgpAnnotations(bgp.Config{}, tt.args.node, tt.args.prefix) if (err != nil) != tt.wantErr { t.Errorf("parseBgpAnnotations() error = %v, wantErr %v", err, tt.wantErr) return From 88dbd0f45da690d466523e6ea8fc0ac8e7aa2b4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Dec 2023 12:25:40 +0000 Subject: [PATCH 487/542] Bump golang.org/x/crypto from 0.14.0 to 0.17.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0. - [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 06529ef0..c8885ef8 100644 --- a/go.mod +++ b/go.mod @@ -96,12 +96,12 @@ require ( github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/vishvananda/netns v0.0.4 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect diff --git a/go.sum b/go.sum index 8a6a790e..8e004ea4 100644 --- a/go.sum +++ b/go.sum @@ -388,8 +388,8 @@ golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -560,8 +560,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -570,8 +570,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 4438fcb6d3a207d76ddc4663f357790581289403 Mon Sep 17 00:00:00 2001 From: Teo Stocco Date: Sun, 24 Dec 2023 15:33:39 +0100 Subject: [PATCH 488/542] docs: fix directroute forwarding method --- docs/flags/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/flags/index.md b/docs/flags/index.md index 9217309f..c80810da 100644 --- a/docs/flags/index.md +++ b/docs/flags/index.md @@ -20,9 +20,9 @@ These flags are typically used in the `kube-vip` manifest generation process. | | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | | | `--enableLoadBalancer` | Enables IPVS load balancer | `kube-vip` ≥ 0.4.0 | | | `--lbPort` | 6443 | The port that the api server will load-balanced on | -| | `--lbForwardingMethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | +| | `--lbForwardingMethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, directroute, bypass) | | **Services** | | | | -| | `--serviceInterface` | "" | Defines an optional different interface to bind services too | +| | `--serviceInterface` | "" | Defines an optional different interface to bind services too | | | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | | **Kubernetes** | | | | | | `--inCluster` | Required for `kube-vip` as DaemonSet. | Runs `kube-vip` with a ServiceAccount called `kube-vip`. | @@ -72,7 +72,7 @@ More environment variables can be read through the `pkg/kubevip/config_envvar.go | | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | | | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | | | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | -| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, direct, bypass) | +| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, directroute, bypass) | | **Services** | | | | | | `vip_servicesinterface`| "" | Defines an optional different interface to bind services too | | | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | From 5308dfc0554581c0afa2d3e338df5348270bd11f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 02:22:51 +0000 Subject: [PATCH 489/542] Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0) --- updated-dependencies: - dependency-name: github.com/spf13/cobra dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 06529ef0..c33372df 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 go.etcd.io/etcd/api/v3 v3.5.10 diff --git a/go.sum b/go.sum index 8a6a790e..6a7a961b 100644 --- a/go.sum +++ b/go.sum @@ -65,7 +65,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -325,8 +325,8 @@ github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= From 2cfe326b9ca9b6901809a423392a02e1463d6963 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 28 Dec 2023 14:19:35 +0000 Subject: [PATCH 490/542] Updates to the client to auto-detect Signed-off-by: Dan Finneran --- cmd/kube-vip-manifests.go | 26 ++++++++ cmd/kube-vip.go | 1 + go.mod | 2 +- pkg/k8s/client.go | 65 ++++++++++++++++++- pkg/k8s/client_test.go | 78 +++++++++++++++++++++++ pkg/kubevip/config_environment.go | 10 +++ pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_generator.go | 101 +++++++++++++++++++++++++++++- pkg/kubevip/config_types.go | 3 + pkg/manager/manager.go | 24 ++++++- 10 files changed, 307 insertions(+), 6 deletions(-) create mode 100644 pkg/k8s/client_test.go diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 703d6f51..442cdba3 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -6,6 +6,7 @@ import ( "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" ) // manifests will eventually deprecate the kubeadm set of subcommands @@ -22,6 +23,7 @@ func init() { kubeManifest.AddCommand(kubeManifestPod) kubeManifest.AddCommand(kubeManifestDaemon) + kubeManifest.AddCommand(kubeManifestRbac) } var kubeManifest = &cobra.Command{ @@ -80,3 +82,27 @@ var kubeManifestDaemon = &cobra.Command{ fmt.Println(cfg) }, } + +var kubeManifestRbac = &cobra.Command{ + Use: "rbac", + Short: "Generate an RBAC Manifest", + Run: func(cmd *cobra.Command, args []string) { + // 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) + } + + // 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") + } + cfg := kubevip.GenerateSA() + b, _ := yaml.Marshal(cfg) + + fmt.Println(string(b)) + }, +} diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index ad363518..fb12449e 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -128,6 +128,7 @@ func init() { // Behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPlane, "controlplane", false, "Enable HA for control plane") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DetectControlPlane, "autodetectcp", false, "Determine working address for control plane (from loopback)") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServices, "services", false, "Enable Kubernetes services") // Extended behaviour flags diff --git a/go.mod b/go.mod index fddfe3c7..3a7e1cec 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 + gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.28.3 k8s.io/apimachinery v0.28.3 k8s.io/client-go v0.28.3 @@ -113,7 +114,6 @@ require ( google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index 2414ef1d..a03fe59a 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -1,8 +1,12 @@ package k8s import ( + "crypto/tls" "fmt" + "net" + "time" + log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -14,7 +18,11 @@ import ( // Also takes a hostname which allow for overriding the config's hostname // before generating a client. func NewClientset(configPath string, inCluster bool, hostname string) (*kubernetes.Clientset, error) { - config, err := restConfig(configPath, inCluster) + return newClientset(configPath, inCluster, hostname, time.Second*10) +} + +func newClientset(configPath string, inCluster bool, hostname string, timeout time.Duration) (*kubernetes.Clientset, error) { + config, err := restConfig(configPath, inCluster, timeout) if err != nil { panic(err.Error()) } @@ -30,8 +38,11 @@ func NewClientset(configPath string, inCluster bool, hostname string) (*kubernet return clientset, nil } -func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { +func restConfig(kubeconfig string, inCluster bool, timeout time.Duration) (*rest.Config, error) { cfg, err := rest.InClusterConfig() + if err != nil { + log.Debugf("[k8s client] we try the incluster first, this error [%v] can safely be ignored", err) + } if kubeconfig != "" && !inCluster { cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig) @@ -45,5 +56,55 @@ func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { // these should hopefully be redundant, however issues will still be logged. cfg.QPS = 100 cfg.Burst = 250 + cfg.Timeout = timeout return cfg, nil } + +func findAddressFromRemoteCert(address string) ([]net.IP, error) { + + // TODO: should we care at this point, probably not as we just want the certificates + conf := &tls.Config{ + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: true, //nolint + } + d := &net.Dialer{ + Timeout: time.Duration(3) * time.Second, + } + + // Create the TCP connection + conn, err := tls.DialWithDialer(d, "tcp", address, conf) + if err != nil { + return nil, err + } + + defer conn.Close() + // Grab the certificactes + certs := conn.ConnectionState().PeerCertificates + if len(certs) > 1 { + return nil, fmt.Errorf("[k8s client] not designed to recive multiple certs from API server") + } + + return certs[0].IPAddresses, nil +} + +func FindWorkingKubernetesAddress(configPath string, inCluster bool) (*kubernetes.Clientset, error) { + // check with loopback, and retrieve its certificate + ips, err := findAddressFromRemoteCert("127.0.0.1:6443") + if err != nil { + return nil, err + } + for x := range ips { + log.Debugf("[k8s client] checking with IP address [%s]", ips[x].String()) + + k, err := newClientset(configPath, inCluster, ips[x].String()+":6443", time.Second*2) + if err != nil { + log.Info(err) + } + _, err = k.DiscoveryClient.ServerVersion() + if err == nil { + log.Infof("[k8s client] working with IP address [%s]", ips[x].String()) + return NewClientset(configPath, inCluster, ips[x].String()+":6443") + } + } + return nil, fmt.Errorf("unable to find a working address for the local API server [%v]", err) +} diff --git a/pkg/k8s/client_test.go b/pkg/k8s/client_test.go new file mode 100644 index 00000000..64b6a1ff --- /dev/null +++ b/pkg/k8s/client_test.go @@ -0,0 +1,78 @@ +package k8s + +import ( + "net" + "reflect" + "testing" + + "k8s.io/client-go/kubernetes" +) + +//"192.168.0.174:6443" + +func Test_findAddressFromRemoteCert(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want []net.IP + wantErr bool + }{ + { + name: "test server", + args: args{address: "192.168.0.174:6443"}, + want: []net.IP{net.IPv4(10, 96, 0, 1), net.IPv4(192, 168, 0, 174)}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := findAddressFromRemoteCert(tt.args.address) + if (err != nil) != tt.wantErr { + t.Errorf("findAddressFromRemoteCert() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("findAddressFromRemoteCert() = %v, want %v", got, tt.want) + } + }) + } +} + +//findAddressFromRemoteCert() = +//[10.96.0.1 192.168.0.174] +//[10.96.0.1 192.168.0.174] + +func Test_findWorkingKubernetesAddress(t *testing.T) { + type args struct { + configPath string + inCluster bool + } + tests := []struct { + name string + args args + want *kubernetes.Clientset + wantErr bool + }{ + { + name: "test", + args: args{ + configPath: "/home/dan/super-admin.conf", + inCluster: false, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := FindWorkingKubernetesAddress(tt.args.configPath, tt.args.inCluster) + if (err != nil) != tt.wantErr { + t.Errorf("findWorkingKubernetesAddress() error = %v, wantErr %v", err, tt.wantErr) + return + } + + }) + } +} diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index fd2c48a6..8a22a9d2 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -152,6 +152,16 @@ func ParseEnvironment(c *Config) error { c.EnableControlPlane = b } + // Find controlplane toggle + env = os.Getenv(cpDetect) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.DetectControlPlane = b + } + // Find Services toggle env = os.Getenv(svcEnable) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 3f4a82be..f569c8f6 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -138,6 +138,9 @@ const ( // cpEnable enables the control plane feature cpEnable = "cp_enable" + // cpDetect will attempt to automatically find a working address for the control plane from loopback + cpDetect = "cp_detect" + // svcEnable enables the Kubernetes service feature svcEnable = "svc_enable" diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index b4882819..3718dd21 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -7,9 +7,98 @@ import ( appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + applyCoreV1 "k8s.io/client-go/applyconfigurations/core/v1" + applyMetaV1 "k8s.io/client-go/applyconfigurations/meta/v1" + applyRbacV1 "k8s.io/client-go/applyconfigurations/rbac/v1" + "sigs.k8s.io/yaml" ) +// GenerateSA will create the service account for kube-vip +func GenerateSA() *applyCoreV1.ServiceAccountApplyConfiguration { + kind := "ServiceAccount" + name := "kube-vip" + namespace := "kube-system" + newManifest := &applyCoreV1.ServiceAccountApplyConfiguration{ + TypeMetaApplyConfiguration: applyMetaV1.TypeMetaApplyConfiguration{APIVersion: &corev1.SchemeGroupVersion.Version, Kind: &kind}, + ObjectMetaApplyConfiguration: &applyMetaV1.ObjectMetaApplyConfiguration{ + Name: &name, + Namespace: &namespace, + }, + } + return newManifest +} + +// GenerateCR will generate the Cluster role for kube-vip +func GenerateCR() *applyRbacV1.ClusterRoleApplyConfiguration { + name := "system:kube-vip-role" + roleRefKind := "ClusterRole" + apiVersion := "rbac.authorization.k8s.io/v1" + + newManifest := &applyRbacV1.ClusterRoleApplyConfiguration{ + TypeMetaApplyConfiguration: applyMetaV1.TypeMetaApplyConfiguration{APIVersion: &apiVersion, Kind: &roleRefKind}, + ObjectMetaApplyConfiguration: &applyMetaV1.ObjectMetaApplyConfiguration{ + Name: &name, + }, + Rules: []applyRbacV1.PolicyRuleApplyConfiguration{ + { + APIGroups: []string{""}, + Resources: []string{"services/status"}, + Verbs: []string{"update"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"services", "endpoints"}, + Verbs: []string{"list", "get", "watch", "endoints"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"nodes"}, + Verbs: []string{"list", "get", "watch", "update", "patch"}, + }, + { + APIGroups: []string{"coordination.k8s.io"}, + Resources: []string{"leases"}, + Verbs: []string{"list", "get", "watch", "update", "create"}, + }, + }, + } + return newManifest +} + +// GenerateCRB will generate the clusterRoleBinding +func GenerateCRB() *applyRbacV1.ClusterRoleBindingApplyConfiguration { + kind := "ClusterRoleBinding" + apiVersion := "rbac.authorization.k8s.io/v1" + subjectKind := "ServiceAccount" + apiGroup := "rbac.authorization.k8s.io" + roleRefKind := "ClusterRole" + roleRefName := "system:kube-vip-role" + name := "kube-vip" + bindName := "system:kube-vip-role-binding" + namespace := "kube-system" + + newManifest := &applyRbacV1.ClusterRoleBindingApplyConfiguration{ + TypeMetaApplyConfiguration: applyMetaV1.TypeMetaApplyConfiguration{APIVersion: &apiVersion, Kind: &kind}, + ObjectMetaApplyConfiguration: &applyMetaV1.ObjectMetaApplyConfiguration{ + Name: &bindName, + }, + RoleRef: &applyRbacV1.RoleRefApplyConfiguration{ + APIGroup: &apiGroup, + Kind: &roleRefKind, + Name: &roleRefName, + }, + Subjects: []applyRbacV1.SubjectApplyConfiguration{ + { + Kind: &subjectKind, + Name: &name, + Namespace: &namespace, + }, + }, + } + return newManifest +} + // generatePodSpec will take a kube-vip config and generate a Pod spec func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod { command := "manager" @@ -92,10 +181,18 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: cpNamespace, Value: c.Namespace, }, - { + } + if c.DDNS { + cp = append(cp, corev1.EnvVar{ Name: vipDdns, Value: strconv.FormatBool(c.DDNS), - }, + }) + } + if c.DetectControlPlane { + cp = append(cp, corev1.EnvVar{ + Name: cpDetect, + Value: strconv.FormatBool(c.DetectControlPlane), + }) } newEnvironment = append(newEnvironment, cp...) } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 7704e136..e04ff360 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -24,6 +24,9 @@ type Config struct { // EnableControlPlane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPlane bool `yaml:"enableControlPlane"` + // DetectControlPlane, will attempt to find the control plane from loopback (127.0.0.1) + DetectControlPlane bool `yaml:"detectControlPlane"` + // EnableServices, will enable the services functionality (used for hybrid behaviour) EnableServices bool `yaml:"enableServices"` diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index fdec7d73..538b3e25 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -74,7 +74,12 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { // If this is a control plane host it will likely have started as a static pod or won't have the // VIP up before trying to connect to the API server, we set the API endpoint to this machine to // ensure connectivity. - clientset, err = k8s.NewClientset(adminConfigPath, false, fmt.Sprintf("kubernetes:%v", config.Port)) + if config.DetectControlPlane { + clientset, err = k8s.FindWorkingKubernetesAddress(adminConfigPath, false) + } else { + // This will attempt to use kubernetes as the hostname (this should be passed as a host alias) in the pod manifest + clientset, err = k8s.NewClientset(adminConfigPath, false, fmt.Sprintf("kubernetes:%v", config.Port)) + } } else { clientset, err = k8s.NewClientset(adminConfigPath, false, "") } @@ -96,6 +101,23 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) { log.Debug("Using external Kubernetes configuration from incluster config.") } + // Flip this to something else + // if config.DetectControlPlane { + // log.Info("[k8s client] flipping to internal service account") + // _, err = clientset.CoreV1().ServiceAccounts("kube-system").Apply(context.TODO(), kubevip.GenerateSA(), v1.ApplyOptions{FieldManager: "application/apply-patch"}) + // if err != nil { + // return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err) + // } + // _, err = clientset.RbacV1().ClusterRoles().Apply(context.TODO(), kubevip.GenerateCR(), v1.ApplyOptions{FieldManager: "application/apply-patch"}) + // if err != nil { + // return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err) + // } + // _, err = clientset.RbacV1().ClusterRoleBindings().Apply(context.TODO(), kubevip.GenerateCRB(), v1.ApplyOptions{FieldManager: "application/apply-patch"}) + // if err != nil { + // return nil, fmt.Errorf("could not create k8s clientset from incluster config: %v", err) + // } + // } + return &Manager{ clientSet: clientset, configMap: configMap, From 52ad35d462a4790f71e6647903928637470a1a17 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 28 Dec 2023 14:24:44 +0000 Subject: [PATCH 491/542] disable local tests Signed-off-by: Dan Finneran --- pkg/k8s/client_test.go | 134 +++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 71 deletions(-) diff --git a/pkg/k8s/client_test.go b/pkg/k8s/client_test.go index 64b6a1ff..9180f99e 100644 --- a/pkg/k8s/client_test.go +++ b/pkg/k8s/client_test.go @@ -1,78 +1,70 @@ package k8s -import ( - "net" - "reflect" - "testing" - - "k8s.io/client-go/kubernetes" -) - //"192.168.0.174:6443" -func Test_findAddressFromRemoteCert(t *testing.T) { - type args struct { - address string - } - tests := []struct { - name string - args args - want []net.IP - wantErr bool - }{ - { - name: "test server", - args: args{address: "192.168.0.174:6443"}, - want: []net.IP{net.IPv4(10, 96, 0, 1), net.IPv4(192, 168, 0, 174)}, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := findAddressFromRemoteCert(tt.args.address) - if (err != nil) != tt.wantErr { - t.Errorf("findAddressFromRemoteCert() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("findAddressFromRemoteCert() = %v, want %v", got, tt.want) - } - }) - } -} +// func Test_findAddressFromRemoteCert(t *testing.T) { +// type args struct { +// address string +// } +// tests := []struct { +// name string +// args args +// want []net.IP +// wantErr bool +// }{ +// { +// name: "test server", +// args: args{address: "192.168.0.174:6443"}, +// want: []net.IP{net.IPv4(10, 96, 0, 1), net.IPv4(192, 168, 0, 174)}, +// wantErr: false, +// }, +// } +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// got, err := findAddressFromRemoteCert(tt.args.address) +// if (err != nil) != tt.wantErr { +// t.Errorf("findAddressFromRemoteCert() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// if !reflect.DeepEqual(got, tt.want) { +// t.Errorf("findAddressFromRemoteCert() = %v, want %v", got, tt.want) +// } +// }) +// } +// } -//findAddressFromRemoteCert() = -//[10.96.0.1 192.168.0.174] -//[10.96.0.1 192.168.0.174] +// //findAddressFromRemoteCert() = +// //[10.96.0.1 192.168.0.174] +// //[10.96.0.1 192.168.0.174] -func Test_findWorkingKubernetesAddress(t *testing.T) { - type args struct { - configPath string - inCluster bool - } - tests := []struct { - name string - args args - want *kubernetes.Clientset - wantErr bool - }{ - { - name: "test", - args: args{ - configPath: "/home/dan/super-admin.conf", - inCluster: false, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := FindWorkingKubernetesAddress(tt.args.configPath, tt.args.inCluster) - if (err != nil) != tt.wantErr { - t.Errorf("findWorkingKubernetesAddress() error = %v, wantErr %v", err, tt.wantErr) - return - } +// func Test_findWorkingKubernetesAddress(t *testing.T) { +// type args struct { +// configPath string +// inCluster bool +// } +// tests := []struct { +// name string +// args args +// want *kubernetes.Clientset +// wantErr bool +// }{ +// { +// name: "test", +// args: args{ +// configPath: "/home/dan/super-admin.conf", +// inCluster: false, +// }, +// wantErr: false, +// }, +// } +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// _, err := FindWorkingKubernetesAddress(tt.args.configPath, tt.args.inCluster) +// if (err != nil) != tt.wantErr { +// t.Errorf("findWorkingKubernetesAddress() error = %v, wantErr %v", err, tt.wantErr) +// return +// } - }) - } -} +// }) +// } +// } From 12638aee85d40628e7b1baa39683231d3aa3a992 Mon Sep 17 00:00:00 2001 From: Archit H Barve Date: Fri, 29 Dec 2023 15:46:54 +0530 Subject: [PATCH 492/542] Removed docs --- docs/Dockerfile | 5 - docs/architecture/index.md | 157 ------- .../kubernetes-vip-architecture.png | Bin 68679 -> 0 bytes docs/control-plane/0.1.4/index.md | 147 ------ docs/control-plane/0.1.5/index.md | 195 -------- docs/control-plane/index.md | 421 ------------------ docs/flags/index.md | 103 ----- docs/hybrid/daemonset/index.md | 242 ---------- docs/hybrid/index.md | 142 ------ docs/hybrid/services/index.md | 269 ----------- docs/hybrid/static/index.md | 129 ------ docs/index.md | 70 --- docs/install_daemonset/index.md | 253 ----------- docs/install_static/index.md | 257 ----------- docs/k3s | 61 --- docs/kube-vip.png | Bin 62135 -> 0 bytes docs/kubernetes/arp/index.md | 181 -------- docs/kubernetes/bgp/index.md | 87 ---- docs/kubernetes/index.md | 75 ---- docs/manifests/0.3.1/kube-vip-arp-ds.yaml | 63 --- docs/manifests/0.3.1/kube-vip-arp.yaml | 55 --- docs/manifests/0.3.1/kube-vip-bgp-ds.yaml | 72 --- docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml | 82 ---- docs/manifests/0.3.1/kube-vip-bgp.yaml | 62 --- docs/manifests/controller.yaml | 70 --- docs/manifests/kube-vip-arp.yaml | 85 ---- docs/manifests/kube-vip-bgp.yaml | 90 ---- docs/manifests/kube-vip-em.yaml | 91 ---- docs/manifests/kube-vip.yaml | 83 ---- docs/manifests/rbac.yaml | 32 -- docs/manifests/v0.3.7/kube-vip-arp-ds.yaml | 65 --- docs/manifests/v0.3.7/kube-vip-arp.yaml | 57 --- docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml | 74 --- docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml | 84 ---- docs/manifests/v0.3.7/kube-vip-bgp.yaml | 64 --- docs/manifests/v0.3.9/kube-vip-arp-ds.yaml | 65 --- docs/manifests/v0.3.9/kube-vip-arp.yaml | 61 --- docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml | 74 --- docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml | 84 ---- docs/manifests/v0.3.9/kube-vip-bgp.yaml | 62 --- docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml | 69 --- docs/manifests/v0.4.0/kube-vip-arp-ds.yaml | 65 --- docs/manifests/v0.4.0/kube-vip-arp-lb.yaml | 65 --- docs/manifests/v0.4.0/kube-vip-arp.yaml | 61 --- docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml | 74 --- docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml | 84 ---- docs/manifests/v0.4.0/kube-vip-bgp.yaml | 62 --- docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml | 70 --- docs/manifests/v0.4.1/kube-vip-arp-ds.yaml | 64 --- docs/manifests/v0.4.1/kube-vip-arp-lb.yaml | 66 --- docs/manifests/v0.4.1/kube-vip-arp.yaml | 60 --- docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml | 73 --- docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml | 83 ---- docs/manifests/v0.4.1/kube-vip-bgp.yaml | 61 --- docs/publish.sh | 9 - docs/usage/EquinixMetal/index.md | 163 ------- docs/usage/k3s/index.md | 53 --- docs/usage/kind/index.md | 86 ---- docs/usage/on-prem/index.md | 203 --------- 59 files changed, 5740 deletions(-) delete mode 100644 docs/Dockerfile delete mode 100644 docs/architecture/index.md delete mode 100644 docs/architecture/kubernetes-vip-architecture.png delete mode 100644 docs/control-plane/0.1.4/index.md delete mode 100644 docs/control-plane/0.1.5/index.md delete mode 100644 docs/control-plane/index.md delete mode 100644 docs/flags/index.md delete mode 100644 docs/hybrid/daemonset/index.md delete mode 100644 docs/hybrid/index.md delete mode 100644 docs/hybrid/services/index.md delete mode 100644 docs/hybrid/static/index.md delete mode 100644 docs/index.md delete mode 100644 docs/install_daemonset/index.md delete mode 100644 docs/install_static/index.md delete mode 100644 docs/k3s delete mode 100644 docs/kube-vip.png delete mode 100644 docs/kubernetes/arp/index.md delete mode 100644 docs/kubernetes/bgp/index.md delete mode 100644 docs/kubernetes/index.md delete mode 100644 docs/manifests/0.3.1/kube-vip-arp-ds.yaml delete mode 100644 docs/manifests/0.3.1/kube-vip-arp.yaml delete mode 100644 docs/manifests/0.3.1/kube-vip-bgp-ds.yaml delete mode 100644 docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml delete mode 100644 docs/manifests/0.3.1/kube-vip-bgp.yaml delete mode 100644 docs/manifests/controller.yaml delete mode 100644 docs/manifests/kube-vip-arp.yaml delete mode 100644 docs/manifests/kube-vip-bgp.yaml delete mode 100644 docs/manifests/kube-vip-em.yaml delete mode 100644 docs/manifests/kube-vip.yaml delete mode 100644 docs/manifests/rbac.yaml delete mode 100644 docs/manifests/v0.3.7/kube-vip-arp-ds.yaml delete mode 100644 docs/manifests/v0.3.7/kube-vip-arp.yaml delete mode 100644 docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml delete mode 100644 docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml delete mode 100644 docs/manifests/v0.3.7/kube-vip-bgp.yaml delete mode 100644 docs/manifests/v0.3.9/kube-vip-arp-ds.yaml delete mode 100644 docs/manifests/v0.3.9/kube-vip-arp.yaml delete mode 100644 docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml delete mode 100644 docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml delete mode 100644 docs/manifests/v0.3.9/kube-vip-bgp.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-arp-ds.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-arp-lb.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-arp.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml delete mode 100644 docs/manifests/v0.4.0/kube-vip-bgp.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-arp-ds.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-arp-lb.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-arp.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml delete mode 100644 docs/manifests/v0.4.1/kube-vip-bgp.yaml delete mode 100644 docs/publish.sh delete mode 100644 docs/usage/EquinixMetal/index.md delete mode 100644 docs/usage/k3s/index.md delete mode 100644 docs/usage/kind/index.md delete mode 100644 docs/usage/on-prem/index.md diff --git a/docs/Dockerfile b/docs/Dockerfile deleted file mode 100644 index fb92fcf1..00000000 --- a/docs/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM nginx:latest -RUN apt-get update; apt-get install -y nodejs npm; npm install -g markdown-styles; -COPY . /docs -WORKDIR /docs -RUN generate-md --layout github --input ./ --output /usr/share/nginx/html/ diff --git a/docs/architecture/index.md b/docs/architecture/index.md deleted file mode 100644 index 360bfbbc..00000000 --- a/docs/architecture/index.md +++ /dev/null @@ -1,157 +0,0 @@ -# Kube-Vip Architecture - -This section covers two parts of the architecture: - -1. The technical capabilities of `kube-vip`. -2. The components to build a load balancing service within Kubernetes. - -The `kube-vip` project is designed to provide both a highly available networking endpoint and load balancing functionality for underlying networking services. The project was originally designed for the purpose of providing a resilient control plane for Kubernetes but has since expanded to provide the same functionality for Service resources within a Kubernetes cluster. - -Additionally, `kube-vip` is designed to be lightweight and multi-architecture. All of the components are built for Linux on `x86`, `armv7`, `armhvf`, `ppc64le` and `s390x` architectures. This means that `kube-vip` will run fine in bare metal, virtual, and edge (Raspberry Pi or small ARM SoC) use cases. - -## Technologies - -There are a number of technologies or functional design choices that provide high availability and networking functions as part of a VIP/load balancing solution. - -### Cluster - -The `kube-vip` service builds a multi-node or multi-pod cluster to provide high availability. In ARP mode, a leader is elected which will inherit the virtual IP and become the leader of the load balancing within the cluster whereas with BGP all nodes will advertise the VIP address. - -When using ARP or [Layer 2](https://osi-model.com/data-link-layer/) it will use [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection). - -### Virtual IP - -The leader within the cluster will assume the VIP and will have it bound to the selected interface that is declared within the configuration. When the leader changes, it will evacuate the VIP first or in failure scenarios the VIP will be directly assumed by the next elected leader. - -When the VIP moves from one host to another, any host that has been using the VIP will retain the previous VIP-to-MAC address mapping until the old ARP entry expires (typically within 30 seconds) and retrieves a new mapping. This can be improved by using [Gratuitous ARP](https://wiki.wireshark.org/Gratuitous_ARP) broadcasts when enabled (detailed below). - -### ARP - -`kube-vip` can optionally be configured to broadcast a Gratuitous ARP that will typically immediately notify all local hosts that the VIP-to-MAC address mapping has changed. - -Below we can see that the failover is typically done within a few seconds as the ARP broadcast is received. - -``` -64 bytes from 192.168.0.75: icmp_seq=146 ttl=64 time=0.258 ms -64 bytes from 192.168.0.75: icmp_seq=147 ttl=64 time=0.240 ms -92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) -Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 bc98 0 0000 3f 01 3d16 192.168.0.95 192.168.0.75 - -Request timeout for icmp_seq 148 -92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) -Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 75ff 0 0000 3f 01 83af 192.168.0.95 192.168.0.75 - -Request timeout for icmp_seq 149 -92 bytes from 192.168.0.70: Redirect Host(New addr: 192.168.0.75) -Vr HL TOS Len ID Flg off TTL Pro cks Src Dst -4 5 00 0054 2890 0 0000 3f 01 d11e 192.168.0.95 192.168.0.75 - -Request timeout for icmp_seq 150 -64 bytes from 192.168.0.75: icmp_seq=151 ttl=64 time=0.245 ms -``` - -### Load Balancing - -`kube-vip` has the capability to provide a high availability address for both the Kubernetes control plane and for a Kubernetes Service. As of v0.4.0, `kube-vip` implements support for true load balancing for the control plane to distribute API requests across control plane nodes. - -#### Kubernetes Service Load Balancing - -The following is required in the `kube-vip` manifest to enable Service of type `LoadBalancer`: - -```yaml -- name: svc_enable - value: "true" -``` - -This section details the flow of events in order for `kube-vip` to advertise a Kubernetes Service: - -1. An end user exposes an application through Kubernetes as a Service type `LoadBalancer`. For example, imperatively using `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster, a Service object is created with the `spec.type` set to `LoadBalancer`. -3. A controller (typically a [Cloud Controller](/usage/cloud-provider)) has a loop that "watches" for Services of the type `LoadBalancer`. -4. The controller now has the responsibility of providing an IP address for this Service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address, it will update the Service field `metadata.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release -6. `kube-vip` Pods implement a "watcher" for Services that have a `metadata.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `spec.loadBalancerIP`. -7. When a new Service appears, `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the Service network. -8. Finally, `kube-vip` will update the Service status so that the API reflects the object is ready. This is done by updating the `status.loadBalancer.ingress` with the VIP address. - -#### Control Plane Load-Balancing - -As of `kube-vip` v0.4.0, IPVS load balancing is configured for having the VIP in the same subnet as the control plane nodes. NAT-based load balancing will follow later. - -To enable control plane load balancing using IPVS, the environment variable `lb_enable` is required in the `kube-vip` manifest: - -```yaml -- name : lb_enable - value: "true" -``` - -The load balancing is provided through IPVS (IP Virtual Server) and provides a Layer 4 (TCP-based) round-robin across all of the control plane nodes. By default, the load balancer will listen on the default port of 6443 as the Kubernetes API server. The IPVS virtual server lives in kernel space and doesn't create an "actual" service that listens on port 6443. This allows the kernel to parse packets before they're sent to an actual TCP port. This is important to know because it means we don't have any port conflicts having the IPVS load balancer listening on the same port as the API server on the same host. - -The load balancer port can be customised by changing the `lb_port` environment variable in the `kube-vip` manifest: - -```yaml -- name: lb_port - value: "6443" -``` - -##### How it works - -Once the `lb_enable` variable is set to `true`, `kube-vip` will do the following: - -- In Layer 2 it will create an IPVS service on the leader. -- In Layer 3 all nodes will create an IPVS service. -- It will start a Kubernetes node watcher for nodes with the control plane label. -- It will add/delete them as they're added and removed from the cluster. - -#### Debugging control plane load balancing - -In order to inspect and debug traffic, install the `ipvsadm` tool. - -##### View the configuration - -The command `sudo ipvsadm -ln` will display the load balancer configuration. - -```sh -$ sudo ipvsadm -ln -IP Virtual Server version 1.2.1 (size=4096) -Prot LocalAddress:Port Scheduler Flags --> RemoteAddress:Port Forward Weight ActiveConn InActConn -TCP 192.168.0.40:6443 rr --> 192.168.0.41:6443 Local 1 4 0 --> 192.168.0.42:6443 Local 1 3 0 --> 192.168.0.43:6443 Local 1 3 0 -``` - -##### Watch things interact with the API server - -The command `watch sudo ipvsadm -lnc` will auto-refresh the connections to the load balancer. - -```sh -$ watch sudo ipvsadm -lnc - - - -sudo ipvsadm -lnc k8s01: Tue Nov 9 11:39:39 2021 - -IPVS connection entries -pro expire state source virtual destination -TCP 14:49 ESTABLISHED 192.168.0.42:37090 192.168.0.40:6443 192.168.0.41:6443 -TCP 14:55 ESTABLISHED 192.168.0.45:46510 192.168.0.40:6443 192.168.0.41:6443 -TCP 14:54 ESTABLISHED 192.168.0.43:39602 192.168.0.40:6443 192.168.0.43:6443 -TCP 14:58 ESTABLISHED 192.168.0.44:50458 192.168.0.40:6443 192.168.0.42:6443 -TCP 14:32 ESTABLISHED 192.168.0.43:39648 192.168.0.40:6443 192.168.0.42:6443 -TCP 14:58 ESTABLISHED 192.168.0.40:55944 192.168.0.40:6443 192.168.0.41:6443 -TCP 14:54 ESTABLISHED 192.168.0.42:36950 192.168.0.40:6443 192.168.0.41:6443 -TCP 14:42 ESTABLISHED 192.168.0.44:50488 192.168.0.40:6443 192.168.0.43:6443 -TCP 14:53 ESTABLISHED 192.168.0.45:46528 192.168.0.40:6443 192.168.0.43:6443 -TCP 14:49 ESTABLISHED 192.168.0.40:56040 192.168.0.40:6443 192.168.0.42:6443 -``` - -## Components within a Kubernetes Cluster - -The `kube-vip` Kubernetes load balancer requires a number of components in order to function: - -- [Kube-Vip Cloud Provider](https://github.com/kube-vip/kube-vip-cloud-provider) -- [Kube-Vip Deployment](https://github.com/kube-vip/kube-vip) diff --git a/docs/architecture/kubernetes-vip-architecture.png b/docs/architecture/kubernetes-vip-architecture.png deleted file mode 100644 index 9d5a6f4c1919ccfab459ea3488cee41524d3dde4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68679 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 z 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

    Behl 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%0A+>$O$F*H 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 Q8u;_%k-Sv?LtU@`2g6f+?EnA( diff --git a/docs/control-plane/0.1.4/index.md b/docs/control-plane/0.1.4/index.md deleted file mode 100644 index e40ef6ec..00000000 --- a/docs/control-plane/0.1.4/index.md +++ /dev/null @@ -1,147 +0,0 @@ -# Load Balancing a Kubernetes Cluster (Control-Plane) (pre 0.1.5) - -This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster - -`tl;dr version` -- Generate/modify first node `kube-vip` config/manifest -- `init` first node -- `join` remaining nodes -- Add remaining config/manifests - -## Infrastructure architecture - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -|----------------|------------| -| VIP | 10.0.0.75 | -| controlPlane01 | 10.0.0.70 | -| controlPlane02 | 10.0.0.71 | -| controlPlane03 | 10.0.0.72 | - -All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. - -### Generate the `kube-vip` configuration - -Make sure that the config directory exists: `sudo mkdir -p /etc/kube-vip/`, this directory can be any directory however the `hostPath` in the manifest will need modifying to point to the correct path. - -``` -sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample config | sudo tee /etc/kube-vip/config.yaml -``` - -### Modify the configuration - -**Cluster Configuration** -Modify the `remotePeers` to point to the correct addresses of the other two nodes, ensure that their `id` is unique otherwise this will confuse the raft algorithm. The `localPeer` should be the configuration of the current node (`controlPlane01`), which is where this instance of the cluster will run. - -As this node will be the first node, it will need to elect itself leader as until this occurs the VIP won’t be activated! - -`startAsLeader: true` - -**VIP Config** -We will need to set our VIP address to `192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `gratuitousARP: true` - -**Load Balancer** -We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. - -We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. - -**config.yaml** - -`user@controlPlane01:/etc/kube-vip$ cat config.yaml` - -... - -``` -remotePeers: -- id: server2 - address: 192.168.0.71 - port: 10000 -- id: server3 - address: 192.168.0.72 - port: 10000 -localPeer: - id: server1 - address: 192.168.0.70 - port: 10000 -vip: 192.168.0.75 -gratuitousARP: true -singleNode: false -startAsLeader: true -interface: ens192 -loadBalancers: -- name: Kubernetes Control Plane - type: tcp - port: 6443 - bindToVip: true - backends: - - port: 6444 - address: 192.168.0.70 - - port: 6444 - address: 192.168.0.71 - - port: 6444 - address: 192.168.0.72 -``` - -### First Node - -To generate the basic Kubernetes static pod `yaml` configuration: - -Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` - -``` -sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. Also ensure that the `hostPath` points to the correct `kube-vip` configuration, if it isn’t the above path. - -The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. - -`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` - -Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: - -``` -$ kubectl get pods -A -NAMESPACE NAME READY STATUS RESTARTS AGE -<...> -kube-system kube-vip-controlplane01 1/1 Running 0 10m -``` - -### Remaining Nodes - -We first will need to create the `kube-vip` configuration that resides in `/etc/kube-vip/config.yaml` or we can regenerate it from scratch using the above example. Ensure that the configuration is almost identical with the `localPeer` and `remotePeers` sections are updated for each node. Finally, ensure that the remaining nodes will behave as standard cluster nodes by setting `startAsLeader: false`. - -At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. - -``` - kubeadm join 192.168.0.75:6443 --token \ - --discovery-token-ca-cert-hash sha256: \ - --control-plane --certificate-key - -``` - -**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). - -``` -sudo docker run -it --rm plndr/kube-vip:0.1 /kube-vip sample manifest | sudo tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: - -``` -user@controlPlane01:~$ kubectl get pods -A | grep vip -kube-system kube-vip-controlplane01 1/1 Running 1 16m -kube-system kube-vip-controlplane02 1/1 Running 0 18m -kube-system kube-vip-controlplane03 1/1 Running 0 20m - -``` - -If we look at the logs, we can see that the VIP is running on the second node and we’re waiting for our third node to join the cluster: - -``` -$ kubectl logs kube-vip-controlplane02 -n kube-system -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” - -``` \ No newline at end of file diff --git a/docs/control-plane/0.1.5/index.md b/docs/control-plane/0.1.5/index.md deleted file mode 100644 index d22e3e4d..00000000 --- a/docs/control-plane/0.1.5/index.md +++ /dev/null @@ -1,195 +0,0 @@ -# Load Balancing a Kubernetes Cluster (Control-Plane) - -This document covers the newer (post `0.1.5`) method for using `kube-vip` to provide HA for a Kubernetes Cluster. The documentation for older releases can be found [here](./0.1.4/) - -This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster - -`tl;dr version` -- Generate/modify first node `kube-vip` config/manifest -- `init` first node -- `join` remaining nodes -- Add remaining config/manifests - -Below are examples of the steps required: - -``` -# First Node -sudo docker run --network host --rm plndr/kube-vip:0.1.5 kubeadm init --interface ens192 --vip 192.168.0.81 --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml - -sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0.81 --upload-certs - -# Additional Node(s) - -sudo kubeadm join 192.168.0.81:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 - -sudo docker run -v /etc/kubernetes/admin.conf:/etc/kubernetes/admin.conf --network host --rm plndr/kube-vip:0.1.5 kubeadm join --interface ens192 --vip 192.168.0.81 --startAsLeader=false | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - - -## Infrastructure architecture - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -|----------------|------------| -| VIP | 10.0.0.75 | -| controlPlane01 | 10.0.0.70 | -| controlPlane02 | 10.0.0.71 | -| controlPlane03 | 10.0.0.72 | - -All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. - -### Generate the `kube-vip` configuration - -Kube-Vip no longer requires storing it's configuration in a seperate directory and will now store its configuration in the actual manifest that defines the static pods. - -``` -sudo docker run --network host \ - --rm plndr/kube-vip:0.1.5 \ - kubeadm init \ - --interface ens192 \ - --vip 192.168.0.75 \ - --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -The above command will "initialise" the manifest within the `/etc/kubernetes/manifests` directory, that will be started when we actually initialise our Kubernetes cluster with `kubeadm init` - -### Modify the configuration - -**Cluster Configuration** -As this node will be the first node, it will need to elect itself leader as until this occurs the VIP won’t be activated! - -`--startAsLeader=true` - -**VIP Config** -We will need to set our VIP address to `192.168.0.75` with `--vip 192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `--arp` (defaults to `true`) - -**Load Balancer** -We will configure the load balancer to sit on the standard API-Server port `6443` and we will configure the backends to point to the API-servers that will be configured to run on port `6444`. Also for the Kubernetes Control Plane we will configure the load balancer to be of `type: tcp`. - -We can also use `6443` for both the VIP and the API-Servers, in order to do this we need to specify that the api-server is bound to it's local IP. To do this we use the `--apiserver-advertise-address` flag as part of the `init`, this means that we can then bind the same port to the VIP and we wont have a port conflict. - -**vip.yaml** Static-pod Manifest - -`$ sudo cat /etc/kubernetes/manifests/vip.yaml` - - -``` -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - start - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: ens192 - - name: vip_address - value: 192.168.0.81 - - name: vip_startleader - value: "true" - - name: vip_addpeerstolb - value: "true" - - name: vip_localpeer - value: controlPlane01:192.168.0.70:10000 - - name: lb_backendport - value: "6443" - - name: lb_name - value: Kubeadm Load Balancer - - name: lb_type - value: tcp - - name: lb_bindtovip - value: "true" - image: plndr/kube-vip:0.1.5 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_TIME - hostNetwork: true -status: {} -``` - -### First Node - -To generate the basic Kubernetes static pod `yaml` configuration: - -Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` - -``` -sudo docker run --network host \ - --rm plndr/kube-vip:0.1.5 \ - kubeadm init \ - --interface ens192 \ - --vip 192.168.0.75 \ - --startAsLeader=true | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -Ensure that `image: plndr/kube-vip:` is modified to point to a specific version (`0.1.5` at the time of writing), refer to [docker hub](https://hub.docker.com/r/plndr/kube-vip/tags) for details. - -The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. - -`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --apiserver-bind-port 6444 --upload-certs --kubernetes-version “v1.17.0”` - -Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: - -``` -$ kubectl get pods -A -NAMESPACE NAME READY STATUS RESTARTS AGE -<...> -kube-system kube-vip-controlplane01 1/1 Running 0 10m -``` - -### Remaining Nodes - - -At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. - -``` - kubeadm join 192.168.0.75:6443 --token \ - --discovery-token-ca-cert-hash sha256: \ - --control-plane --certificate-key - -``` - -**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). - -``` -sudo docker run \ - -v /etc/kubernetes/admin.conf:/etc/kubernetes/admin.conf \ - --network host \ - --rm plndr/kube-vip:0.1.5 \ - kubeadm join \ - --interface ens192 \ - --vip 192.168.0.81 \ - --startAsLeader=false | sudo tee /etc/kubernetes/manifests/vip.yaml - -``` - -Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: - -``` -user@controlPlane01:~$ kubectl get pods -A | grep vip -kube-system kube-vip-controlplane01 1/1 Running 1 16m -kube-system kube-vip-controlplane02 1/1 Running 0 18m -kube-system kube-vip-controlplane03 1/1 Running 0 20m - -``` - -If we look at the logs, we can see that the VIP is running on the second node and we’re waiting for our third node to join the cluster: - -``` -$ kubectl logs kube-vip-controlplane02 -n kube-system -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” -time=“2020-02-12T15:33:09Z” level=info msg=“The Node [192.168.0.70:10000] is leading” - -``` \ No newline at end of file diff --git a/docs/control-plane/index.md b/docs/control-plane/index.md deleted file mode 100644 index f7a5867e..00000000 --- a/docs/control-plane/index.md +++ /dev/null @@ -1,421 +0,0 @@ -# Load Balancing a Kubernetes Cluster (Control-Plane) - -**Note**: The most common deployment currently for HA Kubernetes clusters w/`kube-vip` involved `kubeadm`, however recently we've worked to bring a method of bringing `kube-vip` to other types of Kubernetes cluster. Typically this deployment method makes use of a daemonset that is usually brought up during the cluster instantiation.. So for those wanting to deploy [k3s](https://k3s.io), we now have installation steps available [here](https://kube-vip.io/control-plane/#k3s), - -This document covers the newer (post `0.1.6`) method for using `kube-vip` to provide HA for a Kubernetes Cluster. The documentation for older releases can be found [here](./0.1.5/) - -From version `0.1.6` we've moved `kube-vip` from raft to leaderElection within the Kubernetes cluster. After a lot of testing it became clear that the leaderElection gave quicker reconciliation when removing nodes etc.. during upgrades and failures. - -For **more** configuration around LeaderElection click [here](https://kube-vip.io/control-plane/#leaderelection-configuration). - -This document covers all of the details for using `kube-vip` to build a HA Kubernetes cluster - -`tl;dr version` -- Generate/modify first node `kube-vip` config/manifest -- `init` first node -- `join` remaining nodes -- Add remaining config/manifests - -Below are examples of the steps required: - -``` -# First Node -sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ ---interface ens192 \ ---vip 192.168.0.75 \ ---arp \ ---leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml - -sudo kubeadm init --kubernetes-version 1.17.0 --control-plane-endpoint 192.168.0.75 --upload-certs - -# Additional Node(s) - -sudo kubeadm join 192.168.0.75:6443 --token w5atsr.blahblahblah --control-plane --certificate-key abc123 - -sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ ---interface ens192 \ ---vip 192.168.0.75 \ ---arp \ ---leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - - -## Infrastructure architecture - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -|----------------|------------| -| VIP | 10.0.0.75 | -| controlPlane01 | 10.0.0.70 | -| controlPlane02 | 10.0.0.71 | -| controlPlane03 | 10.0.0.72 | - -All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.17.0. - -### Generate the `kube-vip` configuration - -`kube-vip` no longer requires storing its configuration in a separate directory and will now store its configuration in the actual manifest that defines the static pods. - -``` -sudo docker run --network host \ - --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ - manifest pod \ - --interface ens192 \ - --vip 192.168.0.75 \ - --arp \ - --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -The above command will "initialise" the manifest within the `/etc/kubernetes/manifests` directory, that will be started when we actually initialise our Kubernetes cluster with `kubeadm init` - -### Modify the configuration - -**Cluster Configuration** -To enable Kubernetes leader Election passing the `--leaderElection` flag will enable `kube-vip` to use the Kubernetes leaderElection functionality to work out which member is the leader. - -**VIP Config** -We will need to set our VIP address to `192.168.0.75` with `--vip 192.168.0.75` and to ensure all hosts are updated when the VIP moves we will enable ARP broadcasts `--arp` (defaults to `true`) - -**vip.yaml** Static-pod Manifest - -`$ sudo cat /etc/kubernetes/manifests/vip.yaml` - - -``` -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - start - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: ens160 - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.75 - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_TIME - hostNetwork: true -status: {} -``` - -### First Node - -To generate the basic Kubernetes static pod `yaml` configuration: - -Make sure that the manifest directory exists: `sudo mkdir -p /etc/kubernetes/manifests/` - -``` -sudo docker run --network host \ - --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ - manifest pod \ - --interface ens192 \ - --vip 192.168.0.75 \ - --arp \ - --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -Ensure that `image: ghcr.io/kube-vip/kube-vip:` is modified to point to a specific version (`0.3.7` at the time of writing), refer to [GitHyb](https://github.com/kube-vip/kube-vip/pkgs/container/kube-vip) for details. - -The **vip** is set to `192.168.0.75` and this first node will elect itself as leader, and as part of the `kubeadm init` it will use the VIP in order to speak back to the initialising api-server. - -`sudo kubeadm init --control-plane-endpoint “192.168.0.75:6443” --upload-certs --kubernetes-version “v1.17.0”` - -Once this node is up and running we will be able to see the control-plane pods, including the `kube-vip` pod: - -``` -$ kubectl get pods -A -NAMESPACE NAME READY STATUS RESTARTS AGE -<...> -kube-system kube-vip-controlplane01 1/1 Running 0 10m -``` - -### Remaining Nodes - - -At this point **DON’T** generate the manifests, this is due to some bizarre `kubeadm/kubelet` behaviour. - -``` - kubeadm join 192.168.0.75:6443 --token \ - --discovery-token-ca-cert-hash sha256: \ - --control-plane --certificate-key - -``` - -**After** this node has been added to the cluster, we can add the manifest to also add this node as a `kube-vip` member. (Adding the manifest afterwards doesn’t interfere with `kubeadm`). - -``` -sudo docker run --network host \ - --rm ghcr.io/kube-vip/kube-vip:0.3.7 \ - manifest pod \ - --interface ens192 \ - --vip 192.168.0.75 \ - --arp \ - --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml - -``` - -Once this node is added we will be able to see that the `kube-vip` pod is up and running as expected: - -``` -user@controlPlane01:~$ kubectl get pods -A | grep vip -kube-system kube-vip-controlplane01 1/1 Running 1 16m -kube-system kube-vip-controlplane02 1/1 Running 0 18m -kube-system kube-vip-controlplane03 1/1 Running 0 20m - -``` - -## DNS Support - -### Static DNS Support (added in 0.2.0) - -A new flag `--address` is introduced to support using a DNS record as the control plane endpoint. `kube-vip` will do a dns lookup to retrieve the IP for the DNS record, and use that IP as the VIP. An `dnsUpdater` periodically checks and updates the system if IP changes for the DNS record. - -### Dynamic DNS Support (added in 0.2.1) - -`kube-vip` was also updated to support DHCP + [Dynamic DNS](https://en.wikipedia.org/wiki/Dynamic_DNS), for the use case where it's not able to reserve a static IP for the control plane endpoint. - -A new flag `--ddns` is introduced. Once enabled, `kube-vip` expects the input `--address` will be a FQDN without binding to an IP. Then `kube-vip` will start a dhcp client to allocate an IP for the hostname of FQDN, and maintain the lease for it. - -Once DHCP returns an IP for the FQDN, the same `dnsUpdater` runs to periodically checks and updates if IP got changed. - -## BGP Support (added in 0.1.8) - -In version `0.1.8`+ `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. - -The following new flags are used: - -- `--bgp` This will enable BGP support within kube-vip -- `--localAS` The local AS number -- `--bgpRouterID` The local router address -- `--peerAS` The AS number for a BGP peer -- `--peerAddress` The address of a BGP peer - -### BGP Packet support - -If the `--bgp` flag is passed alone with the Packet flags `packet, packetKey and packetProject`, then the Packet API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Packet much simpler. - -## Packet Support (added in 0.1.7) - -Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Packet Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Packet account and create a EIP (either public (eek) or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Packet project we can now apply this address to the servers that live in the same project. - -In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. - -The following new flags are used: - -- `--packet` which enables the use of the Packet API -- `--packetKey` which is our API key -- `--packetProject`which is the name of our Packet project where our servers and EIP are located. - -*Also* the `--arp` flag should NOT be used as it wont work within the Packet network. - -### Variables - -``` -export EIP=1.1.1.1 -export PACKET_AUTH_TOKEN=XYZ -``` - -### First node - -``` -# Generate the manifest - -sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ ---arp=false \ ---interface lo \ ---vip $EIP \ ---leaderElection \ ---packet \ ---packetKey $PACKET_AUTH_TOKEN \ ---packetProject vipTest | sudo tee /etc/kubernetes/manifests/vip.yaml\ - -# Init Kubernetes - -sudo kubeadm init --kubernetes-version 1.18.5 --control-plane-endpoint $EIP --upload-certs -``` - -### Other nodes - -``` -# Join -kubeadm join $EIP:6443 --token BLAH --control-plane --certificate-key BLAH --discovery-token-ca-cert-hash sha:blah - -# Generate Manifest - -sudo docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7 manifest pod \ ---arp=false \ ---interface lo \ ---vip $EIP \ ---leaderElection \ ---packet \ ---packetKey $PACKET_AUTH_TOKEN \ ---packetProject vipTest | sudo tee /etc/kubernetes/manifests/vip.yaml\ -``` - -The Elastic IP failover takes some time (30+ seconds) to move from a failed host to a new leader, so in this release it is mainly for testing. - - -## Upgrades - -From above we have a 3 node cluster and the controlPlane01 is leader: - -``` -$ kubectl logs -n kube-system kube-vip-controlplane01 -f -time="2020-07-04T15:12:52Z" level=info msg="Beginning cluster membership, namespace [kube-system], lock name [plunder-lock], id [controlPlane01]" -I0704 15:12:52.290420 1 leaderelection.go:242] attempting to acquire leader lease kube-system/plunder-lock... -I0704 15:12:56.373113 1 leaderelection.go:252] successfully acquired lease kube-system/plunder-lock -time="2020-07-04T15:12:56Z" level=info msg="This node is assuming leadership of the cluster" -time="2020-07-04T15:12:56Z" level=error msg="This node is leader and is adopting the virtual IP" -time="2020-07-04T15:12:56Z" level=info msg="Starting TCP Load Balancer for service [192.168.0.81:0]" -time="2020-07-04T15:12:56Z" level=info msg="Load Balancer [Kubeadm Load Balancer] started" -time="2020-07-04T15:12:56Z" level=info msg="Broadcasting ARP update for 192.168.0.81 (00:50:56:a5:69:a1) via ens192" -time="2020-07-04T15:12:56Z" level=info msg="Starting TCP Load Balancer for service [192.168.0.81:0]" -time="2020-07-04T15:12:56Z" level=info msg="Load Balancer [Kubeadm Load Balancer] started" -time="2020-07-04T15:12:56Z" level=info msg="Broadcasting ARP update for 192.168.0.81 (00:50:56:a5:69:a1) via ens192" -time="2020-07-04T15:12:56Z" level=info msg="new leader elected: controlPlane01" -``` - -We will kill this node and watch `kube-vip` logs from another node: - -#### Pinging VIP - -``` -64 bytes from 192.168.0.81: icmp_seq=667 ttl=64 time=0.387 ms -Request timeout for icmp_seq 668 -Request timeout for icmp_seq 669 -Request timeout for icmp_seq 670 -Request timeout for icmp_seq 671 -Request timeout for icmp_seq 672 -64 bytes from 192.168.0.81: icmp_seq=673 ttl=64 time=0.453 ms -``` - -#### Logs -``` -$ kubectl logs -n kube-system kube-vip-controlplane03 -f -time="2020-07-04T15:17:53Z" level=info msg="Beginning cluster membership, namespace [kube-system], lock name [plunder-lock], id [controlPlane03]" -I0704 15:17:53.484698 1 leaderelection.go:242] attempting to acquire leader lease kube-system/plunder-lock... -time="2020-07-04T15:17:53Z" level=info msg="new leader elected: controlPlane01" -E0704 15:20:18.864141 1 leaderelection.go:331] error retrieving resource lock kube-system/plunder-lock: etcdserver: request timed out -time="2020-07-04T15:20:20Z" level=info msg="new leader elected: controlPlane02" -``` - -#### Adding `controlPlane04` - -A kubeadm join will fail as the `controlPlane01` still exists as an endpoint, so we have two options (manual steps and configmap edit to remove all mention of this node, or we can bring this node up and `kubeadm reset` the node (which we will do)). - -``` -$ kubectl get nodes -NAME STATUS ROLES AGE VERSION -controlplane01 NotReady master 14m v1.17.0 -controlplane02 Ready master 13m v1.17.2 -controlplane03 Ready master 13m v1.17.0 -controlplane04 NotReady master 9s v1.17.0 -``` - After this we can add this node into `kube-vip` with the same manifest created by `docker run`. - -## LeaderElection configuration - -The Kubernetes LeaderElection that is used to manage the election of a new leader now supports having it's settings managed through flags. - - - `--leaseDuration` Length of time a Kubernetes leader lease can be held for - - `--leaseRenewDuration` Length of time a Kubernetes leader can attempt to renew its lease - - `--leaseRetry` Number of times the host will retry to hold a lease - -For larger clusters the `--leaseDuration` and `--leaseRenewDuration` may need extending due to slower `etcd` performance. (Tested with 2000 nodes) - -## k3s - -This section details the steps required to deploye `k3s` in a Highly available manner, using kube-vip deployed within k3s as a daemonset on the control plane nodes. As of `k3s` v1 the persistent datastore is back to etcd, however this guide will also include the steps for using `mysql`. - -### Example MySQL deployment (optional) - -To quickly validate this we can use docker on a host to quickly spin up a mysql database to store the persistent Kubernetes data. - -#### Create local directory for BD storage -`mkdir mysql` - -#### Start Docker MySQL container -`sudo docker run --cap-add SYS_NICE -p 3306:3306 --name k3s-mysql -v /home/dan/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=k3s-password -d mysql:8` - -### Create `kube-vip` manifest - -The `kube-vip` manifest contains all the configuration for starting up `kube-vip` within the `k3s` cluster, it runs as a daemonset with affinity/taints for the control-plane nodes. As `k3s` starts it will parse all manifests in the manifests folder and start the highly available VIP across all control plane nodes in the cluster. - -#### Create the `k3` manifests directory - -Create the manifests directory, this directory is used by `k3s` for all of it's other deployments once it's up and running. -`sudo mkdir -p /var/lib/rancher/k3s/server/manifests/` - -#### Generate the manifest - -Modify the `vipAddress` and `vipInterface` to match the floating IP address you'd like to use and the interface it should bind to. - -`curl -sL kube-vip.io/k3s | vipAddress=192.168.0.10 vipInterface=ens192 sh | sudo tee /var/lib/rancher/k3s/server/manifests/vip.yaml` - -### Start `k3s` - -Set the VIP **first** - -`export VIP=192.168.0.10` - - -From online `-->` - -``` -curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ --t agent-secret --tls-san $VIP" sh - -``` - -From local `-->` - -``` -sudo ./k3s server --tls-san $VIP -``` - -#### With MySQL - -From online `-->` - -``` -curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 \ ---datastore-endpoint mysql://root:k3s-password@tcp(192.168.0.43:3306)/kubernetes \ --t agent-secret --tls-san $VIP" sh - -``` - -From local `-->` - -``` -sudo ./k3s server --tls-san $VIP \ ---datastore-endpoint="mysql://root:k3s-password@tcp(192.168.0.43:3306)/kubernetes" -``` - -### Get a `kubeconfig` that uses the vip - -```` -mkdir -p $HOME/.kube -sudo cat /etc/rancher/k3s/k3s.yaml | sed 's/127.0.0.1/'$VIP'/g' > $HOME/.kube/config -sudo chown $(id -u):$(id -g) $HOME/.kube/config -``` diff --git a/docs/flags/index.md b/docs/flags/index.md deleted file mode 100644 index c80810da..00000000 --- a/docs/flags/index.md +++ /dev/null @@ -1,103 +0,0 @@ -# Kube-Vip Flag / Environment Variable reference - -## Flags - -These flags are typically used in the `kube-vip` manifest generation process. - -| Category | Flag | Usage | Notes | -| ------------------- | ---------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------- | -| **Troubleshooting** | | | | -| | `--log` | default 4 | Set to `5` for debugging logs | -| **Mode** | | | | -| | `--controlplane` | Enables `kube-vip` control plane functionality | | -| | `--services` | Enables `kube-vip` to watch services of type `LoadBalancer` | | -| **VIP Config** | | | | -| | `--arp` | Enables ARP broadcasts from Leader | | -| | `--bgp` | Enables BGP peering from `kube-vip` | | -| | `--vip` | `` | (deprecated) | -| | `--address` | `` or `` | | -| | `--interface` | Linux interface on the node | | -| | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| | `--enableLoadBalancer` | Enables IPVS load balancer | `kube-vip` ≥ 0.4.0 | -| | `--lbPort` | 6443 | The port that the api server will load-balanced on | -| | `--lbForwardingMethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, directroute, bypass) | -| **Services** | | | | -| | `--serviceInterface` | "" | Defines an optional different interface to bind services too | -| | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | -| **Kubernetes** | | | | -| | `--inCluster` | Required for `kube-vip` as DaemonSet. | Runs `kube-vip` with a ServiceAccount called `kube-vip`. | -| | `--taint` | Required for `kube-vip` as DaemonSet. | Adds node affinity rules forcing `kube-vip` Pods to run on control plane. | -| **LeaderElection** | | | | -| | `--leaseDuration` | default 5 | Seconds a lease is held for | -| | `--leaseRenewDuration` | default 3 | Seconds a leader can attempt to renew the lease | -| | `--leaseRetry` | default 1 | Number of times the leader will hold the lease for | -| | `--namespace` | "kube-vip" | The namespace where the lease will reside | -| **BGP** | | | | -| | `--bgpRouterID` | `` | Typically the address of the local node | -| | `--localAS` | default 65000 | The AS we peer from | -| | `--bgppeers` | `` | Comma separated list of BGP peers | -| | `--peerAddress` | `` | Address of a single BGP Peer | -| | `--peerAS` | default 65000 | AS of a single BGP Peer | -| | `--peerPass` | "" | Password to work with a single BGP Peer | -| | `--multiHop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | -| | `--sourceif` | Source Interface | Determines which interface BGP should peer _from_ | -| | `--sourceip` | Source Address | Determines which IP address BGP should peer _from_ | -| | `--annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | -| **Equinix Metal** | | | (May be deprecated) | -| | `--metal` | Enables Equinix Metal API calls | | -| | `--metalKey` | Equinix Metal API token | | -| | `--metalProject` | Equinix Metal Project (Name) | | -| | `--metalProjectID` | Equinix Metal Project (UUID) | | -| | `--provider-config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | - -## Environment Variables - -These environment variables are usually part of a `kube-vip` manifest and used when running the `kube-vip` Pod. - -More environment variables can be read through the `pkg/kubevip/config_envvar.go` file. - -| Category | Environment Variable | Usage | Notes | -| ------------------- | ---------------------- |-------------------------------------------------------------|---------------------------------------------------------------------------------| -| **Troubleshooting** | | | | -| | `vip_loglevel` | default 4 | Set to `5` for debugging logs | -| **Mode** | | | | -| | `cp_enable` | Enables `kube-vip` control plane functionality | | -| | `svc_enable` | Enables `kube-vip` to watch Services of type `LoadBalancer` | | -| **VIP Config** | | | | -| | `vip_arp` | Enables ARP broadcasts from Leader | | -| | `bgp_enable` | Enables BGP peering from `kube-vip` | | -| | `vip_address` | `` | (deprecated) | -| | `address` | `` or `` | | -| | `vip_interface` | `` | | -| | `vip_leaderelection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| | `lb_enable` | Enables IPVS LoadBalancer | `kube-vip` ≥ 0.4.0. Adds nodes to the IPVS load balancer | -| | `lb_port` | 6443 | The IPVS port that will be used to load-balance control plane requests | -| | `lb_fwdmethod` | Select the forwarding method (default local) | The IPVS forwarding method (local, masquerade, tunnel, directroute, bypass) | -| **Services** | | | | -| | `vip_servicesinterface`| "" | Defines an optional different interface to bind services too | -| | `vip_cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | -| **LeaderElection** | | | | -| | `vip_leaseduration` | default 5 | Seconds a lease is held for | -| | `vip_renewdeadline` | default 3 | Seconds a leader can attempt to renew the lease | -| | `vip_retryperiod` | default 1 | Number of times the leader will hold the lease for | -| | `cp_namespace` | "kube-vip" | The namespace where the lease will reside | -| **BGP** | | | | -| | `bgp_routerid` | `` | Typically the address of the local node | -| | `bgp_routerinterface` | Interface name | Used to associate the `routerID` with the control plane's interface. | -| | `bgp_as` | default 65000 | The AS we peer from | -| | `bgp_peers` | `` | Comma separated list of BGP peers (IPv6 addresses should be enclosed with `[]`) | -| | `bgp_peeraddress` | `` | Address of a single BGP Peer | -| | `bgp_peeras` | default 65000 | AS of a single BGP Peer | -| | `bgp_peerpass` | "" | Password to work with a single BGP Peer | -| | `bgp_multihop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | -| | `bgp_sourceif` | Source Interface | Determines which interface BGP should peer _from_ | -| | `bgp_sourceip` | Source Address | Determines which IP address BGP should peer _from_ | -| | `bgp_hold_time` | default 0 | BGP timer HoldTime config. Defaults to 0, using the peer's default | -| | `bgp_keepalive_interval`| default 0 | BGP timer KeepaliveInterval config. Defaults to 0, using peer's default | -| | `annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | -| **Equinix Metal** | | | (May be deprecated) | -| | `vip_packet` | Enables Equinix Metal API calls | | -| | `PACKET_AUTH_TOKEN` | Equinix Metal API token | | -| | `vip_packetproject` | Equinix Metal Project (Name) | | -| | `vip_packetprojectid` | Equinix Metal Project (UUID) | | -| | `provider_config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | diff --git a/docs/hybrid/daemonset/index.md b/docs/hybrid/daemonset/index.md deleted file mode 100644 index 46139e5b..00000000 --- a/docs/hybrid/daemonset/index.md +++ /dev/null @@ -1,242 +0,0 @@ -# Kube-Vip as a daemonset - -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. - - -**Note about Daemonsets** - -The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. - -If the Kubernetes installer allows for adding a Virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate then we can apply `kube-vip` to the cluster once the first node has been brought up. - -Unlike generating the static manifest there are a few more things that may need configuring, this page will cover most scenarios. - -## Create the RBAC settings - -As a daemonSet runs within the Kubernetes cluster it needs the correct access to be able to watch Kubernetes services and other objects. In order to do this we create a User, Role, and a binding.. we can apply this with the command: - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` - -## Generating a Manifest - -This section only covers generating a simple *BGP* configuration, as the main focus is will be on additional changes to the manifest. For more examples we can look at [here](/hybrid/static/). - -**Note:** Pay attention if using the "static" examples, as the `manifest` subcommand should use `daemonset` and NOT `pod`. - -### Set configuration details - -`export VIP=192.168.0.40` - -`export INTERFACE=` - -### Configure to use a container runtime - -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. - -#### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip"` - -#### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` - -### BGP Example - -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. - -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. - -**Note 2** we pass the `--inCluster` flag as this is running as a daemonSet within the Kubernetes cluster and therefore will have access to the token inside the running pod. - -**Note 2** we pass the `--taint` flag as we're deploying `kube-vip` as both a daemonset and as advertising controlplane, we want to taint this daemonset to only run on the worker nodes. - -`export INTERFACE=lo` - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --vip $VIP \ - --controlplane \ - --services \ - --inCluster \ - --taint \ - --bgp \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false -``` - -### Generated Manifest - -``` -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: lo - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: bgp_enable - value: "true" - - name: bgp_peers - value: "192.168.0.10:65000::false,192.168.0.11:65000::false" - - name: vip_address - value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - nodeSelector: - node-role.kubernetes.io/master: "true" - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - updateStrategy: {} -``` - -### Manifest Overview - -- `nodeSelector` - Ensures that this particular daemonset only runs on control plane nodes -- `serviceAccountName: kube-vip` - this specifies the user in the `rbac` that will give us the permissions to get/update services. -- `hostNetwork: true` - This pod will need to modify interfaces (for VIPs) -- `env {...}` - We pass the configuration into the kube-vip pod through environment variables. - -## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) - -The below example is for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. - -**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. - -This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --services \ - --bgp \ - --annotations metal.equinix.com \ - --inCluster | k apply -f - -``` - -### Troubleshooting - -If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node. -As of Equinix Metal's CCM v3.3.0, the annotations format was changed. This means, you should expect either of the following: - -1. Equinix Metal's CCM v3.3.0 onwards: - -``` -kubectl describe node k8s.bgp02 -... -Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock - node.alpha.kubernetes.io/ttl: 0 - metal.equinix.com/bgp-peers-0-node-asn: 65000 - metal.equinix.com/bgp-peers-0-peer-asn: 65530 - metal.equinix.com/bgp-peers-0-peer-ip: x.x.x.x - metal.equinix.com/bgp-peers-0-src-ip: x.x.x.x -``` - -2. Equinix Metal's CCM before v3.0.0: - -``` -kubectl describe node k8s.bgp02 -... -Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock - node.alpha.kubernetes.io/ttl: 0 - metal.equinix.com/node-asn: 65000 - metal.equinix.com/peer-asn: 65530 - metal.equinix.com/peer-ip: x.x.x.x - metal.equinix.com/src-ip: x.x.x.x -``` - -If there are errors regarding `169.254.255.1` or `169.254.255.2` in the `kube-vip` logs then the routes to the ToR switches that provide BGP peering may by missing from the nodes. They can be replaced with the below command: - -``` -GATEWAY_IP=$(curl https://metadata.platformequinix.com/metadata | jq -r ".network.addresses[] | select(.public == false) | .gateway") -ip route add 169.254.255.1 via $GATEWAY_IP -ip route add 169.254.255.2 via $GATEWAY_IP -``` - -Additionally examining the logs of the Packet CCM may reveal why the node is not yet ready. - -## K3s overview (on Equinix Metal) - -### Step 1: TIDY (best if something was running before) -`rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; ip addr flush dev lo; ip addr add 127.0.0.1/8 dev lo; mkdir -p /var/lib/rancher/k3s/server/manifests/` - -### Step 2: Get rbac -`curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/rbac.yaml` - -### Step 3: Generate kube-vip (get EIP from CLI or UI) - -``` -export EIP=x.x.x.x -export INTERFACE=lo -``` - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --vip $EIP \ - --controlplane \ - --services \ - --inCluster \ - --taint \ - --bgp \ - --metal \ - --provider-config /etc/cloud-sa/cloud-sa.json | tee /var/lib/rancher/k3s/server/manifests/vip.yaml -``` - -NOTE: the `—provider-config` actually comes from the secret we apply in step 5 (this will leave kube-vip waiting to start) - -### Step 4: Up Cluster -`K3S_TOKEN=SECRET k3s server --cluster-init --tls-san $EIP --no-deploy servicelb --disable-cloud-controller` - -### Step 5: Add CCM - -`alias k="k3s kubectl"` -`k apply -f ./secret.yaml` - -(^ https://github.com/packethost/packet-ccm/blob/master/deploy/template/secret.yaml) - -`k apply -f https://gist.githubusercontent.com/thebsdbox/c86dd970549638105af8d96439175a59/raw/4abf90fb7929ded3f7a201818efbb6164b7081f0/ccm.yaml` - -### Step 6: Demo ! -`k apply -f https://k8s.io/examples/application/deployment.yaml` -`k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` - -### Step 7 watch and test: -`k get svc --watch` diff --git a/docs/hybrid/index.md b/docs/hybrid/index.md deleted file mode 100644 index f83fbea9..00000000 --- a/docs/hybrid/index.md +++ /dev/null @@ -1,142 +0,0 @@ -# Using kube-vip in Hybrid Mode - -We can deploy kube-vip in two different methods, which completely depends on your use-case and method for installing Kubernetes: - -- Static Pods (hybrid) -- Daemonset (hybrid, requires taint) - -## Prerequisites - -In order for `kube-vip` to be able to speak with the Kubernetes API server, we need to be able to resolve the hostname within the pod. In order to ensure this will work as expected the `/etc/hosts` file should have the `hostname` of the server within it. The `/etc/hosts` file is passed into the running container and will ensure that the pod isn't "confused" by any Kubernetes networking. - -## Kubernetes Services (`type:LoadBalancer`) - -To learn more about how `kube-vip` in hybrid works with the LoadBalancer services within a kubernetes cluster the documentation is [here](./services/). To get `kube-vip` deployed read on! - -## Static Pods - -Static pods are a Kubernetes pod that is ran by the `kubelet` on a single node, and is **not** managed by the Kubernetes cluster itself. This means that whilst the pod can appear within Kubernetes it can't make use of a variety of kubernetes functionality (such as the kubernetes token or `configMaps`). The static pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/), this is due to the sequence of actions performed by `kubeadm`. Ideally we want `kube-vip` to be part of the kubernetes cluster, for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. - -The sequence of events for this to work follows: - -1. Generate a `kube-vip` manifest in the static pods manifest folder -2. Run `kubeadm init`, this generates the manifests for the control plane and wait to connect to the VIP -3. The `kubelet` will parse and execute all manifest, including the `kube-vip` manifest -4. `kube-vip` starts and advertises our VIP -5. The `kubeadm init` finishes successfully. - -## Daemonset - -Other Kubernetes distributions can bring up a Kubernetes cluster, without depending on a VIP (BUT they are configured to support one). A prime example of this would be k3s, that can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist **before** the cluster, we can bring up the k3s node(s) and then add `kube-vip` as a daemonset for all control plane nodes. - -## Deploying `kube-vip` - -The simplest method for generating the Kubernetes manifests is with `kube-vip` itself.. The subcommand `manifest pod|daemonset` can be used to generate specific types of Kubernetes manifests for use in a cluster. These subcommands can be configured with additional flags to enable/disable BGP/ARP/LeaderElection and a host of other options. - -Both Examples will use the same Architecture: - -## Infrastructure architecture - -The infrastructure for our example HA Kubernetes cluster is as follows: - -| Node | Address | -| -------------- | --------- | -| VIP | 10.0.0.40 | -| controlPlane01 | 10.0.0.41 | -| controlPlane02 | 10.0.0.42 | -| controlPlane03 | 10.0.0.43 | -| worker01 | 10.0.0.44 | - -All nodes are running Ubuntu 18.04, Docker CE and will use Kubernetes 1.19.0, we only have one worker as we're going to use our controlPlanes in "hybrid" mode. - -## As a static Pod (for kubeadm) - -The details for creating a static pod are available [here](./static/) - -## As a daemonset - -When using `kube-vip` as a daemonset the details are available [here](./daemonset/) - -## Kube-Vip flag reference - -| Category | Flag | Usage | Notes | -| ------------------ | ---------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------- | -| **Mode** | | | | -| | `--controlPlane` | Enables `kube-vip` control-plane functionality | | -| | `--services` | Enables `kube-vip` to watch services of type:LoadBalancer | | -| **Vip Config** | | | | -| | `--arp` | Enables ARP broadcasts from Leader | | -| | `--bgp` | Enables BGP peering from `kube-vip` | | -| | `--vip` | `` | (deprecated) | -| | `--address` | `` or `` | | -| | `--interface` | `` | | -| | `--leaderElection` | Enables Kubernetes LeaderElection | Used by ARP, as only the leader can broadcast | -| **Services** | | | | -| | `--cidr` | Defaults "32" | Used when advertising BGP addresses (typically as `x.x.x.x/32`) | -| **Kubernetes** | | | | -| | `--inCluster` | Defaults to looking inside the Pod for the token | | -| | `--taint` | Enables a taint, stopping control plane daemonset being on workers | | -| **LeaderElection** | | | | -| | `--leaseDuration` | default 5 | Seconds a lease is held for | -| | `--leaseRenewDuration` | default 3 | Seconds a leader can attempt to renew the lease | -| | `--leaseRetry` | default 1 | Number of times the leader will hold the lease for | -| | `--namespace` | "kube-vip" | The namespace where the lease will reside | -| **BGP** | | | | -| | `--bgpRouterID` | `` | Typically the address of the local node | -| | `--localAS` | default 65000 | The AS we peer from | -| | `--bgppeers` | `` | Comma separated list of BGP peers | -| | `--peerAddress` | `` | Address of a single BGP Peer | -| | `--peerAS` | default 65000 | AS of a single BGP Peer | -| | `--peerPass` | "" | Password to work with a single BGP Peer | -| | `--multiHop` | Enables eBGP MultiHop | Enable multiHop with a single BGP Peer | -| | `--annotations` | `` | Startup will be paused until the node annotations contain the BGP configuration | -| **Equinix Metal** | | | (May be deprecated) | -| | `--metal` | Enables Equinix Metal API calls | | -| | `--metalKey` | Equinix Metal API token | | -| | `--metalProject` | Equinix Metal Project (Name) | | -| | `--metalProjectID` | Equinix Metal Project (UUID) | | -| | `--provider-config` | Path to the Equinix Metal provider configuration | Requires the Equinix Metal CCM | - -## Changelog - -### Static DNS Support (added in 0.2.0) - -A new flag `--address` is introduced to support using a DNS record as the control plane endpoint. `kube-vip` will do a dns lookup to retrieve the IP for the DNS record, and use that IP as the VIP. An `dnsUpdater` periodically checks and updates the system if IP changes for the DNS record. - -### Dynamic DNS Support (added in 0.2.1) - -`kube-vip` was also updated to support DHCP + [Dynamic DNS](https://en.wikipedia.org/wiki/Dynamic_DNS), for the use case where it's not able to reserve a static IP for the control plane endpoint. - -A new flag `--ddns` is introduced. Once enabled, `kube-vip` expects the input `--address` will be a FQDN without binding to an IP. Then `kube-vip` will start a dhcp client to allocate an IP for the hostname of FQDN, and maintain the lease for it. - -Once DHCP returns an IP for the FQDN, the same `dnsUpdater` runs to periodically checks and updates if IP got changed. - -## BGP Support (added in 0.1.8) - -In version `0.1.8` `kube-vip` was updated to support [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) as a VIP failover mechanism. When a node is elected as a leader then it will update it's peers so that they are aware to route traffic to that node in order to access the VIP. - -The following new flags are used: - -- `--bgp` This will enable BGP support within kube-vip -- `--localAS` The local AS number -- `--bgpRouterID` The local router address -- `--peerAS` The AS number for a BGP peer -- `--peerAddress` The address of a BGP peer - -### Equinix Metal BGP support - -If the `--bgp` flag is passed along with the Equinix Metal flags `metal, metalKey and metalProject`, then Equinix Metal API will be used in order to determine the BGP configuration for the nodes being used in the cluster. This automates a lot of the process and makes using BGP within Equinix Metal much simpler. - -## Equinix Metal Control Plane Support (added in 0.1.8) - -Recently in version `0.1.7` of `kube-vip` we added the functionality to use a Equinix Metal Elastic IP as the virtual IP fronting the Kubernetes Control plane cluster. In order to first get out virtual IP we will need to use our Equinix Metal account and create a EIP (either public or private). We will only need a single address so a `/32` will suffice, once this is created as part of a Equinix Metal project we can now apply this address to the servers that live in the same project. - -In this example we've logged into the UI can created a new EIP of `147.75.1.2`, and we've deployed three small server instances with Ubuntu. - -The following new flags are used: - -- `--metal` which enables the use of the Equinix Metal API -- `--metalKey` which is our API key -- `--metalProject`which is the name of our Equinix Metal project where our servers and EIP are located. - -*Also* the `--arp` flag should NOT be used as it wont work within the Equinix Metal network. diff --git a/docs/hybrid/services/index.md b/docs/hybrid/services/index.md deleted file mode 100644 index ee3ebc92..00000000 --- a/docs/hybrid/services/index.md +++ /dev/null @@ -1,269 +0,0 @@ -# Kube-vip services - -We've designed `kube-vip` to be as de-coupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes services to the outside world and marking these services as ready to use. - -## Flow - -This section details the flow of events in order for `kube-vip` to advertise a Kubernetes service: - -1. An end user exposes a application through Kubernetes as a LoadBalancer => `kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx` -2. Within the Kubernetes cluster a service object is created with the `spec.Type = LoadBalancer` -3. A controller (typically a Cloud Controller) has a loop that "watches" for services of the type `LoadBalancer`. -4. The controller now has the responsibility of providing an IP address for this service along with doing anything that is network specific for the environment where the cluster is running. -5. Once the controller has an IP address, it will update the Service field `metadata.annotations["kube-vip.io/loadbalancerIPs"]` and `spec.loadBalancerIP` with the IP address. `spec.loadBalancerIP` is deprecated in k8s 1.24, will not be updated in future release -6. `kube-vip` Pods implement a "watcher" for Services that have a `metadata.annotations["kube-vip.io/loadbalancerIPs"]` address attached. If the annotation is not presented, it will fallback to check `spec.loadBalancerIP`. -7. When a new service appears `kube-vip` will start advertising this address to the wider network (through BGP/ARP) which will allow traffic to come into the cluster and hit the service network. -8. Finally `kube-vip` will update the service status so that the API reflects that this LoadBalancer is ready. This is done by updating the `status.LoadBalancer.Ingress` with the VIP address. - -## CCM - -We can see from the [flow](#Flow) above that `kube-vip` isn't coupled to anything other than the Kubernetes API, and will only act upon an existing Kubernetes primative (in this case the object of type `Service`). This makes it easy for existing CCMs to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load-balancers to the outside world. - - -## Using the Kube-vip Cloud Provider - -The below instructions *should just work* on Kubernetes regardless of architecture (Linux Operating System is the only requirement) - you can quickly install the "latest" components: - -**Install the `kube-vip-cloud-provider`** - -``` -$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml -``` - -It uses a `statefulSet` and can always be viewed with the following command: - -``` -kubectl describe pods -n kube-system kube-vip-cloud-provider-0 -``` - -**Create a global CIDR or IP Range** - -Any `service` in any `namespace` can use an address from the global CIDR `cidr-global` or range `range-global` - -``` -kubectl create configmap --namespace kube-system kubevip --from-literal cidr-global=192.168.0.220/29 -``` -or -``` -kubectl create configmap --namespace kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 -``` - -Creating services of `type: LoadBalancer` in *any namespace* will now take addresses from the **global** cidr defined in the `configmap` unless a specific - - -## The Detailed guide - -### Deploy the Kube-vip Cloud Provider - -**Install the `kube-vip-cloud-provider`** - -``` -$ kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml -``` - -The following output should appear when the manifest is applied: - -``` -serviceaccount/kube-vip-cloud-controller created -clusterrole.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-role created -clusterrolebinding.rbac.authorization.k8s.io/system:kube-vip-cloud-controller-binding created -statefulset.apps/kube-vip-cloud-provider created -``` - -We can validate the cloud provider by examining the pods and following the logs: - -``` -kubectl describe pods -n kube-system kube-vip-cloud-provider-0 -kubectl logs -n kube-system kube-vip-cloud-provider-0 -f -``` - -### The Kube-vip Cloud Provider `configmap` - -To manage the IP address ranges for the load balancer instances the `kube-vip-cloud-provider` uses a `configmap` held in the `kube-system` namespace. IP address ranges can be configured using: -- IP address pools by CIDR -- IP ranges [start address - end address] -- Multiple pools by CIDR per namespace -- Multiple IP ranges per namespace (handles overlapping ranges) -- Setting of static addresses through --load-balancer-ip=x.x.x.x - -To control which IP address range is used for which service the following rules are applied: -- Global address pools (`cidr-global` or `range-global`) are available for use by *any* `service` in *any* `namespace` -- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by `service` in the *specific* `namespace` -- Static IP addresses can be applied to a load balancer `service` using the `loadbalancerIP` setting, even outside of the assigned ranges - -Example Configmap: - -``` -$ kubectl get configmap -n kube-system kubevip -o yaml - -apiVersion: v1 -kind: ConfigMap -metadata: - name: kubevip - namespace: kube-system -data: - cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default namespace - range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development namespace - cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance namespace - cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any namespace -``` - -### Expose a service - -We can now expose a service and once the cloud provider has provided an address `kube-vip` will start to advertise that address to the outside world as shown below! - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx -``` - -or via a `service` YAML definition - -``` -apiVersion: v1 -kind: Service -metadata: - name: nginx -spec: - ports: - - name: http - port: 80 - protocol: TCP - selector: - app: nginx - type: LoadBalancer - ``` - - -We can also expose a specific address by specifying it on the command line: - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` - -or including it in the `service` definition: - -``` -apiVersion: v1 -kind: Service -metadata: - name: nginx -spec: - ports: - - name: http - port: 80 - protocol: TCP - selector: - app: nginx - type: LoadBalancer - loadBalancerIP: "1.1.1.1" -``` - -### Using DHCP for Load Balancers (experimental) - -With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a - Kubernetes service on the network. - -In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the -address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! - -``` -$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc -service/nginx-dhcp exposed -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s - -{ ... a second or so later ... } - -$ k get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s -``` - -### Using UPNP to expose a service to the outside world - -With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the inte -rnet. - -Most simple networks look something like the following: - -`<----- ----> Internet` - -Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. - -#### Enable UPNP - -Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. - -**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) - -``` -- name: enableUPNP - value: "true" -``` - -#### Exposing a service - -To expose a port successfully we'll need to change the command slightly: - -`--target-port=80` the port of the application in the pods (HTT/NGINX) -`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) - -`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` - -The above example should expose a port on your external (internet facing address), that can be tested externally with: - -``` -$ curl externalIP:32380 - - -... -``` - -### Expose with Equinix Metal (using the `kube-vip-cloud-provider`) - -Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! - -``` -# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 -+-------+---------------+--------+----------------------+ -| ID | ADDRESS | PUBLIC | CREATED | -+-------+---------------+--------+----------------------+ -| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | -+-------+---------------+--------+----------------------+ - -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` - -## Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) - -Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. - -**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/packethost/packet-ccm) to be installed and that the cluster/kubelet is configured to use an "external" cloud provider. - -### Using Annotations - -This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --services \ - --bgp \ - --annotations metal.equinix.com \ - --inCluster | k apply -f - -``` - -### Using the existing CCM secret - -Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. - -``` -kube-vip manifest daemonset --interface $INTERFACE \ ---services \ ---inCluster \ ---bgp \ ---metal \ ---provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - -``` diff --git a/docs/hybrid/static/index.md b/docs/hybrid/static/index.md deleted file mode 100644 index 5e193ece..00000000 --- a/docs/hybrid/static/index.md +++ /dev/null @@ -1,129 +0,0 @@ -# Kube-vip as a Static Pod - -In Hybrid mode `kube-vip` will manage a virtual IP address that is passed through it's configuration for a Highly Available Kubernetes cluster, it will also "watch" services of `type:LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller) it will advertise this address using BGP/ARP. - -The "hybrid" mode is now the default mode in `kube-vip` from `0.2.3` onwards, and allows both modes to be enabled at the same time. - -## Generating a Manifest - -This section details creating a number of manifests for various use cases - -### Set configuration details - -`export VIP=192.168.0.40` - -`export INTERFACE=` - -### Configure to use a container runtime - -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. - -#### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:0.3.7 vip /kube-vip"` - -#### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:0.3.7"` - - -### ARP - -This configuration will create a manifest that starts `kube-vip` providing **controlplane** and **services** management, using **leaderElection**. When this instance is elected as the leader it will bind the `vip` to the specified `interface`, this is also the same for services of `type:LoadBalancer`. - -`export INTERFACE=eth0` - -``` -kube-vip manifest pod \ - --interface $INTERFACE \ - --vip $VIP \ - --controlplane \ - --services \ - --arp \ - --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -### BGP - -This configuration will create a manifest that will start `kube-vip` providing **controlplane** and **services** management. **Unlike** ARP, all nodes in the BGP configuration will advertise virtual IP addresses. - -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma seperate list in the format of `address:AS:password:multihop`. - -`export INTERFACE=lo` - -``` -kube-vip manifest pod \ - --interface $INTERFACE \ - --vip $VIP \ - --controlplane \ - --services \ - --bgp \ - --localAS 65000 \ - --bgpRouterID 192.168.0.2 \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -### BGP with Equinix Metal - -When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). - -**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/packethost/packet-ccm)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. - -#### Creating a manifest using the API - -We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. - -``` -kube-vip manifest pod \ - --interface $INTERFACE\ - --vip $VIP \ - --controlplane \ - --services \ - --bgp \ - --metal \ - --metalKey xxxxxxx \ - --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -#### Creating a manifest using the metadata - -We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. - -``` -kube-vip manifest pod \ - --interface $INTERFACE\ - --vip $VIP \ - --controlplane \ - --services \ - --bgp \ - --peerAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].peer_as') \ - --peerAddress $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].peer_ips[0]') \ - --localAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].customer_as') \ - --bgpRouterID $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].customer_ip') | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -## Deploy your Kubernetes Cluster - -### First node - -``` -sudo kubeadm init \ - --kubernetes-version 1.19.0 \ - --control-plane-endpoint $VIP \ - --upload-certs -``` - -### Additional Node(s) - -Due to an oddity with `kubeadm` we can't have our `kube-vip` manifest present **before** joining our additional nodes. So on these control plane nodes we will add them first to the cluster. - -``` -sudo kubeadm join $VIP:6443 \ - --token w5atsr.blahblahblah - --control-plane \ - --certificate-key abc123 -``` - -**Once**, joined these nodes can have the same command that we ran on the first node to populate the `/etc/kubernetes/manifests/` folder with the `kube-vip` manifest. - -## Services - -At this point your `kube-vip` static pods will be up and running and where used with the `--services` flag will also be watching for Kubernetes services that they can advertise. In order for `kube-vip` to advertise a service it needs a CCM or other controller to apply an IP address to the `spec.LoadBalancerIP`, which marks the loadbalancer as defined. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 92674069..00000000 --- a/docs/index.md +++ /dev/null @@ -1,70 +0,0 @@ -![kube-vip.png](kube-vip.png) - -## Overview - -Kube-Vip provides Kubernetes clusters a virtual IP and load balancer for both control plane and Kubernetes Services. - -The idea behind `kube-vip` is a small, self-contained, highly-available option for all environments, especially: - -- Bare metal -- On-Premises -- Edge (ARM / Raspberry Pi) -- Virtualisation -- Pretty much anywhere else :) - -## Features - -Kube-Vip was originally created to provide a HA solution for the Kubernetes control plane, but over time it has evolved to incorporate that same functionality for Kubernetes Services of type [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer). Some of the features include: - -- VIP addresses can be either IPv4 or IPv6 -- Control Plane with ARP (Layer 2) or BGP (Layer 3) -- Control Plane using either [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) or [raft](https://en.wikipedia.org/wiki/Raft_(computer_science)) -- Control Plane HA with kubeadm (static Pods) -- Control Plane HA with K3s/and others (DaemonSets) -- Control Plane LoadBalancing with IPVS (kube-vip ≥ 0.4) -- Service LoadBalancer using [leader election](https://godoc.org/k8s.io/client-go/tools/leaderelection) for ARP (Layer 2) -- Service LoadBalancer using multiple nodes with BGP -- Service LoadBalancer address pools per namespace or global -- Service LoadBalancer address via (existing network DHCP) -- Service LoadBalancer address exposure to gateway via UPnP -- ... manifest generation, vendor API integrations and many more... - -## Why? - -The "original" purpose of `kube-vip` was to simplify the building of HA Kubernetes clusters, which at the time involved a few components and configurations that all needed to be managed. This was blogged about in detail by [thebsdbox](https://twitter.com/thebsdbox/) [here](https://thebsdbox.co.uk/2020/01/02/Designing-Building-HA-bare-metal-Kubernetes-cluster/#Networking-load-balancing). Since the project has evolved, it can now use those same technologies to provide load balancing capabilities within a Kubernetes Cluster. - -## Architecture - -The architecture for `kube-vip` (and associated Kubernetes components) is covered in detail [here](/architecture/). - -## Installation - -There are two main routes for deploying `kube-vip`: either through a [static Pod](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) when bringing up a Kubernetes cluster with [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) or as a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (typically with distributions like [K3s](https://k3s.io)). - -- [Static Pod](/install_static) -- [DaemonSet](/install_daemonset) - -## Usage - -- [On-Prem with the kube-vip cloud controller](/usage/on-prem) -- [KinD](/usage/kind) -- [Equinix Metal](/usage/EquinixMetal) -- [k3s](/usage/k3s) - -## Flags/Environment Variables - -- [Flags and Environment variables](/flags/) - -## Links - -- [Kube-Vip Cloud Provider Repository](https://github.com/kube-vip/kube-vip-cloud-provider) -- [Kube-Vip Repository](https://github.com/kube-vip/kube-vip) -- [Kube-Vip RBAC manifest (required for the DaemonSet)](https://kube-vip.io/manifests/rbac.yaml) - -## Copyright - -© 2021 [The Linux Foundation](https://www.linuxfoundation.org/). All rights reserved. - -The Linux Foundation has registered trademarks and uses trademarks. - -For a list trademarks of The Linux Foundation, please see our [Trademark Usage page](https://www.linuxfoundation.org/en/trademark-usage). diff --git a/docs/install_daemonset/index.md b/docs/install_daemonset/index.md deleted file mode 100644 index 95687ef4..00000000 --- a/docs/install_daemonset/index.md +++ /dev/null @@ -1,253 +0,0 @@ -# Kube-Vip as a DaemonSet - -## DaemonSet - -Some Kubernetes distributions can bring up a Kubernetes cluster without depending on a pre-existing VIP (but they may be configured to support one). A prime example of this would be K3s which can be configured to start and also sign the certificates to allow incoming traffic to a virtual IP. Given we don't need the VIP to exist before the cluster, we can bring up the K3s node(s) and then add `kube-vip` as a DaemonSet for all control plane nodes. - -If the Kubernetes installer allows for adding a virtual IP as an additional [SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name) to the API server certificate, we can apply `kube-vip` to the cluster once the first node has been brought up. - -Unlike running `kube-vip` as a [static Pod](/install_static) there are a few more things that may need configuring when running `kube-vip` as a DaemonSet. This page will cover primarily the differences. - -## Kube-Vip as HA, Load Balancer, or both - -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. - -## Create the RBAC settings - -Since `kube-vip` as a DaemonSet runs as a regular resource instead of a static Pod, it still needs the correct access to be able to watch Kubernetes Services and other objects. In order to do this, RBAC resources must be created which include a ServiceAccount, ClusterRole, and ClusterRoleBinding and can be applied this with the command: - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` - -## Generating a Manifest - -In order to create an easier experience of consuming the various functionality within `kube-vip`, we can use the `kube-vip` container itself to generate our DaemonSet manifest. We do this by running the `kube-vip` image as a container and passing in the various [flags](/flags/) for the capabilities we want to enable. Generating a `kube-vip` manifest for running as a DaemonSet is almost identical to the process when running `kube-vip` as a [static Pod](/install_static). Only a few flags are different between the two processes. Therefore, refer back to the [Generating a Manifest](/install_static/#generating-a-manifest) section on the [static Pod installation page](/install_static) for the main process steps. - -### ARP Example for DaemonSet - -When creating the `kube-vip` installation manifest as a DaemonSet, the `manifest` subcommand takes the value `daemonset` as opposed to the `pod` value. The flags `--inCluster` and `--taint` are also needed to configure the DaemonSet to use a ServiceAccount and affine the `kube-vip` Pods to control plane nodes thereby preventing them from running on worker instances. - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --address $VIP \ - --inCluster \ - --taint \ - --controlplane \ - --services \ - --arp \ - --leaderElection -``` - -#### Example ARP Manifest - -```yaml -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: node-role.kubernetes.io/master - operator: Exists - - matchExpressions: - - key: node-role.kubernetes.io/control-plane - operator: Exists - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: ens160 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: address - value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - tolerations: - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 -``` - -### BGP Example for DaemonSet - -This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management. Unlike ARP, all nodes in the BGP configuration will advertise virtual IP addresses. - -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma-separated list in the format of `address:AS:password:multihop`. - -`export INTERFACE=lo` - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --address $VIP \ - --inCluster \ - --taint \ - --controlplane \ - --services \ - --bgp \ - --localAS 65000 \ - --bgpRouterID 192.168.0.2 \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false - -``` - -#### Example BGP Manifest - -```yaml -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: node-role.kubernetes.io/master - operator: Exists - - matchExpressions: - - key: node-role.kubernetes.io/control-plane - operator: Exists - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: ens160 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: bgp_enable - value: "true" - - name: bgp_routerid - value: 192.168.0.2 - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: bgp_peers - value: 192.168.0.10:65000::false,192.168.0.11:65000::false - - name: address - value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - tolerations: - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 -``` - -#### Managing a `routerID` as a DaemonSet - -The `routerID` needs to be unique on each node that participates in BGP advertisements. In order to do this, we can modify the manifest so that when `kube-vip` starts it will look up its local address and use that as the `routerID`. Add the following to the `env[]` array of the container: - -```yaml -- name: bgp_routerinterface - value: "ens160" -``` - -### DaemonSet Manifest Overview - -Once the manifest for `kube-vip` as a DaemonSet is generated, these are some of the notable differences over the [static Pod](/install_static) manifest and their significance. - -- `nodeSelector`: Ensures that DaemonSet Pods only run on control plane nodes. -- `serviceAccountName: kube-vip`: Specifies the ServiceAccount name that will be used to get/update Kubernetes Service resources. -- `tolerations`: Allows scheduling to control plane nodes that normally specify `NoSchedule` or `NoExecute` taints. diff --git a/docs/install_static/index.md b/docs/install_static/index.md deleted file mode 100644 index a5a97b7a..00000000 --- a/docs/install_static/index.md +++ /dev/null @@ -1,257 +0,0 @@ -# Kube-Vip as a Static Pod - -## Static Pods - -[Static Pods](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/) are Kubernetes Pods that are run by the `kubelet` on a single node and are not managed by the Kubernetes cluster itself. This means that whilst the Pod can appear within Kubernetes, it can't make use of a variety of Kubernetes functionality (such as the Kubernetes token or ConfigMap resources). The static Pod approach is primarily required for [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) as this is due to the sequence of actions performed by `kubeadm`. Ideally, we want `kube-vip` to be part of the Kubernetes cluster, but for various bits of functionality we also need `kube-vip` to provide a HA virtual IP as part of the installation. - -### with kubeadm -The sequence of events for building a highly available Kubernetes cluster with `kubeadm` and `kube-vip` are as follows: - -1. Generate a `kube-vip` manifest in the static Pods manifest directory (see the [generating a manifest](#generating-a-manifest) section below). -2. Run `kubeadm init` with the `--control-plane-endpoint` flag using the VIP address provided when generating the static Pod manifest. -3. The `kubelet` will parse and execute all manifests, including the `kube-vip` manifest generated in step one and the other control plane components including `kube-apiserver`. -4. `kube-vip` starts and advertises the VIP address. -5. The `kubelet` on this first control plane will connect to the VIP advertised in the previous step. -6. `kubeadm init` finishes successfully on the first control plane. -7. Using the output from the `kubeadm init` command on the first control plane, run the `kubeadm join` command on the remainder of the control planes. -8. Copy the generated `kube-vip` manifest to the remainder of the control planes and place in their static Pods manifest directory (default of `/etc/kubernetes/manifests/`). - -### with k0sctl -The sequence of events for building a highly available Kubernetes cluster with `k0sctl` and `kube-vip` are as follows: - - -1. Generate a `kube-vip` manifest in the static Pods manifest directory (see the [generating a manifest](#generating-a-manifest) section below). -2. Run `k0sctl init > k0sctl.yaml` edit the manifest to change and add your host IPs. Controller need to have both role by using `role: controller+worker` -3. Add in `installFlags` option `--kubelet-extra-args=--pod-manifest-path=/etc/k0s/manifests/` and `--disable-components=konnectivity-server` -4. On the first controller in the list add a `hooks` options like bellow and replace value: - ```yaml - hooks: - apply: - before: - - /usr/sbin/ip addr add ${VIP} dev ${INTERFACE} || exit 0 - after: - - /usr/sbin/ip addr del ${VIP} dev ${INTERFACE} || exit 0 - ``` -5. On every controller in the list configure the `files` options to upload the `kube-vip` manifest into `/etc/k0s/manifests/` - ```yaml - files: - - name: kube-vip.yaml - src: kube-vip.yaml - dstDir: /etc/k0s/manifests/ - perm: 0655 - ``` -6. Configure the `k0s.config.spec.api.externalAddress` in the `k0s` config section in `k0sctl.yaml` -7. Deploy your cluster with `k0sctl apply` - - -## Kube-Vip as HA, Load Balancer, or both - -The functionality of `kube-vip` depends on the flags used to create the static Pod manifest. By passing in `--controlplane` we instruct `kube-vip` to provide and advertise a virtual IP to be used by the control plane. By passing in `--services` we tell `kube-vip` to provide load balancing for Kubernetes Service resources created inside the cluster. With both enabled, `kube-vip` will manage a virtual IP address that is passed through its configuration for a highly available Kubernetes cluster. It will also watch Services of type `LoadBalancer` and once their `service.metadata.annotations["kube-vip.io/loadbalancerIPs"]` or `spec.LoadBalancerIP` is updated (typically by a cloud controller, including (optionally) the one provided by kube-vip in [on-prem](/usage/on-prem) scenarios) it will advertise this address using BGP/ARP. In this example, we will use both when generating the manifest. - -## Generating a Manifest - -In order to create an easier experience of consuming the various functionality within `kube-vip`, we can use the `kube-vip` container itself to generate our static Pod manifest. We do this by running the `kube-vip` image as a container and passing in the various [flags](/flags/) for the capabilities we want to enable. - -### Set configuration details - -We use environment variables to predefine the values of the inputs to supply to `kube-vip`. - -Set the `VIP` address to be used for the control plane: - -`export VIP=192.168.0.40` - -Set the `INTERFACE` name to the name of the interface on the control plane(s) which will announce the VIP. In many Linux distributions this can be found with the `ip a` command. - -`export INTERFACE=ens160` - -Get the latest version of the `kube-vip` release by parsing the GitHub API. This step requires that `jq` and `curl` are installed. - -`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` - -To set manually instead, find the desired [release tag](https://github.com/kube-vip/kube-vip/releases): - -`export KVVERSION=v0.4.0` - -### Creating the manifest - -With the input values now set, we can pull and run the `kube-vip` image supplying it the desired flags and values. Once the static Pod manifest is generated for your desired method (ARP or BGP), if running multiple control plane nodes, ensure it is placed in each control plane's static manifest directory (by default, `/etc/kubernetes/manifests`). - -Depending on the container runtime, use one of the two aliased commands to create a `kube-vip` command which runs the `kube-vip` image as a container. - -For containerd, run the below command: - -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` - -For Docker, run the below command: - -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` - -### ARP - -With the inputs and alias command set, we can run the `kube-vip` container to generate a static Pod manifest which will be directed to a file at `/etc/kubernetes/manifests/kube-vip.yaml`. As such, this is assumed to run on the first control plane node. - -This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management using the `leaderElection` method and ARP. When this instance is elected as the leader, it will bind the `vip` to the specified `interface`. This is the same behavior for Services of type `LoadBalancer`. - -> Note: When running these commands on a to-be control plane node, `sudo` access may be required along with pre-creation of the `/etc/kubernetes/manifests/` directory. - -``` -kube-vip manifest pod \ - --interface $INTERFACE \ - --address $VIP \ - --controlplane \ - --services \ - --arp \ - --leaderElection | tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -#### Example ARP Manifest - -``` -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: ens192 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: address - value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} -``` - -### BGP - -This configuration will create a manifest that starts `kube-vip` providing control plane VIP and Kubernetes Service management. Unlike ARP, all nodes in the BGP configuration will advertise virtual IP addresses. - -**Note** we bind the address to `lo` as we don't want multiple devices that have the same address on public interfaces. We can specify all the peers in a comma-separated list in the format of `address:AS:password:multihop`. - -`export INTERFACE=lo` - -``` -kube-vip manifest pod \ - --interface $INTERFACE \ - --address $VIP \ - --controlplane \ - --services \ - --bgp \ - --localAS 65000 \ - --bgpRouterID 192.168.0.2 \ - --bgppeers 192.168.0.10:65000::false,192.168.0.11:65000::false | tee /etc/kubernetes/manifests/kube-vip.yaml -``` - -#### Example BGP Manifest - -``` -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: ens192 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: bgp_enable - value: "true" - - name: bgp_routerid - value: 192.168.0.2 - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: bgp_peers - value: 192.168.0.10:65000::false,192.168.0.11:65000::false - - name: address - value: 192.168.0.40 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} -``` diff --git a/docs/k3s b/docs/k3s deleted file mode 100644 index 73840e89..00000000 --- a/docs/k3s +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -echo "apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: \"true\" - - name: vip_interface - value: $vipInterface - - name: port - value: \"6443\" - - name: vip_cidr - value: \"32\" - - name: cp_enable - value: \"true\" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: \"false\" - - name: vip_address - value: $vipAddress - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - nodeSelector: - node-role.kubernetes.io/master: \"true\" - serviceAccountName: kube-vip - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0" \ No newline at end of file diff --git a/docs/kube-vip.png b/docs/kube-vip.png deleted file mode 100644 index d6384f251aecdf0c8b35cb53f9a4c6d0af181e6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62135 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. - -The following output should appear when the manifest is applied: -``` -serviceaccount/vip created -role.rbac.authorization.k8s.io/vip-role created -rolebinding.rbac.authorization.k8s.io/vip-role-bind created -deployment.apps/kube-vip-cluster created -``` - -*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. - -### Editing `kube-vip` configuration - -Either download and edit the manifest locally or apply as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) - -``` - - name: vip_interface - value: ens192 - - name: vip_configmap - value: plndr - - name: vip_arp - value: "true" - - name: vip_loglevel - value: "5" -``` - -- `vip_interface` - defines the interface that the VIP will bind to -- `vip_configmap` - defines the `configmap` that `kube-vip` will watch for service configuration -- `vip_arp` - determines if ARP broadcasts are enabled -- `vip_loglevel` - determines the verbosity of logging - -## Using other namespaces - -In this example we'll deploy and load-balance within the namespace `plunder` - -### Create the namespace - -`kubectl create namespace plunder` - -### Add a network range/cidr for this namespace - -`kubectl edit -n kube-system configmap/plndr` - -We will add the range 192.168.0.210/29 for the namespace plunder underneath the existing range for the namespace default: - -``` -apiVersion: v1 -data: - cidr-default: 192.168.0.200/29 - cidr-global: 192.168.0.210/29 - cidr-plunder: 192.168.0.220/29 -<...> -``` - -### Deploy `kube-vip` in the namespace **plunder** - -In the same way we deployed `kube-vip` into the default namespace we can deploy the same manifest into a different namespace using `-n namespace` e.g. - -**Note** change the version of manifest when actually deploying! - -``` -kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml -n plunder -``` - -## Usage - -This example will deploy into the namespace `plunder` as mention in the [Using other namespaces](Using other namespaces) example. Remove the `-n plunder` to deploy within the `default` namespace. - -### Deploy nginx - -``` -kubectl create deployment --image nginx plunder-nginx --namespace plunder -``` - -### Create a load balancer - -``` -kubectl expose deployment plunder-nginx --port=80 --type=LoadBalancer --namespace plunder -``` - -## Using DHCP for Load Balancers (experimental) - -With the latest release of `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load-balancer address that can be used to access a Kubernetes service on the network. - -In order to do this we need to signify to `kube-vip` and the cloud-provider that we don't need one of their managed addresses. We do this by explicitly exposing a service on the address `0.0.0.0`. When `kube-vip` sees a service on this address it will create a `macvlan` interface on the host and request a DHCP address, once this address is provided it will assign it as the VIP and update the Kubernetes service! - -``` -$ k expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; k get svc -service/nginx-dhcp exposed -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s - -{ ... a second or so later ... } - -$ k get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s -``` - -## Using UPNP to expose a service to the outside world - -With the latest release of `kube-vip` > 0.2.1, it is possible to expose a load-balancer on a specific port and using UPNP (on a supported gateway) expose this service to the internet. - -Most simple networks look something like the following: - -`<----- ----> Internet` - -Using UPNP we can create a matching port on the `` allowing your service to be exposed to the internet. - -### Enable UPNP - -Add the following to the `kube-vip` `env:` section, and the rest should be completely automated. - -**Note** some environments may require (Unifi) will require `Secure mode` being `disabled` (this allows a host with a different address to register a port) - -``` -- name: enableUPNP - value: "true" -``` - -### Exposing a service - -To expose a port successfully we'll need to change the command slightly: - -`--target-port=80` the port of the application in the pods (HTT/NGINX) -`--port=32380` the port the service will be exposed on (and what you should connect to in order to receive traffic from the service) - -`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` - -The above example should expose a port on your external (internet facing address), that can be tested externally with: - -``` -$ curl externalIP:32380 - - -... -``` - -## Troubleshooting - -Typically the logs from the `kube-vip` controller will reveal the most clues as to where a problem may lie. - -The `ClusterRoleBinding` is missing will result in the following: - -``` -E0229 17:36:38.014351 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) -E0229 17:36:38.014352 1 retrywatcher.go:129] Watch failed: unknown (get endpoints) -``` - -Additionally ensure that the vip_interface matches the correct interface from `ip addr` \ No newline at end of file diff --git a/docs/kubernetes/bgp/index.md b/docs/kubernetes/bgp/index.md deleted file mode 100644 index 160376c0..00000000 --- a/docs/kubernetes/bgp/index.md +++ /dev/null @@ -1,87 +0,0 @@ -# Kube-vip (Layer 3 / BGP) - -## Deploy `kube-vip` - -To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml`, specific versions should be found in the repository as detailed below: - -From the GitHub repository [https://github.com/kube-vip/kube-vip/tree/master/example/deploy](https://github.com/kube-vip/kube-vip/tree/master/example/deploy) find the version of the `kube-vip` to deploy (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. - -The following output should appear when the manifest is applied: -``` -serviceaccount/vip created -role.rbac.authorization.k8s.io/vip-role created -rolebinding.rbac.authorization.k8s.io/vip-role-bind created -deployment.apps/kube-vip-cluster created -``` - -*NOTE* The manifest for the `kube-vip` deployment has rules to ensure affinity (pods are always distributed to different nodes for HA). By default the replicas are set to `3` in the event you have less than `3` worker nodes then those replicas will sit as `pending`. This in itself isn't an issue, it means when new workers are added then they will be scheduled. *However*, tooling such as `kapps` will inspect the manifest before it's applied an error because of issues such as this. - -### Editing `kube-vip` configuration - -Either download and edit the manifest locally or apply as above and edit the deployment with `kubectl edit deploy/kube-vip-cluster` (change namespace where appropriate `-n`) - -Ensure the `vip_arp` isn't enabled as ARP and BGP can't be used at the same time (today), also that the `vip_interface` is set to localhost (`lo`). - -``` - - name: vip_interface - value: "lo" - - name: vip_configmap - value: "plndr" - - name: bgp_enable - value: "true" - - name: vip_loglevel - value: "5" -``` - -### BGP Specific configuration - -Additionally for BGP we'll need some configuration details, your local friendly network admin should be able to help here: - -``` - - name: bgp_routerid - value: "192.168.0.45" - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - value: "10.0.0.1" - - name: bgp_peeras - value: "65522" -``` - -### BGP on Packet - -If you're lucky enough to be running services on Packet then The above BGP information can be found from the API, instead of specifying the above we need to use the following: - -``` - - name: vip_packet - value: "true" - - name: vip_packetproject - value: "My Project" - - name: PACKET_AUTH_TOKEN - value: "XXYZZYVVY" -``` - -With the above configuration in place, all `kube-vip` pods will start in active mode and when a service is exposed then all nodes will advertise the VIP to the routers. - -## Expose a service - -Given that `kube-vip` doesn't know your network (at this point) ask your local friendly network OPs for an address you can advertise. That is the address you can expose to the outside world as shown below! - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` - -## Expose with packet - -Either through the CLI or through the UI, create a public IPv4 EIP address.. and this is the address you can expose through BGP! - -``` -# packet ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 -+-------+---------------+--------+----------------------+ -| ID | ADDRESS | PUBLIC | CREATED | -+-------+---------------+--------+----------------------+ -| xxxxx | 1.1.1.1 | true | 2020-11-10T15:57:39Z | -+-------+---------------+--------+----------------------+ - -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` \ No newline at end of file diff --git a/docs/kubernetes/index.md b/docs/kubernetes/index.md deleted file mode 100644 index 2078d83e..00000000 --- a/docs/kubernetes/index.md +++ /dev/null @@ -1,75 +0,0 @@ -# Usage - -The below instructions *should just work* on Kubernetes regardless of architecture, Linux as the Operating System is the only requirement. - -## The `tl;dr` guide - -If you just want things to "work", then you can quickly install the "latest" components: - -**NOTE** the `kube-vip.yaml` may need customising to set ARP/BGP OR to configure which interface to bind VIPs too. - -**Install the `plndr-cloud-provider`, and `kube-vip`** - -``` -kubectl apply -f https://kube-vip.io/manifests/controller.yaml -kubectl apply -f https://kube-vip.io/manifests/kube-vip.yaml -``` - -**Create the `cidr` for the `global` namespace** - -``` -kubectl create configmap --namespace kube-system plndr --from-literal cidr-global=192.168.0.200/29 -``` - -Creating services of `type: LoadBalancer` in the default namespace will now take addresses from the **global** cidr defined in the `configmap`. - -**Additional namespaces** - -Edit the `configmap` and add in the cidr ranges for those namespaces, the key in the cidr should be `cidr-`, then ensure that `kube-vip` is deployed into that namespace with the above `apply` command with the `-n namespace` flag. - -## The Detailed guide - -### Deploy the `plndr-cloud-provider` - -To deploy the [latest] then `kubectl apply -f https://kube-vip.io/manifests/controller.yaml`, specific versions should be found in the repository as detailed below: - -From the GitHub repository [https://github.com/kube-vip/plndr-cloud-provider/tree/master/example/pod](https://github.com/kube-vip/plndr-cloud-provider/tree/master/example/pod), find the version of the plunder cloud provider manifest (although typically the highest version number will provider more functionality/stability). The [raw] option in Github will provide the url that can be applied directly with a `kubectl apply -f `. - -The following output should appear when the manifest is applied: - -``` -serviceaccount/plunder-cloud-controller created -clusterrole.rbac.authorization.k8s.io/system:plunder-cloud-controller-role created -clusterrolebinding.rbac.authorization.k8s.io/system:plunder-cloud-controller-binding created -pod/plndr-cloud-provider created -``` - -We can validate the cloud-provider by examining the pods: - -`kubectl logs -n kube-system plndr-cloud-provider-0 -f` - -#### The `plndr-cloud-provider` `configmap` - -The `configmap` details a CIDR range *per* namespace, however as of (`kube-vip 0.2.1` and `plnder-cloud-provider 0.1.4`), there is now the option of having a **global** CIDR range (`cidr-global)`. - -To manage the ranges for the load-balancer instances, the `plndr-cloud-provider` has a `configmap` held in the `kube-system` namespace. The structure for the key/values within the `configmap` should be that the key is in the format `cidr-` and the value should be the cidr range. - -Example Configmap: - -``` -apiVersion: v1 -kind: ConfigMap -metadata: - name: plndr - namespace: kube-system -data: - cidr-default: 192.168.0.200/29 - cidr-global: 192.168.0.210/29 -``` - -### Deploying `kube-vip` - -To use `kube-vip` in Layer2/ARP the follow this [guide](/kubernetes/arp/) - -To use `kube-vip` in Layer3/BGP the follow this [guide](/kubernetes/bgp/) - diff --git a/docs/manifests/0.3.1/kube-vip-arp-ds.yaml b/docs/manifests/0.3.1/kube-vip-arp-ds.yaml deleted file mode 100644 index 7c55834f..00000000 --- a/docs/manifests/0.3.1/kube-vip-arp-ds.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: plndr/kube-vip:0.3.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/0.3.1/kube-vip-arp.yaml b/docs/manifests/0.3.1/kube-vip-arp.yaml deleted file mode 100644 index 9902ab88..00000000 --- a/docs/manifests/0.3.1/kube-vip-arp.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: plndr/kube-vip:0.3.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/0.3.1/kube-vip-bgp-ds.yaml b/docs/manifests/0.3.1/kube-vip-bgp-ds.yaml deleted file mode 100644 index 7b8b1499..00000000 --- a/docs/manifests/0.3.1/kube-vip-bgp-ds.yaml +++ /dev/null @@ -1,72 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: plndr/kube-vip:0.3.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml b/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml deleted file mode 100644 index a19807f1..00000000 --- a/docs/manifests/0.3.1/kube-vip-bgp-em-ds.yaml +++ /dev/null @@ -1,82 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: lo - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "false" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: plndr/kube-vip:0.3.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: packet-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/0.3.1/kube-vip-bgp.yaml b/docs/manifests/0.3.1/kube-vip-bgp.yaml deleted file mode 100644 index 1994407d..00000000 --- a/docs/manifests/0.3.1/kube-vip-bgp.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: svc_enable - value: "true" - - name: vip_startleader - value: "false" - - name: vip_addpeerstolb - value: "true" - - name: vip_localpeer - value: code:192.168.0.22:10000 - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: plndr/kube-vip:0.3.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/controller.yaml b/docs/manifests/controller.yaml deleted file mode 100644 index c5add884..00000000 --- a/docs/manifests/controller.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-vip-cloud-controller - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-cloud-controller-role -rules: - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "create", "update", "list", "put"] - - apiGroups: [""] - resources: ["configmaps", "endpoints","events","services/status", "leases"] - verbs: ["*"] - - apiGroups: [""] - resources: ["nodes", "services"] - verbs: ["list","get","watch","update"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:kube-vip-cloud-controller-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-cloud-controller-role -subjects: -- kind: ServiceAccount - name: kube-vip-cloud-controller - namespace: kube-system ---- -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: kube-vip-cloud-provider - namespace: kube-system -spec: - serviceName: kube-vip-cloud-provider - podManagementPolicy: OrderedReady - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - app: kube-vip - component: kube-vip-cloud-provider - template: - metadata: - labels: - app: kube-vip - component: kube-vip-cloud-provider - spec: - containers: - - command: - - /kube-vip-cloud-provider - - --leader-elect-resource-name=kube-vip-cloud-controller - image: kubevip/kube-vip-cloud-provider:latest - name: kube-vip-cloud-provider - imagePullPolicy: Always - resources: {} - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 - serviceAccountName: kube-vip-cloud-controller diff --git a/docs/manifests/kube-vip-arp.yaml b/docs/manifests/kube-vip-arp.yaml deleted file mode 100644 index f16dadcc..00000000 --- a/docs/manifests/kube-vip-arp.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-vip - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-role -rules: - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "create", "update", "list", "put"] - - apiGroups: [""] - resources: ["services"] - verbs: ["list","get","watch", "update"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:kube-vip-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-role -subjects: -- kind: ServiceAccount - name: kube-vip - namespace: kube-system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - creationTimestamp: null - labels: - app: kube-vip-workers - name: kube-vip-workers - namespace: kube-system -spec: - replicas: 3 - selector: - matchLabels: - app: kube-vip-workers - strategy: {} - template: - metadata: - creationTimestamp: null - labels: - app: kube-vip-workers - spec: - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchExpressions: - - key: "app" - operator: In - values: - - kube-vip-workers - topologyKey: "kubernetes.io/hostname" - containers: - - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - command: - - /kube-vip - - service - env: - - name: vip_interface - value: "ens160" - - name: vip_arp - value: "true" - - name: vip_loglevel - value: "5" - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - hostNetwork: true - serviceAccountName: kube-vip -status: {} diff --git a/docs/manifests/kube-vip-bgp.yaml b/docs/manifests/kube-vip-bgp.yaml deleted file mode 100644 index 53d5e738..00000000 --- a/docs/manifests/kube-vip-bgp.yaml +++ /dev/null @@ -1,90 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-vip - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-role -rules: - - apiGroups: [""] - resources: ["services"] - verbs: ["list","get","watch", "update"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:kube-vip-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-role -subjects: -- kind: ServiceAccount - name: kube-vip - namespace: kube-system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - creationTimestamp: null - labels: - app: kube-vip-workers - name: kube-vip-workers - namespace: kube-system -spec: - replicas: 3 - selector: - matchLabels: - app: kube-vip-workers - strategy: {} - template: - metadata: - creationTimestamp: null - labels: - app: kube-vip-workers - spec: - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchExpressions: - - key: "app" - operator: In - values: - - kube-vip-workers - topologyKey: "kubernetes.io/hostname" - containers: - - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - command: - - /kube-vip - - service - env: - - name: vip_interface - value: "lo" - - name: bgp_enable - value: "true" - - name: vip_loglevel - value: "5" - - name: bgp_routerinterface - value: "ens160" - - name: bgp_as - value: "64512" - - name: bgp_peeraddress - value: "192.168.0.1" - - name: bgp_peeras - value: "64512" - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - hostNetwork: true - serviceAccountName: kube-vip -status: {} \ No newline at end of file diff --git a/docs/manifests/kube-vip-em.yaml b/docs/manifests/kube-vip-em.yaml deleted file mode 100644 index 08ec4e21..00000000 --- a/docs/manifests/kube-vip-em.yaml +++ /dev/null @@ -1,91 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-vip - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-role -rules: - - apiGroups: [""] - resources: ["services", "services/status"] - verbs: ["list","get","watch", "update"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:kube-vip-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-role -subjects: -- kind: ServiceAccount - name: kube-vip - namespace: kube-system ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: lo - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: svc_enable - value: "true" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: vip_packet - value: "true" - - name: bgp_enable - value: "true" - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_TIME - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: packet-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 \ No newline at end of file diff --git a/docs/manifests/kube-vip.yaml b/docs/manifests/kube-vip.yaml deleted file mode 100644 index b76bf985..00000000 --- a/docs/manifests/kube-vip.yaml +++ /dev/null @@ -1,83 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vip ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: vip-role -rules: - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "create", "update", "list", "put"] - - apiGroups: [""] - resources: ["configmaps", "endpoints"] - verbs: ["watch", "get"] ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: vip-role-bind -subjects: - - kind: ServiceAccount - name: vip - apiGroup: "" -roleRef: - kind: Role - name: vip-role - apiGroup: "" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - creationTimestamp: null - labels: - app: kube-vip-cluster - name: kube-vip-cluster -spec: - replicas: 3 - selector: - matchLabels: - app: kube-vip-cluster - strategy: {} - template: - metadata: - creationTimestamp: null - labels: - app: kube-vip-cluster - spec: - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchExpressions: - - key: "app" - operator: In - values: - - kube-vip-cluster - topologyKey: "kubernetes.io/hostname" - containers: - - image: ghcr.io/kube-vip/kube-vip:0.3.7 - imagePullPolicy: Always - name: kube-vip - command: - - /kube-vip - - service - env: - - name: vip_interface - value: "ens192" - - name: vip_configmap - value: "plndr" - - name: vip_arp - value: "true" - - name: vip_loglevel - value: "5" - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - hostNetwork: true - serviceAccountName: vip -status: {} \ No newline at end of file diff --git a/docs/manifests/rbac.yaml b/docs/manifests/rbac.yaml deleted file mode 100644 index 0480d0ec..00000000 --- a/docs/manifests/rbac.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-vip - namespace: kube-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:kube-vip-role -rules: - - apiGroups: [""] - resources: ["services", "services/status", "nodes", "endpoints"] - verbs: ["list","get","watch", "update"] - - apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["list", "get", "watch", "update", "create"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: system:kube-vip-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:kube-vip-role -subjects: -- kind: ServiceAccount - name: kube-vip - namespace: kube-system diff --git a/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml deleted file mode 100644 index a5d14fd7..00000000 --- a/docs/manifests/v0.3.7/kube-vip-arp-ds.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.7/kube-vip-arp.yaml b/docs/manifests/v0.3.7/kube-vip-arp.yaml deleted file mode 100644 index 95ad7c18..00000000 --- a/docs/manifests/v0.3.7/kube-vip-arp.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml b/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml deleted file mode 100644 index 07fc64dc..00000000 --- a/docs/manifests/v0.3.7/kube-vip-bgp-ds.yaml +++ /dev/null @@ -1,74 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml deleted file mode 100644 index e4c7268b..00000000 --- a/docs/manifests/v0.3.7/kube-vip-bgp-em-ds.yaml +++ /dev/null @@ -1,84 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: metal-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.7/kube-vip-bgp.yaml b/docs/manifests/v0.3.7/kube-vip-bgp.yaml deleted file mode 100644 index cdc80317..00000000 --- a/docs/manifests/v0.3.7/kube-vip-bgp.yaml +++ /dev/null @@ -1,64 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: vip_interface - value: eth0 - - name: port - value: "6443" - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_startleader - value: "false" - - name: vip_addpeerstolb - value: "true" - - name: vip_localpeer - value: code:192.168.0.22:10000 - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.7 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml deleted file mode 100644 index 6707f2ab..00000000 --- a/docs/manifests/v0.3.9/kube-vip-arp-ds.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.9/kube-vip-arp.yaml b/docs/manifests/v0.3.9/kube-vip-arp.yaml deleted file mode 100644 index a89e85aa..00000000 --- a/docs/manifests/v0.3.9/kube-vip-arp.yaml +++ /dev/null @@ -1,61 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml deleted file mode 100644 index b630984f..00000000 --- a/docs/manifests/v0.3.9/kube-vip-bgp-ds.yaml +++ /dev/null @@ -1,74 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml deleted file mode 100644 index bb593623..00000000 --- a/docs/manifests/v0.3.9/kube-vip-bgp-em-ds.yaml +++ /dev/null @@ -1,84 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: metal-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.3.9/kube-vip-bgp.yaml b/docs/manifests/v0.3.9/kube-vip-bgp.yaml deleted file mode 100644 index b60149f8..00000000 --- a/docs/manifests/v0.3.9/kube-vip-bgp.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.3.9 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml b/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml deleted file mode 100644 index 7cadd030..00000000 --- a/docs/manifests/v0.4.0/kube-vip-arp-ds-lb.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: lb_enable - value: "true" - - name: lb_port - value: "6443" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml b/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml deleted file mode 100644 index 00b1e2b1..00000000 --- a/docs/manifests/v0.4.0/kube-vip-arp-ds.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml b/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml deleted file mode 100644 index 7e8d8596..00000000 --- a/docs/manifests/v0.4.0/kube-vip-arp-lb.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: lb_enable - value: "true" - - name: lb_port - value: "6443" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.0/kube-vip-arp.yaml b/docs/manifests/v0.4.0/kube-vip-arp.yaml deleted file mode 100644 index 6ce06718..00000000 --- a/docs/manifests/v0.4.0/kube-vip-arp.yaml +++ /dev/null @@ -1,61 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml b/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml deleted file mode 100644 index af9749a4..00000000 --- a/docs/manifests/v0.4.0/kube-vip-bgp-ds.yaml +++ /dev/null @@ -1,74 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml deleted file mode 100644 index 0472555c..00000000 --- a/docs/manifests/v0.4.0/kube-vip-bgp-em-ds.yaml +++ /dev/null @@ -1,84 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: metal-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.0/kube-vip-bgp.yaml b/docs/manifests/v0.4.0/kube-vip-bgp.yaml deleted file mode 100644 index c7a1a367..00000000 --- a/docs/manifests/v0.4.0/kube-vip-bgp.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.0 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - - SYS_TIME - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml b/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml deleted file mode 100644 index 91e6c7c8..00000000 --- a/docs/manifests/v0.4.1/kube-vip-arp-ds-lb.yaml +++ /dev/null @@ -1,70 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: lb_enable - value: "true" - - name: lb_port - value: "6443" - - name: lb_fwdmethod - value: local - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml b/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml deleted file mode 100644 index c37cf21a..00000000 --- a/docs/manifests/v0.4.1/kube-vip-arp-ds.yaml +++ /dev/null @@ -1,64 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml b/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml deleted file mode 100644 index 81746ccf..00000000 --- a/docs/manifests/v0.4.1/kube-vip-arp-lb.yaml +++ /dev/null @@ -1,66 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: lb_enable - value: "true" - - name: lb_port - value: "6443" - - name: lb_fwdmethod - value: local - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.1/kube-vip-arp.yaml b/docs/manifests/v0.4.1/kube-vip-arp.yaml deleted file mode 100644 index f3fe9c68..00000000 --- a/docs/manifests/v0.4.1/kube-vip-arp.yaml +++ /dev/null @@ -1,60 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "true" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml b/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml deleted file mode 100644 index c8bebaf4..00000000 --- a/docs/manifests/v0.4.1/kube-vip-bgp-ds.yaml +++ /dev/null @@ -1,73 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - hostNetwork: true - serviceAccountName: kube-vip - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml b/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml deleted file mode 100644 index 6b4eb5b1..00000000 --- a/docs/manifests/v0.4.1/kube-vip-bgp-em-ds.yaml +++ /dev/null @@ -1,83 +0,0 @@ -apiVersion: apps/v1 -kind: DaemonSet -metadata: - creationTimestamp: null - name: kube-vip-ds - namespace: kube-system -spec: - selector: - matchLabels: - name: kube-vip-ds - template: - metadata: - creationTimestamp: null - labels: - name: kube-vip-ds - spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: vip_leaderelection - value: "true" - - name: vip_leaseduration - value: "5" - - name: vip_renewdeadline - value: "3" - - name: vip_retryperiod - value: "1" - - name: provider_config - value: /etc/cloud-sa/cloud-sa.json - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - volumeMounts: - - mountPath: /etc/cloud-sa - name: cloud-sa-volume - readOnly: true - hostNetwork: true - serviceAccountName: kube-vip - volumes: - - name: cloud-sa-volume - secret: - secretName: metal-cloud-config - updateStrategy: {} -status: - currentNumberScheduled: 0 - desiredNumberScheduled: 0 - numberMisscheduled: 0 - numberReady: 0 - diff --git a/docs/manifests/v0.4.1/kube-vip-bgp.yaml b/docs/manifests/v0.4.1/kube-vip-bgp.yaml deleted file mode 100644 index 03b22bf5..00000000 --- a/docs/manifests/v0.4.1/kube-vip-bgp.yaml +++ /dev/null @@ -1,61 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: null - name: kube-vip - namespace: kube-system -spec: - containers: - - args: - - manager - env: - - name: vip_arp - value: "false" - - name: port - value: "6443" - - name: vip_interface - value: eth0 - - name: vip_cidr - value: "32" - - name: cp_enable - value: "true" - - name: cp_namespace - value: kube-system - - name: vip_ddns - value: "false" - - name: svc_enable - value: "true" - - name: bgp_enable - value: "true" - - name: bgp_routerid - - name: bgp_as - value: "65000" - - name: bgp_peeraddress - - name: bgp_peerpass - - name: bgp_peeras - value: "65000" - - name: vip_address - value: 192.168.0.1 - image: ghcr.io/kube-vip/kube-vip:v0.4.1 - imagePullPolicy: Always - name: kube-vip - resources: {} - securityContext: - capabilities: - add: - - NET_ADMIN - - NET_RAW - volumeMounts: - - mountPath: /etc/kubernetes/admin.conf - name: kubeconfig - hostAliases: - - hostnames: - - kubernetes - ip: 127.0.0.1 - hostNetwork: true - volumes: - - hostPath: - path: /etc/kubernetes/admin.conf - name: kubeconfig -status: {} - diff --git a/docs/publish.sh b/docs/publish.sh deleted file mode 100644 index ad5e6e45..00000000 --- a/docs/publish.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -echo Deploying updated documentation - -# Sleep for dramatic purposes! - -sleep 5 - -generate-md --layout github --input ./ --output /var/www/kube-vip/ diff --git a/docs/usage/EquinixMetal/index.md b/docs/usage/EquinixMetal/index.md deleted file mode 100644 index 4263d1cc..00000000 --- a/docs/usage/EquinixMetal/index.md +++ /dev/null @@ -1,163 +0,0 @@ -# Equinix Metal Overview (using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal)) - -## BGP with Equinix Metal - -When deploying Kubernetes with Equinix Metal with the `--controlplane` functionality we need to pre-populate the BGP configuration in order for the control plane to be advertised and work in a HA scenario. Luckily Equinix Metal provides the capability to "look up" the configuration details (for BGP) that we need in order to advertise our virtual IP (VIP) for HA functionality. We can either make use of the [Equinix Metal API](https://metal.equinix.com/developers/api/) or we can parse the [Equinix Metal Metadata service](https://metal.equinix.com/developers/docs/servers/metadata/). - -**Note** If this cluster will be making use of Equinix Metal for `type:LoadBalancer` (by using the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal)) then we will need to ensure that nodes are set to use an external cloud-provider. Before doing a `kubeadm init|join` ensure the kubelet has the correct flags by using the following command `echo KUBELET_EXTRA_ARGS=\"--cloud-provider=external\" > /etc/default/kubelet`. - -## Configure to use a container runtime - -### Get latest version - - We can parse the GitHub API to find the latest version (or we can set this manually) - -`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` - -or manually: - -`export KVVERSION=vx.x.x` - -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. - -### containerd -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` - -### Docker -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:KVVERSION"` - -## Creating HA clusters in Equinix Metal - -### Creating a manifest using the API - -We can enable `kube-vip` with the capability to discover the required configuration for BGP by passing the `--metal` flag and the API Key and our project ID. - -``` -export VIP= metal_EIP -export INTERFACE= -``` -where metal_EIP is the Elastic IP (EIP) address your requested via Metal's UI or API. For more informaiton on how to request a Metal's EIP, please see the following [Equinix Metal's EIP document](https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) - is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. - -``` -kube-vip manifest pod \ - --interface $INTERFACE\ - --vip $VIP \ - --controlplane \ - --services \ - --bgp \ - --metal \ - --metalKey xxxxxxx \ - --metalProjectID xxxxx | tee /etc/kubernetes/manifests/kube-vip.yaml -``` -where metalKey is your "personal API key" under "Personal Settings" of your Metal's portal, and MetalProjectID is your Metal's "Project ID" under "Project Settings" - -### Creating a manifest using the metadata - -We can parse the metadata, *however* it requires that the tools `curl` and `jq` are installed. - -``` -kube-vip manifest pod \ - --interface $INTERFACE\ - --vip $VIP \ - --controlplane \ - --services \ - --bgp \ - --peerAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].peer_as') \ - --peerAddress $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].peer_ips[0]') \ - --localAS $(curl https://metadata.platformequinix.com/metadata | jq '.bgp_neighbors[0].customer_as') \ - --bgpRouterID $(curl https://metadata.platformequinix.com/metadata | jq -r '.bgp_neighbors[0].customer_ip') | sudo tee /etc/kubernetes/manifests/vip.yaml -``` - -## Load Balancing servies on Equinix Metal - -Below are two examples for running `type:LoadBalancer` services on worker nodes only and will create a daemonset that will run `kube-vip`. - -**NOTE** This use-case requires the [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) to be installed prior to the kube-vip setup and that the cluster/kubelet is configured to use an "external" cloud provider. - -``` -export INTERFACE= -``` -where is the interface you announce your VIP from via BGP. By default it's lo:0 in Equinix Metal. - -### Using Annotations - -This is important as the CCM will apply the BGP configuration to the [node annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) making it easy for `kube-vip` to find the networking configuration it needs to expose load balancer addresses. The `--annotations metal.equinix.com` will cause kube-vip to "watch" the annotations of the worker node that it is running on, once all of the configuarion has been applied by the CCM then the `kube-vip` pod is ready to advertise BGP addresses for the service. - -``` -kube-vip manifest daemonset \ - --interface $INTERFACE \ - --services \ - --bgp \ - --annotations metal.equinix.com \ - --inCluster | k apply -f - -``` - -### Using the existing CCM secret - -Alternatively it is possible to create a daemonset that will use the existing CCM secret to do an API lookup, this will allow for discovering the networking configuration needed to advertise loadbalancer addresses through BGP. - -``` -kube-vip manifest daemonset --interface $INTERFACE \ ---services \ ---inCluster \ ---bgp \ ---metal \ ---provider-config /etc/cloud-sa/cloud-sa.json | kubectl apply -f - -``` - -### Expose with [Equinix Metal CCM](https://github.com/equinix/cloud-provider-equinix-metal) - -Follow the [Equinix Metal's Elastic IP (EIP) document](https://metal.equinix.com/developers/docs/networking/elastic-ips/#elastic-ip-addresses) either through the API, CLI or through the UI, to create a public IPv4 EIP address, for example (145.75.75.1) and this is the address you can expose through BGP as the service loadbalancer. - -``` -# metal ip request -p xxx-bbb-ccc -f ams1 -q 1 -t public_ipv4 -+-------+---------------+--------+----------------------+ -| ID | ADDRESS | PUBLIC | CREATED | -+-------+---------------+--------+----------------------+ -| xxxxx | 147.75.75.1 | true | 2020-11-10T15:57:39Z | -+-------+---------------+--------+----------------------+ - -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=147.75.75.1 -``` - -## Troubleshooting - -If `kube-vip` has been sat waiting for a long time then you may need to investigate that the annotations have been applied correctly by doing running the `describe` on the node. -As of Equinix Metal's CCM v3.3.0, the annotations format was changed. This means, you should expect either of the following: - -1. Equinix Metal's CCM v3.3.0 onwards: - -``` -kubectl describe node k8s.bgp02 -... -Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock - node.alpha.kubernetes.io/ttl: 0 - metal.equinix.com/bgp-peers-0-node-asn: 65000 - metal.equinix.com/bgp-peers-0-peer-asn: 65530 - metal.equinix.com/bgp-peers-0-peer-ip: x.x.x.x - metal.equinix.com/bgp-peers-0-src-ip: x.x.x.x -``` - -2. Equinix Metal's CCM before v3.0.0: - -``` -kubectl describe node k8s.bgp02 -... -Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock - node.alpha.kubernetes.io/ttl: 0 - metal.equinix.com/node-asn: 65000 - metal.equinix.com/peer-asn: 65530 - metal.equinix.com/peer-ip: x.x.x.x - metal.equinix.com/src-ip: x.x.x.x -``` - -If there are errors regarding `169.254.255.1` or `169.254.255.2` in the `kube-vip` logs then the routes to the ToR switches that provide BGP peering may by missing from the nodes. They can be replaced with the below command: - -``` -GATEWAY_IP=$(curl https://metadata.platformequinix.com/metadata | jq -r ".network.addresses[] | select(.public == false) | .gateway") -ip route add 169.254.255.1 via $GATEWAY_IP -ip route add 169.254.255.2 via $GATEWAY_IP -``` - -Additionally examining the logs of the Equinix Metal's CCM may reveal why the node is not yet ready. diff --git a/docs/usage/k3s/index.md b/docs/usage/k3s/index.md deleted file mode 100644 index 280c2178..00000000 --- a/docs/usage/k3s/index.md +++ /dev/null @@ -1,53 +0,0 @@ -# K3s Overview - -`kube-vip` works on [K3s environments](https://k3s.io/) similar to most others with the exception of how it gets deployed. Because K3s is able to bootstrap a single server (control plane node) without the availability of the load balancer fronting it, `kube-vip` can be installed as a DaemonSet. - -## Prerequisites (on Equinix Metal) - -In order to make ARP work on Equinix Metal, follow the [metal-gateway](https://metal.equinix.com/developers/docs/networking/metal-gateway/) guide to have public VLAN subnet which can be used for the load balancer IP. - -## Clean Environment - -This step is optional but recommended if a K3s installation previously existed. - -``` -rm -rf /var/lib/rancher /etc/rancher ~/.kube/*; \ -ip addr flush dev lo; \ -ip addr add 127.0.0.1/8 dev lo; -``` - -## Step 1: Create Manifests Folder - -K3s has an optional manifests directory that will be searched to [auto-deploy](https://rancher.com/docs/k3s/latest/en/advanced/#auto-deploying-manifests) any manifests found within. Create this directory first in order to later place the `kube-vip` resources inside. - -``` -mkdir -p /var/lib/rancher/k3s/server/manifests/ -``` - -## Step 2: Upload Kube-Vip RBAC Manifest - -As `kube-vip` runs as a DaemonSet under K3s and not a static Pod, we will need to ensure that the required permissions exist for it to communicate with the API server. RBAC resources are needed to ensure a ServiceAccount exists with those permissions and bound appropriately. - -Get the RBAC manifest and place in the auto-deploy directory: - -``` -curl https://kube-vip.io/manifests/rbac.yaml > /var/lib/rancher/k3s/server/manifests/kube-vip-rbac.yaml -``` - -## Step 3: Generate a Kube-Vip DaemonSet Manifest - -Refer to the [DaemonSet manifest generation documentation](/docs/install_daemonset/index.md#generating-a-manifest) for the process to complete this step. - -Either store this generated manifest separately in the `/var/lib/rancher/k3s/server/manifests/` directory, or append to the existing RBAC manifest called `kube-vip-rbac.yaml`. As a general best practice, it is a cleaner approach to place all related resources into a single YAML file. - -> Note: Remember to include YAML document delimiters (`---`) when composing multiple documents. - -## Step 4: Install a HA K3s Cluster - -There are multiple ways to install K3s including `[k3sup](https://k3sup.dev/)` or [running the binary](https://rancher.com/docs/k3s/latest/en/quick-start/) locally. Whichever method you choose, the `--tls-san` flag must be passed with the same IP when generating the `kube-vip` DaemonSet manifest when installing the first server (control plane) instance. This is so that K3s generates an API server certificate with the `kube-vip` virtual IP address. - -Once the cluster is installed, you should be able to edit the `kubeconfig` file generated from the process and use the `kube-vip` VIP address to access the control plane. - -## Step 5: Service Load Balancing - -If wanting to use the `kube-vip` [cloud controller](/docs/usage/cloud-provider/), pass the `--disable servicelb` flag so K3s will not attempt to render Kubernetes Service resources of type `LoadBalancer`. If building with `k3sup`, the flag should be given as an argument to the `--k3s-extra-args` flag itself: `--k3s-extra-args "--disable servicelb"`. To install the `kube-vip` cloud controller, follow the additional steps in the [cloud controller guide](/docs/usage/cloud-provider/#install-the-kube-vip-cloud-provider). diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md deleted file mode 100644 index f8edd13e..00000000 --- a/docs/usage/kind/index.md +++ /dev/null @@ -1,86 +0,0 @@ -# Kube-vip on KIND - -## Deploying KIND - -The documentation for KIND is fantastic and its [quick start](https://kind.sigs.k8s.io/docs/user/quick-start/) guide will have you up and running in no time. - -## Create RBAC settings - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` - -## Find Address Pool for Kube-Vip - -We will need to find addresses that can be used by Kube-Vip: - -``` -docker network inspect kind -f '{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}' -``` - -This will return a CIDR range such as `172.18.0.0/16` and from here we can select a range. - -## Deploy the Kube-Vip Cloud Controller - -``` -kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml -``` - -## Add our Address range - -``` -kubectl create configmap --namespace kube-system kubevip --from-literal range-global=172.18.100.10-172.18.100.30 -``` - -## Install kube-vip - -### Create the RBAC settings - -Since `kube-vip` as a DaemonSet runs as a regular resource instead of a static Pod, it still needs the correct access to be able to watch Kubernetes Services and other objects. In order to do this, RBAC resources must be created which include a ServiceAccount, ClusterRole, and ClusterRoleBinding and can be applied this with the command: - -``` -kubectl apply -f https://kube-vip.io/manifests/rbac.yaml -``` - -### Get latest version - -We can parse the GitHub API to find the latest version (or we can set this manually) - -`KVVERSION=$(curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name")` - -or manually: - -`export KVVERSION=vx.x.x` - -The easiest method to generate a manifest is using the container itself, below will create an alias for different container runtimes. - -### containerd - -`alias kube-vip="ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip /kube-vip"` - -### Docker - -`alias kube-vip="docker run --network host --rm ghcr.io/kube-vip/kube-vip:$KVVERSION"` - -## Deploy Kube-vip as a DaemonSet - -``` -kube-vip manifest daemonset --services --inCluster --arp --interface eth0 | kubectl apply -f - -``` - -## Test - -``` -kubectl apply -f https://k8s.io/examples/application/deployment.yaml -``` - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx -``` - -``` -kubectl get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 74m -nginx LoadBalancer 10.96.196.235 172.18.100.11 80:31236/TCP 6s -``` diff --git a/docs/usage/on-prem/index.md b/docs/usage/on-prem/index.md deleted file mode 100644 index 18dbcc34..00000000 --- a/docs/usage/on-prem/index.md +++ /dev/null @@ -1,203 +0,0 @@ -# Kube-Vip On-Prem - -We've designed `kube-vip` to be as decoupled or agnostic from other components that may exist within a Kubernetes cluster as possible. This has lead to `kube-vip` having a very simplistic but robust approach to advertising Kubernetes Services to the outside world and marking these Services as ready to use. - -## Cloud Controller Manager - -`kube-vip` isn't coupled to anything other than the Kubernetes API and will only act upon an existing Kubernetes primitive (in this case the object of type `Service`). This makes it easy for existing [cloud controller managers (CCMs)](https://kubernetes.io/docs/concepts/architecture/cloud-controller/) to simply apply their logic to services of type LoadBalancer and leave `kube-vip` to take the next steps to advertise these load balancers to the outside world. - -## Using the Kube-Vip Cloud Provider - -The `kube-vip` cloud provider can be used to populate an IP address for Services of type `LoadBalancer` similar to what public cloud providers allow through a Kubernetes CCM. The below instructions *should just work* on Kubernetes regardless of the architecture (a Linux OS being the only requirement) and will install the latest components. - -## Install the Kube-Vip Cloud Provider - -The `kube-vip` cloud provider can be installed from the latest release in the `main` branch by using the following command: - -``` -kubectl apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml -``` - -## Create a global CIDR or IP Range - -In order for `kube-vip` to set an IP address for a Service of type `LoadBalancer`, it needs to have an availability of IP address to assign. This information is stored in a Kubernetes ConfigMap to which `kube-vip` has access. You control the scope of the IP allocations with the `key` within the ConfigMap. Either CIDR blocks or IP ranges may be specified and scoped either globally (cluster-side) or per-Namespace. - -To allow a global (cluster-wide) CIDR block which `kube-vip` can use to allocate an IP to Services of type `LoadBalancer` in any Namespace, create a ConfigMap named `kubevip` with the key `cidr-global` and value equal to a CIDR block available in your environment. For example, the below command creates a global CIDR with value `192.168.0.220/29` from which `kube-vip` will allocate IP addresses. - -``` -kubectl create configmap -n kube-system kubevip --from-literal cidr-global=192.168.0.220/29 -``` - -To use a global range instead, create the key `range-global` with the value set to a valid range of IP addresses. For example, the below command creates a global range using the pool `192.168.1.220-192.168.1.230`. - -``` -kubectl create configmap -n kube-system kubevip --from-literal range-global=192.168.1.220-192.168.1.230 -``` - -Creating services of type `LoadBalancer` in any Namespace will now take addresses from one of the global pools defined in the ConfigMap unless a Namespace-specific pool is created. - -### The Kube-Vip Cloud Provider ConfigMap - -To manage the IP address ranges for Services of type `LoadBalancer`, the `kube-vip-cloud-provider` uses a ConfigMap held in the `kube-system` Namespace. IP addresses can be configured using one or multiple formats: - -- CIDR blocks -- IP ranges [start address - end address] -- Multiple pools by CIDR per Namespace -- Multiple IP ranges per Namespace (handles overlapping ranges) -- Setting of static addresses through service.metadata.annotations `kube-vip.io/loadbalancerIPs` -- Setting of static addresses through --load-balancer-ip=x.x.x.x (`kubectl expose` command) - -To control which IP address range is used for which Service, the following rules are applied: - -- Global address pools (`cidr-global` or `range-global`) are available for use by *any* Service in *any* Namespace -- Namespace specific address pools (`cidr-` or `range-`) are *only* available for use by a Service in the *specific* Namespace -- Static IP addresses can be applied to a Service of type `LoadBalancer` using the `spec.loadBalancerIP` field, even outside of the assigned ranges - -Example Configmap: - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: kubevip - namespace: kube-system -data: - cidr-default: 192.168.0.200/29 # CIDR-based IP range for use in the default Namespace - range-development: 192.168.0.210-192.168.0.219 # Range-based IP range for use in the development Namespace - cidr-finance: 192.168.0.220/29,192.168.0.230/29 # Multiple CIDR-based ranges for use in the finance Namespace - cidr-global: 192.168.0.240/29 # CIDR-based range which can be used in any Namespace -``` - -### Expose a Service - -We can now expose a Service and once the cloud provider has provided an address, `kube-vip` will start to advertise that address to the outside world as shown below: - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx -``` - -or via a Service YAML definition: - -``` -apiVersion: v1 -kind: Service -metadata: - name: nginx -spec: - ports: - - name: http - port: 80 - protocol: TCP - selector: - app: nginx - type: LoadBalancer - ``` - -We can also expose a specific address by specifying it imperatively in the Service definition: - - -``` -apiVersion: v1 -kind: Service -metadata: - annotations: - "kube-vip.io/loadbalancerIPs": "1.1.1.1" - name: nginx -spec: - ports: - - name: http - port: 80 - protocol: TCP - selector: - app: nginx - type: LoadBalancer -``` - -Or set it through command line. - -``` -kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx --load-balancer-ip=1.1.1.1 -``` - -Since k8s 1.24, loadbalancerIP field [is deprecated](https://github.com/kubernetes/kubernetes/pull/107235). It's recommended to use the annotations instead of command line or `service.spec.loadBalancerIP` to specify the ip. - -### Using DHCP for Load Balancers (experimental) - -With `kube-vip` > 0.2.1, it is possible to use the local network DHCP server to provide `kube-vip` with a load balancer address that can be used to access a Kubernetes service on the network. - -In order to do this, we need to signify to `kube-vip` and the cloud provider that we don't need one of their managed addresses. We do this by explicitly exposing a Service on the address `0.0.0.0`. When `kube-vip` sees a Service on this address, it will create a `macvlan` interface on the host and request a DHCP address. Once this address is provided, it will assign it as the `LoadBalancer` IP and update the Kubernetes Service. - -``` -$ kubectl expose deployment nginx-deployment --port=80 --type=LoadBalancer --name=nginx-dhcp --load-balancer-ip=0.0.0.0; kubectl get svc -service/nginx-dhcp exposed -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 0.0.0.0 80:31184/TCP 0s - -{ ... a second or so later ... } - -$ kubectl get svc -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 17m -nginx-dhcp LoadBalancer 10.97.150.208 192.168.0.155 80:31184/TCP 3s -``` - -You can also specify a hostname used for the DHCP lease by adding an annotation to your service. - -``` -apiVersion: v1 -kind: Service -metadata: - name: nginx-dhcp - annotations: - kube-vip.io/loadbalancerHostname: mydhcp-test -spec: - loadBalancerIP: 0.0.0.0 - ports: - - name: http - port: 80 - protocol: TCP - targetPort: 80 - selector: - app: hello-world - type: LoadBalancer -``` - -### Using UPnP to expose a Service to the outside world - -With `kube-vip` > 0.2.1, it is possible to expose a Service of type `LoadBalancer` on a specific port to the Internet by using UPnP (on a supported gateway). - -Most simple networks look something like the following: - -`<----- ----> Internet` - -Using UPnP we can create a matching port on the `` allowing your Service to be exposed to the Internet. - -#### Enable UPnP - -Add the following to the `kube-vip` `env:` section of either the static Pod or DaemonSet for `kube-vip`, and the rest should be completely automated. - -**Note** some environments may require (Unifi) `Secure mode` being `disabled` (this allows a host with a different address to register a port). - -``` -- name: enableUPNP - value: "true" -``` - -#### Exposing a Service - -To expose a port successfully, we'll need to change the command slightly: - -`--target-port=80` the port of the application in the pods (HTT/NGINX) -`--port=32380` the port the Service will be exposed on (and what you should connect to in order to receive traffic from the Service) - -`kubectl expose deployment plunder-nginx --port=32380 --target-port=80 --type=LoadBalancer --namespace plunder` - -The above example should expose a port on your external (Internet facing) address that can be tested externally with: - -``` -$ curl externalIP:32380 - - -... -``` From 0212e78dc6945ea2c0ee532cf43401a21da46920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:45:25 +0000 Subject: [PATCH 493/542] Bump k8s.io/apimachinery from 0.28.3 to 0.29.0 Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.28.3 to 0.29.0. - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.28.3...v0.29.0) --- updated-dependencies: - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 12 ++++++------ go.sum | 21 ++++++++++----------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index af2f9f6c..ee1166dd 100644 --- a/go.mod +++ b/go.mod @@ -28,11 +28,11 @@ require ( golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.15.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - k8s.io/api v0.28.4 - k8s.io/apimachinery v0.28.4 gopkg.in/yaml.v2 v2.4.0 + k8s.io/api v0.28.4 + k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.28.3 - k8s.io/klog/v2 v2.100.1 + k8s.io/klog/v2 v2.110.1 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.4.0 ) @@ -115,8 +115,8 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index b65a0eb1..a21d408c 100644 --- a/go.sum +++ b/go.sum @@ -98,7 +98,6 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -768,16 +767,16 @@ honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= +k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= +k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= @@ -785,8 +784,8 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From ec1288074e4c3e34406159cc0069311096773470 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:50:18 +0000 Subject: [PATCH 494/542] Bump go.etcd.io/etcd/api/v3 from 3.5.10 to 3.5.11 Bumps [go.etcd.io/etcd/api/v3](https://github.com/etcd-io/etcd) from 3.5.10 to 3.5.11. - [Release notes](https://github.com/etcd-io/etcd/releases) - [Commits](https://github.com/etcd-io/etcd/compare/v3.5.10...v3.5.11) --- updated-dependencies: - dependency-name: go.etcd.io/etcd/api/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index ee1166dd..eed54724 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 - go.etcd.io/etcd/api/v3 v3.5.10 + go.etcd.io/etcd/api/v3 v3.5.11 go.etcd.io/etcd/client/pkg/v3 v3.5.10 go.etcd.io/etcd/client/v3 v3.5.10 go.uber.org/zap v1.26.0 @@ -99,7 +99,7 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -107,10 +107,10 @@ require ( golang.org/x/tools v0.14.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index a21d408c..ff29f8b1 100644 --- a/go.sum +++ b/go.sum @@ -362,8 +362,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E= +go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= @@ -482,8 +482,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -699,12 +699,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -721,8 +721,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From f82b4a08b48c77b50957ebaba7e82ed3f7c561d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:50:51 +0000 Subject: [PATCH 495/542] Bump go.etcd.io/etcd/client/v3 from 3.5.10 to 3.5.11 Bumps [go.etcd.io/etcd/client/v3](https://github.com/etcd-io/etcd) from 3.5.10 to 3.5.11. - [Release notes](https://github.com/etcd-io/etcd/releases) - [Commits](https://github.com/etcd-io/etcd/compare/v3.5.10...v3.5.11) --- updated-dependencies: - dependency-name: go.etcd.io/etcd/client/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index ee1166dd..d4fe6c5c 100644 --- a/go.mod +++ b/go.mod @@ -21,9 +21,9 @@ require ( github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/vishvananda/netlink v1.2.1-beta.2 - go.etcd.io/etcd/api/v3 v3.5.10 - go.etcd.io/etcd/client/pkg/v3 v3.5.10 - go.etcd.io/etcd/client/v3 v3.5.10 + go.etcd.io/etcd/api/v3 v3.5.11 + go.etcd.io/etcd/client/pkg/v3 v3.5.11 + go.etcd.io/etcd/client/v3 v3.5.11 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 golang.org/x/sys v0.15.0 @@ -99,7 +99,7 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -107,10 +107,10 @@ require ( golang.org/x/tools v0.14.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index a21d408c..72031e8f 100644 --- a/go.sum +++ b/go.sum @@ -362,12 +362,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= -go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= -go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= -go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.etcd.io/etcd/api/v3 v3.5.11 h1:B54KwXbWDHyD3XYAwprxNzTe7vlhR69LuBgZnMVvS7E= +go.etcd.io/etcd/api/v3 v3.5.11/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.11 h1:bT2xVspdiCj2910T0V+/KHcVKjkUrCZVtk8J2JF2z1A= +go.etcd.io/etcd/client/pkg/v3 v3.5.11/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v3 v3.5.11 h1:ajWtgoNSZJ1gmS8k+icvPtqsqEav+iUorF7b0qozgUU= +go.etcd.io/etcd/client/v3 v3.5.11/go.mod h1:a6xQUEqFJ8vztO1agJh/KQKOMfFI8og52ZconzcDJwE= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -482,8 +482,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -699,12 +699,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -721,8 +721,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 52776f4a753cc05f4cbea4f97f1123dc491fe9b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 13:51:16 +0000 Subject: [PATCH 496/542] Bump k8s.io/client-go from 0.28.3 to 0.29.0 Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.28.3 to 0.29.0. - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.28.3...v0.29.0) --- updated-dependencies: - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index ee1166dd..a2b7b48f 100644 --- a/go.mod +++ b/go.mod @@ -29,9 +29,9 @@ require ( golang.org/x/sys v0.15.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.28.4 + k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 - k8s.io/client-go v0.28.3 + k8s.io/client-go v0.29.0 k8s.io/klog/v2 v2.110.1 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.4.0 @@ -47,7 +47,7 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/eapache/channels v1.1.0 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect diff --git a/go.sum b/go.sum index a21d408c..153daed5 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4 github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -765,12 +765,12 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= -k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= -k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= +k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= +k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= From 66c86e995bf45fb9852ea1701c8d19443dbd9b34 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 3 Jan 2024 13:52:13 +0000 Subject: [PATCH 497/542] fixes go modules Signed-off-by: Dan Finneran --- go.mod | 4 +++- go.sum | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ee1166dd..39b28d4c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/kube-vip/kube-vip -go 1.19 +go 1.21 + +toolchain go1.21.3 require ( github.com/cloudflare/ipvs v0.9.1 diff --git a/go.sum b/go.sum index a21d408c..5f806218 100644 --- a/go.sum +++ b/go.sum @@ -87,12 +87,14 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -109,6 +111,7 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -117,6 +120,7 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -191,6 +195,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -232,6 +237,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -272,6 +278,7 @@ github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5A github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -316,6 +323,7 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -375,6 +383,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -427,6 +436,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -756,6 +766,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From a342c75a65d894943c88ca14c34e81c2fdab4fc9 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 3 Jan 2024 13:56:43 +0000 Subject: [PATCH 498/542] Workflow update for go 1.21 Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3aa75088..afe8d203 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,7 +3,7 @@ on: push: pull_request: env: - GO_VERSION: "1.20" + GO_VERSION: "1.21" jobs: validation: runs-on: ubuntu-latest From e6d56f7eb00c9ce303a196d914ecfd7e4291dc84 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Wed, 3 Jan 2024 14:07:53 +0000 Subject: [PATCH 499/542] Update codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d40b2915..0ce93ae6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,12 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version-file: go.mod + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 From 03467dd085dda9598bab6df2c7bfad39a359de99 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 3 Jan 2024 14:26:47 +0000 Subject: [PATCH 500/542] More fixes Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 20 ++++++++++---------- .github/workflows/codeql-analysis.yml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index afe8d203..1c306c31 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,10 +15,10 @@ jobs: run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go ${{ env.GO_VERSION }} + - name: Install Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: All checks run: make check unit-tests: @@ -27,10 +27,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go ${{ env.GO_VERSION }} + - name: Install Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Run tests run: make unit-tests integration-tests: @@ -39,10 +39,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go ${{ env.GO_VERSION }} + - name: Install Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Run tests run: make integration-tests e2e-tests: @@ -51,10 +51,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go ${{ env.GO_VERSION }} + - name: Install Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Build image locally run: make dockerx86Local - name: Run tests @@ -65,10 +65,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Go ${{ env.GO_VERSION }} + - name: Install Go uses: actions/setup-go@v5 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Build image with iptables run: make dockerx86ActionIPTables - name: Run tests diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0ce93ae6..dca0ef6d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,7 +41,7 @@ jobs: uses: actions/checkout@v4 - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version-file: go.mod From 98d6579d9da64c93e46707680a64b589f8f7a992 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Wed, 3 Jan 2024 17:53:38 +0000 Subject: [PATCH 501/542] fixes to the new ipvs import Signed-off-by: Dan Finneran --- go.mod | 7 ++++++ go.sum | 16 ++++++++++++++ pkg/loadbalancer/ipvs.go | 12 +++++----- pkg/loadbalancer/ipvs_test.go | 41 +++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 pkg/loadbalancer/ipvs_test.go diff --git a/go.mod b/go.mod index f4f1ced9..ddc074ff 100644 --- a/go.mod +++ b/go.mod @@ -90,6 +90,7 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -103,6 +104,7 @@ require ( github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.17.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.4.0 // indirect @@ -122,6 +124,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + modernc.org/cc/v4 v4.1.0 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/opt v0.1.3 // indirect + modernc.org/strutil v1.1.3 // indirect + modernc.org/token v1.0.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index e02f838c..b5e23324 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,7 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= @@ -300,6 +301,7 @@ github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CT github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -323,6 +325,8 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= @@ -796,6 +800,18 @@ k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/A k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/cc/v4 v4.1.0 h1:PlApAKux1sNvreOGs1Hr04FFz35QmAWoa98YFjcdH94= +modernc.org/cc/v4 v4.1.0/go.mod h1:T6KFXc8WI0m9k6IOHuRe9+vB+Pb/AaV8BMZoVqHLm1I= +modernc.org/ccorpus2 v1.1.0 h1:r/Z2+wOD5Tmcs1AMVXJgslE9HgRRROVWo0qUox1kJIo= +modernc.org/ccorpus2 v1.1.0/go.mod h1:Wifvo4Q/qS/h1aRoC2TffcHsnxwTikmi1AuLANuucJQ= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/loadbalancer/ipvs.go b/pkg/loadbalancer/ipvs.go index b0b15cb6..af93b2e2 100644 --- a/pkg/loadbalancer/ipvs.go +++ b/pkg/loadbalancer/ipvs.go @@ -3,6 +3,7 @@ package loadbalancer import ( "fmt" "net" + "net/netip" "strings" "github.com/cloudflare/ipvs" @@ -66,7 +67,7 @@ func NewIPVSLB(address string, port int, forwardingMethod string) (*IPVSLoadBala var m ipvs.ForwardType switch strings.ToLower(forwardingMethod) { case "masquerade": - m = ipvs.Masquarade + m = ipvs.Masquerade case "local": m = ipvs.Local case "tunnel": @@ -178,13 +179,14 @@ func (lb *IPVSLoadBalancer) RemoveBackend(address string, port int) error { } func (lb *IPVSLoadBalancer) addrString() string { - return lb.loadBalancerService.Address.Net(lb.loadBalancerService.Family).String() + return lb.loadBalancerService.Address.String() } -func ipAndFamily(address string) (ipvs.IP, ipvs.AddressFamily) { +func ipAndFamily(address string) (netip.Addr, ipvs.AddressFamily) { + ipAddr := net.ParseIP(address) if ipAddr.To4() == nil { - return ipvs.NewIP(ipAddr), ipvs.INET6 + return netip.AddrFrom16([16]byte(ipAddr.To16())), ipvs.INET6 } - return ipvs.NewIP(ipAddr), ipvs.INET + return netip.AddrFrom4([4]byte(ipAddr.To4())), ipvs.INET } diff --git a/pkg/loadbalancer/ipvs_test.go b/pkg/loadbalancer/ipvs_test.go new file mode 100644 index 00000000..6271aa88 --- /dev/null +++ b/pkg/loadbalancer/ipvs_test.go @@ -0,0 +1,41 @@ +package loadbalancer + +import ( + "net/netip" + "reflect" + "testing" + + "github.com/cloudflare/ipvs" +) + +func Test_ipAndFamily(t *testing.T) { + type args struct { + address string + } + tests := []struct { + name string + args args + want netip.Addr + want1 ipvs.AddressFamily + }{ + { + name: "IPv4", + args: args{ + address: "192.168.0.20", + }, + want: netip.AddrFrom4([4]byte{192, 168, 0, 20}), + want1: ipvs.INET, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := ipAndFamily(tt.args.address) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ipAndFamily() got = %v, want %v", got, tt.want) + } + if !reflect.DeepEqual(got1, tt.want1) { + t.Errorf("ipAndFamily() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} From 7901b8d50ce1a02fcaf3685e6a20c4ccf6f2f2cf Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 5 Jan 2024 14:00:49 +0000 Subject: [PATCH 502/542] Bumps the Makefile for a new release Signed-off-by: Dan Finneran --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24579904..6e3803a9 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL := $(TARGET) # These will be provided to the target -VERSION := v0.6.4 +VERSION := v0.7.0 BUILD := `git rev-parse HEAD` From d29b8d1bd8062f385755daf9d09d1ceddf92b8ee Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Fri, 5 Jan 2024 16:00:40 +0000 Subject: [PATCH 503/542] Allows a configurable path to the kubernetes config Signed-off-by: Dan Finneran --- cmd/kube-vip.go | 4 ++++ pkg/kubevip/config_environment.go | 5 +++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_generator.go | 2 +- pkg/kubevip/config_types.go | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index fb12449e..183b5d1c 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -148,6 +148,10 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.Etcd.ClientKeyFile, "etcdKey", "", "Identify secure client using this TLS key file") kubeVipCmd.PersistentFlags().StringSliceVar(&initConfig.Etcd.Endpoints, "etcdEndpoints", nil, "Etcd member endpoints") + // Kubernetes client specific flags + + kubeVipCmd.PersistentFlags().StringVar(&initConfig.K8sConfigFile, "k8sConfigPath", "/etc/kubernetes/admin.conf", "Path to the configuration file used with the Kubernetes client") + kubeVipCmd.AddCommand(kubeKubeadm) kubeVipCmd.AddCommand(kubeManifest) kubeVipCmd.AddCommand(kubeVipManager) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 621d9c3d..013e82ea 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -519,5 +519,10 @@ func ParseEnvironment(c *Config) error { c.EgressWithNftables = b } + // check to see if we're using a specific path to the Kubernetes config file + env = os.Getenv(k8sConfigFile) + if env != "" { + c.K8sConfigFile = env + } return nil } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 2d8d93f8..09675d31 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -183,4 +183,7 @@ const ( // vipConfigMap defines the configmap that kube-vip will watch for service definitions // vipConfigMap = "vip_configmap" + + //k8sConfigFile defines the path to the configfile used to speak with the API server + k8sConfigFile = "k8s_config_file" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 3718dd21..6415064e 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -523,7 +523,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod Name: "kubeconfig", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ - Path: "/etc/kubernetes/admin.conf", + Path: c.K8sConfigFile, }, }, } diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index e04ff360..2bc2edee 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -154,6 +154,9 @@ type Config struct { // ServicesLeaseName, this will set the lease name for services leader in arp mode ServicesLeaseName string `yaml:"servicesLeaseName"` + + // K8sConfigFile, this is the path to the config file used to speak with the API server + K8sConfigFile string `yaml:"k8sConfigFile"` } // KubernetesLeaderElection defines all of the settings for Kubernetes KubernetesLeaderElection From 047fe8f44479d7b2d20c783b3e0adc99bc7cdbcd Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 6 Jan 2024 16:16:21 +0000 Subject: [PATCH 504/542] Additional tests Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 4 +++- Makefile | 3 +++ testing/e2e/e2e_test.go | 11 ++++++++--- testing/e2e/kube-vip.yaml.tmpl | 2 +- testing/e2e/template.go | 1 + 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c306c31..0f083e71 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -57,8 +57,10 @@ jobs: go-version-file: go.mod - name: Build image locally run: make dockerx86Local - - name: Run tests + - name: Run Control plane tests run: make e2e-tests + - name: Run Control plane tests v1.29.0 onwards + run: make e2e-tests129 service-e2e-tests: runs-on: ubuntu-latest name: E2E service tests diff --git a/Makefile b/Makefile index 6e3803a9..77b51f4d 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,9 @@ integration-tests: e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd +e2e-tests129: + CONFIG_PATH=/etc/kubernetes/super-admin.conf K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd + service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 532d5ebd..7fe9dc80 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -35,6 +35,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { logger log.Logger imagePath string k8sImagePath string + configPath string kubeVIPManifestTemplate *template.Template clusterName string tempDirPath string @@ -44,9 +45,12 @@ var _ = Describe("kube-vip broadcast neighbor", func() { klog.SetOutput(GinkgoWriter) logger = e2e.TestLogger{} - imagePath = os.Getenv("E2E_IMAGE_PATH") - k8sImagePath = os.Getenv("K8S_IMAGE_PATH") - + imagePath = os.Getenv("E2E_IMAGE_PATH") // Path to kube-vip image + configPath = os.Getenv("CONFIG_PATH") // path to the api server config + k8sImagePath = os.Getenv("K8S_IMAGE_PATH") // path to the kubernetes image (version for kind) + if configPath == "" { + configPath = "/etc/kubernetes/admin.conf" + } curDir, err := os.Getwd() Expect(err).NotTo(HaveOccurred()) templatePath := filepath.Join(curDir, "kube-vip.yaml.tmpl") @@ -118,6 +122,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ ControlPlaneVIP: ipv4VIP, ImagePath: imagePath, + ConfigPath: configPath, })).To(Succeed()) }) diff --git a/testing/e2e/kube-vip.yaml.tmpl b/testing/e2e/kube-vip.yaml.tmpl index c5620914..dba27284 100644 --- a/testing/e2e/kube-vip.yaml.tmpl +++ b/testing/e2e/kube-vip.yaml.tmpl @@ -45,5 +45,5 @@ spec: hostNetwork: true volumes: - hostPath: - path: /etc/kubernetes/admin.conf + path: "{{ .ConfigPath }}" name: kubeconfig diff --git a/testing/e2e/template.go b/testing/e2e/template.go index 43fc9582..4b9abe92 100644 --- a/testing/e2e/template.go +++ b/testing/e2e/template.go @@ -6,4 +6,5 @@ package e2e type KubevipManifestValues struct { ControlPlaneVIP string ImagePath string + ConfigPath string } From 80241ecc743f653f932bc7032d67df60c9ac5c81 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 6 Jan 2024 16:29:55 +0000 Subject: [PATCH 505/542] align timeouts Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 7fe9dc80..435b0181 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -218,7 +218,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv6 VIP with little downtime")) // Allow at most 20 seconds of downtime when polling the control plane nodes - assertControlPlaneIsRoutable(ipv6VIP, 1*time.Second, 20*time.Second) + assertControlPlaneIsRoutable(ipv6VIP, 1*time.Second, 30*time.Second) }) }) }) From e0f9b195af8beb87fd3cf6b7497b0874c6901260 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sat, 6 Jan 2024 17:43:34 +0000 Subject: [PATCH 506/542] grasping at straws Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 435b0181..5ce7c1f5 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -131,6 +131,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { time.Sleep(30 * time.Second) By(withTimestamp("loading local docker image to kind cluster")) e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + killLoadBalancer(clusterName) }() By(withTimestamp("creating a kind cluster with multiple control plane nodes")) @@ -203,6 +204,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { time.Sleep(30 * time.Second) By(withTimestamp("loading local docker image to kind cluster")) e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + killLoadBalancer(clusterName) }() By(withTimestamp("creating a kind cluster with multiple control plane nodes")) @@ -287,6 +289,20 @@ func killLeader(leaderIPAddr string, clusterName string) { Eventually(session, "5s").Should(gexec.Exit(0)) } +func killLoadBalancer(clusterName string) { + dockerLoadBalancer := fmt.Sprintf("%s--external-load-balancer", clusterName) + + Expect(dockerLoadBalancer).ToNot(BeEmpty()) + + cmd := exec.Command( + "docker", "kill", dockerLoadBalancer, + ) + + session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) + Expect(err).NotTo(HaveOccurred()) + Eventually(session, "5s").Should(gexec.Exit(0)) +} + func withTimestamp(text string) string { return fmt.Sprintf("%s: %s", time.Now(), text) } From 6a7c198df0774a7482f9ee01f40bd15efba51000 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 11:24:43 +0000 Subject: [PATCH 507/542] remove lb step Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 5ce7c1f5..435b0181 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -131,7 +131,6 @@ var _ = Describe("kube-vip broadcast neighbor", func() { time.Sleep(30 * time.Second) By(withTimestamp("loading local docker image to kind cluster")) e2e.LoadDockerImageToKind(logger, imagePath, clusterName) - killLoadBalancer(clusterName) }() By(withTimestamp("creating a kind cluster with multiple control plane nodes")) @@ -204,7 +203,6 @@ var _ = Describe("kube-vip broadcast neighbor", func() { time.Sleep(30 * time.Second) By(withTimestamp("loading local docker image to kind cluster")) e2e.LoadDockerImageToKind(logger, imagePath, clusterName) - killLoadBalancer(clusterName) }() By(withTimestamp("creating a kind cluster with multiple control plane nodes")) @@ -289,20 +287,6 @@ func killLeader(leaderIPAddr string, clusterName string) { Eventually(session, "5s").Should(gexec.Exit(0)) } -func killLoadBalancer(clusterName string) { - dockerLoadBalancer := fmt.Sprintf("%s--external-load-balancer", clusterName) - - Expect(dockerLoadBalancer).ToNot(BeEmpty()) - - cmd := exec.Command( - "docker", "kill", dockerLoadBalancer, - ) - - session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) - Expect(err).NotTo(HaveOccurred()) - Eventually(session, "5s").Should(gexec.Exit(0)) -} - func withTimestamp(text string) string { return fmt.Sprintf("%s: %s", time.Now(), text) } From c60660d4d946d14bd23752d51e47e885f9c4e441 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 11:39:37 +0000 Subject: [PATCH 508/542] fix for IPv6 Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 435b0181..ee87e857 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -195,6 +195,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ ControlPlaneVIP: ipv6VIP, ImagePath: imagePath, + ConfigPath: configPath, })).To(Succeed()) }) From 1aba51c70f9637d710ae602b6bb00a45aec5a06c Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 14:38:08 +0000 Subject: [PATCH 509/542] v129 fixes Signed-off-by: Dan Finneran --- Makefile | 2 +- testing/e2e/e2e_test.go | 76 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77b51f4d..5377e7ca 100644 --- a/Makefile +++ b/Makefile @@ -126,7 +126,7 @@ e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd e2e-tests129: - CONFIG_PATH=/etc/kubernetes/super-admin.conf K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd + V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index ee87e857..21974a54 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -39,6 +39,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { kubeVIPManifestTemplate *template.Template clusterName string tempDirPath string + v129 bool ) BeforeEach(func() { @@ -51,6 +52,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { if configPath == "" { configPath = "/etc/kubernetes/admin.conf" } + _, v129 = os.LookupEnv("V129") curDir, err := os.Getwd() Expect(err).NotTo(HaveOccurred()) templatePath := filepath.Join(curDir, "kube-vip.yaml.tmpl") @@ -124,6 +126,44 @@ var _ = Describe("kube-vip broadcast neighbor", func() { ImagePath: imagePath, ConfigPath: configPath, })).To(Succeed()) + + if v129 { + // create a seperate manifest + manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4-first.yaml") + + // for i := 0; i < 3; i++ { + // nodeConfig := kindconfigv1alpha4.Node{ + // Role: kindconfigv1alpha4.ControlPlaneRole, + // ExtraMounts: []kindconfigv1alpha4.Mount{ + // { + // HostPath: manifestPath, + // ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + // }, + // }, + // } + // // Override the kind image version + // if k8sImagePath != "" { + // nodeConfig.Image = k8sImagePath + // } + // clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) + // } + + // change the path of the mount to the new file + clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath + + manifestFile2, err := os.Create(manifestPath) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile2.Close() + + ipv4VIP = e2e.GenerateIPv4VIP() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile2, e2e.KubevipManifestValues{ + ControlPlaneVIP: ipv4VIP, + ImagePath: imagePath, + ConfigPath: "/etc/kubernetes/super-admin.conf", // Change the kuberenetes file + })).To(Succeed()) + } }) It("provides an IPv4 VIP address for the Kubernetes control plane nodes", func() { @@ -197,6 +237,42 @@ var _ = Describe("kube-vip broadcast neighbor", func() { ImagePath: imagePath, ConfigPath: configPath, })).To(Succeed()) + + if v129 { + // create a seperate manifest + manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv6-first.yaml") + + // for i := 0; i < 3; i++ { + // nodeConfig := kindconfigv1alpha4.Node{ + // Role: kindconfigv1alpha4.ControlPlaneRole, + // ExtraMounts: []kindconfigv1alpha4.Mount{ + // { + // HostPath: manifestPath, + // ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + // }, + // }, + // } + // // Override the kind image version + // if k8sImagePath != "" { + // nodeConfig.Image = k8sImagePath + // } + // clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) + // } + + // change the path of the mount to the new file + clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath + + manifestFile2, err := os.Create(manifestPath) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile2.Close() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile2, e2e.KubevipManifestValues{ + ControlPlaneVIP: ipv6VIP, + ImagePath: imagePath, + ConfigPath: "/etc/kubernetes/super-admin.conf", // Change the kuberenetes file + })).To(Succeed()) + } }) It("provides an IPv6 VIP address for the Kubernetes control plane nodes", func() { From 879b5337dc02026291d43c20bf439ab8b04d391a Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 15:04:13 +0000 Subject: [PATCH 510/542] extensive fudging of the CI tests Signed-off-by: Dan Finneran --- Makefile | 2 +- testing/e2e/e2e_test.go | 56 +++++++++++------------------------------ 2 files changed, 15 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 5377e7ca..96e3a868 100644 --- a/Makefile +++ b/Makefile @@ -126,7 +126,7 @@ e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd e2e-tests129: - V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e ./testing/e2e/etcd + V129=true K8S_IMAGE_PATH=kindest/node:v1.29.0 E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo --tags=e2e -v -p ./testing/e2e service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 21974a54..b1701d55 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -129,35 +129,16 @@ var _ = Describe("kube-vip broadcast neighbor", func() { if v129 { // create a seperate manifest - manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4-first.yaml") - - // for i := 0; i < 3; i++ { - // nodeConfig := kindconfigv1alpha4.Node{ - // Role: kindconfigv1alpha4.ControlPlaneRole, - // ExtraMounts: []kindconfigv1alpha4.Mount{ - // { - // HostPath: manifestPath, - // ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", - // }, - // }, - // } - // // Override the kind image version - // if k8sImagePath != "" { - // nodeConfig.Image = k8sImagePath - // } - // clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) - // } + manifestPath2 := filepath.Join(tempDirPath, "kube-vip-ipv4-first.yaml") // change the path of the mount to the new file - clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath + clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath2 - manifestFile2, err := os.Create(manifestPath) + manifestFile2, err := os.Create(manifestPath2) Expect(err).NotTo(HaveOccurred()) defer manifestFile2.Close() - ipv4VIP = e2e.GenerateIPv4VIP() - Expect(kubeVIPManifestTemplate.Execute(manifestFile2, e2e.KubevipManifestValues{ ControlPlaneVIP: ipv4VIP, ImagePath: imagePath, @@ -181,6 +162,10 @@ var _ = Describe("kube-vip broadcast neighbor", func() { // use the default timeout for establishing a connection to the VIP assertControlPlaneIsRoutable(ipv4VIP, time.Duration(0), 20*time.Second) + // wait for a bit + time.Sleep(20 * time.Second) + By(withTimestamp("sitting for a few seconds to hopefully allow the roles to have been created in the cluster")) + By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv4VIP, clusterName) @@ -240,29 +225,12 @@ var _ = Describe("kube-vip broadcast neighbor", func() { if v129 { // create a seperate manifest - manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv6-first.yaml") - - // for i := 0; i < 3; i++ { - // nodeConfig := kindconfigv1alpha4.Node{ - // Role: kindconfigv1alpha4.ControlPlaneRole, - // ExtraMounts: []kindconfigv1alpha4.Mount{ - // { - // HostPath: manifestPath, - // ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", - // }, - // }, - // } - // // Override the kind image version - // if k8sImagePath != "" { - // nodeConfig.Image = k8sImagePath - // } - // clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) - // } + manifestPath2 := filepath.Join(tempDirPath, "kube-vip-ipv6-first.yaml") // change the path of the mount to the new file - clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath + clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath2 - manifestFile2, err := os.Create(manifestPath) + manifestFile2, err := os.Create(manifestPath2) Expect(err).NotTo(HaveOccurred()) defer manifestFile2.Close() @@ -290,6 +258,10 @@ var _ = Describe("kube-vip broadcast neighbor", func() { // use the default timeout for establishing a connection to the VIP assertControlPlaneIsRoutable(ipv6VIP, time.Duration(0), 20*time.Second) + // wait for a bit + time.Sleep(30 * time.Second) + By(withTimestamp("sitting for a few seconds to hopefully allow the roles to have been created in the cluster")) + By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv6VIP, clusterName) From 748d60147da29f4779e67063ea18b2a9fa07a242 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 15:13:15 +0000 Subject: [PATCH 511/542] rage Signed-off-by: Dan Finneran --- testing/e2e/e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index b1701d55..6997c3e6 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -163,8 +163,8 @@ var _ = Describe("kube-vip broadcast neighbor", func() { assertControlPlaneIsRoutable(ipv4VIP, time.Duration(0), 20*time.Second) // wait for a bit - time.Sleep(20 * time.Second) By(withTimestamp("sitting for a few seconds to hopefully allow the roles to have been created in the cluster")) + time.Sleep(30 * time.Second) By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv4VIP, clusterName) @@ -259,8 +259,8 @@ var _ = Describe("kube-vip broadcast neighbor", func() { assertControlPlaneIsRoutable(ipv6VIP, time.Duration(0), 20*time.Second) // wait for a bit - time.Sleep(30 * time.Second) By(withTimestamp("sitting for a few seconds to hopefully allow the roles to have been created in the cluster")) + time.Sleep(30 * time.Second) By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) killLeader(ipv6VIP, clusterName) From 6ef860da528e75282c3490731d60225d5a6230a2 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 7 Jan 2024 15:28:17 +0000 Subject: [PATCH 512/542] Last fix Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0f083e71..5dc63425 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -10,7 +10,7 @@ jobs: name: Checks and linters steps: - name: Init - run: sudo apt-get update && sudo apt-get install -y build-essential golint + run: sudo apt-get update && sudo apt-get install -y build-essential golint && sudo sysctl fs.inotify.max_user_instances=8192 && sudo sysctl fs.inotify.max_user_watches=524288 - name: Install golangci-lint run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - name: Checkout code From 3c0e5e327e21e26f1f131c90e0908dc01662ae37 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Sun, 7 Jan 2024 16:15:27 +0000 Subject: [PATCH 513/542] Update ci.yaml --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5dc63425..c4fca5af 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: - name: Init run: sudo apt-get update && sudo apt-get install -y build-essential golint && sudo sysctl fs.inotify.max_user_instances=8192 && sudo sysctl fs.inotify.max_user_watches=524288 - name: Install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2 - name: Checkout code uses: actions/checkout@v4 - name: Install Go From 444b4a9c0d7a92eb0a6bacbffbb84af18abffef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 02:07:44 +0000 Subject: [PATCH 514/542] Bump github.com/packethost/packngo from 0.30.0 to 0.31.0 Bumps [github.com/packethost/packngo](https://github.com/packethost/packngo) from 0.30.0 to 0.31.0. - [Release notes](https://github.com/packethost/packngo/releases) - [Changelog](https://github.com/packethost/packngo/blob/master/CHANGELOG.md) - [Commits](https://github.com/packethost/packngo/compare/v0.30.0...v0.31.0) --- updated-dependencies: - dependency-name: github.com/packethost/packngo dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ddc074ff..736040d6 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 github.com/osrg/gobgp/v3 v3.19.0 - github.com/packethost/packngo v0.30.0 + github.com/packethost/packngo v0.31.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index b5e23324..89c35cdd 100644 --- a/go.sum +++ b/go.sum @@ -298,8 +298,8 @@ github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CTN21W18= -github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= -github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= +github.com/packethost/packngo v0.31.0 h1:LLH90ardhULWbagBIc3I3nl2uU75io0a7AwY6hyi0S4= +github.com/packethost/packngo v0.31.0/go.mod h1:Io6VJqzkiqmIEQbpOjeIw9v8q9PfcTEq8TEY/tMQsfw= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= From 7dec36796027fbde1a4ae295fbc1f60c1a6e9104 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 02:07:48 +0000 Subject: [PATCH 515/542] Bump golang.org/x/sys from 0.15.0 to 0.16.0 Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.15.0 to 0.16.0. - [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.16.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ddc074ff..529102b7 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( go.etcd.io/etcd/client/v3 v3.5.11 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 - golang.org/x/sys v0.15.0 + golang.org/x/sys v0.16.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.29.0 diff --git a/go.sum b/go.sum index b5e23324..4d60612f 100644 --- a/go.sum +++ b/go.sum @@ -578,8 +578,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= From 7dda7b42c1ebbe1890a8afe231be50547bc203ae Mon Sep 17 00:00:00 2001 From: Marcel Fest Date: Fri, 15 Dec 2023 09:57:19 +0100 Subject: [PATCH 516/542] Added non-leader-election mode for routing table mode and preliminary support for endpointslices. Signed-off-by: Patryk Strusiewicz-Surmacki --- cmd/kube-vip.go | 1 + pkg/cluster/service.go | 6 +- pkg/kubevip/config_environment.go | 10 ++ pkg/kubevip/config_envvar.go | 3 + pkg/kubevip/config_generator.go | 7 + pkg/kubevip/config_types.go | 3 + pkg/manager/manager.go | 13 ++ pkg/manager/manager_table.go | 10 +- pkg/manager/services.go | 36 ++-- pkg/manager/servicesLeader.go | 1 + pkg/manager/watch_endpoints.go | 136 ++++++++++----- pkg/manager/watch_endpointslices.go | 252 ++++++++++++++++++++++++++++ pkg/manager/watch_services.go | 44 ++++- 13 files changed, 458 insertions(+), 64 deletions(-) create mode 100644 pkg/manager/watch_endpointslices.go diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 183b5d1c..2af0dd98 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -138,6 +138,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpointSlices, "enableEndpointSlices", false, "If enabled, kube-vip will only advertise services, but will use EndpointSLices instead of endpoints to get IPs of Pods") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index d57264ba..c5077a7c 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -155,12 +155,12 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser if err != nil { log.Warnf("Attempted to clean existing VIP => %v", err) } - if c.EnableRoutingTable { + if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) { err = cluster.Network.AddRoute() if err != nil { log.Warnf("%v", err) } - } else { + } else if !c.EnableRoutingTable { err = cluster.Network.AddIP() if err != nil { log.Warnf("%v", err) @@ -216,7 +216,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // Stop the Arp context if it is running cancelArp() - if c.EnableRoutingTable { + if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) { err = cluster.Network.DeleteRoute() if err != nil { log.Warnf("%v", err) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 013e82ea..8dd449eb 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -524,5 +524,15 @@ func ParseEnvironment(c *Config) error { if env != "" { c.K8sConfigFile = env } + + env = os.Getenv(enableEndpointSlices) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.EnableEndpointSlices = b + } + return nil } diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 09675d31..2fe55fc0 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -186,4 +186,7 @@ const ( //k8sConfigFile defines the path to the configfile used to speak with the API server k8sConfigFile = "k8s_config_file" + + // enableEndpointSlices enables use of EndpointSLices instead of Endpoints + enableEndpointSlices = "enable_endpointslices" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 6415064e..b60a82a4 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -476,6 +476,13 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, prometheus...) } + if c.EnableEndpointSlices { + newEnvironment = append(newEnvironment, corev1.EnvVar{ + Name: enableEndpointSlices, + Value: strconv.FormatBool(c.EnableEndpointSlices), + }) + } + newManifest := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 2bc2edee..08994c02 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -157,6 +157,9 @@ type Config struct { // K8sConfigFile, this is the path to the config file used to speak with the API server K8sConfigFile string `yaml:"k8sConfigFile"` + + // EnableEndpointSlices, if enabled, EndpointSlices will be used instead of Endpoints + EnableEndpointSlices bool `yaml:"enableEndpointSlices"` } // KubernetesLeaderElection defines all of the settings for Kubernetes KubernetesLeaderElection diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 538b3e25..bf266c79 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -16,6 +16,7 @@ import ( "github.com/kube-vip/kube-vip/pkg/kubevip" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes" ) @@ -216,3 +217,15 @@ func fileExists(filename string) bool { } return !info.IsDir() } + +func (sm *Manager) findServiceInstance(svc *v1.Service) *Instance { + svcUID := string(svc.UID) + log.Debugf("service UID: %s", svcUID) + for i := range sm.serviceInstances { + log.Debugf("saved service instance %d UID: %s", i, sm.serviceInstances[i].UID) + if sm.serviceInstances[i].UID == svcUID { + return sm.serviceInstances[i] + } + } + return nil +} diff --git a/pkg/manager/manager_table.go b/pkg/manager/manager_table.go index 274bbb67..6d9749e4 100644 --- a/pkg/manager/manager_table.go +++ b/pkg/manager/manager_table.go @@ -50,7 +50,7 @@ func (sm *Manager) startTableMode() error { if err != nil { return err } - } else { + } else if sm.config.EnableLeaderElection { log.Infof("beginning services leadership, namespace [%s], lock name [%s], id [%s]", ns, plunderLock, id) // we use the Lease lock type since edits to Leases are less common @@ -65,7 +65,6 @@ func (sm *Manager) startTableMode() error { Identity: id, }, } - // start the leader election code loop leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{ Lock: lock, @@ -107,6 +106,13 @@ func (sm *Manager) startTableMode() error { }, }, }) + } else { + // TODO: this needs to be called periodically or do I need to wrap it somehow with a cancel context? + log.Infof("beginning watching services without leader election") + err = sm.servicesWatcher(ctx, sm.syncServices) + if err != nil { + log.Errorf("Cannot watch services, %v", err) + } } return nil } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 440b29ab..494897ad 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/google/go-cmp/cmp" log "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" v1 "k8s.io/api/core/v1" @@ -24,7 +25,7 @@ const ( egress = "kube-vip.io/egress" egressDestinationPorts = "kube-vip.io/egress-destination-ports" egressSourcePorts = "kube-vip.io/egress-source-ports" - endpoint = "kube-vip.io/active-endpoint" + activeEndpoint = "kube-vip.io/active-endpoint" flushContrack = "kube-vip.io/flush-conntrack" loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" loadbalancerHostname = "kube-vip.io/loadbalancerHostname" @@ -150,17 +151,17 @@ func (sm *Manager) addService(svc *v1.Service) error { if svc.Annotations[egress] == "true" && len(serviceIPs) > 0 { log.Debugf("Enabling egress for the service [%s]", svc.Name) serviceIP := serviceIPs[0] - if svc.Annotations[endpoint] != "" { + if svc.Annotations[activeEndpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(serviceIP, svc.Annotations[endpoint], svc.Annotations[egressDestinationPorts], svc.Namespace) + err = sm.configureEgress(serviceIP, svc.Annotations[activeEndpoint], svc.Annotations[egressDestinationPorts], svc.Namespace) if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } else { - err = sm.updateServiceEndpointAnnotation(svc.Annotations[endpoint], svc) + err = sm.updateServiceEndpointAnnotation(svc.Annotations[activeEndpoint], svc) if err != nil { log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) } @@ -236,10 +237,10 @@ func (sm *Manager) deleteService(uid string) error { // We will need to tear down the egress if serviceInstance.serviceSnapshot.Annotations[egress] == "true" { - if serviceInstance.serviceSnapshot.Annotations[endpoint] != "" { + if serviceInstance.serviceSnapshot.Annotations[activeEndpoint] != "" { log.Infof("service [%s] has an egress re-write enabled", serviceInstance.serviceSnapshot.Name) - err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[endpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) + err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[activeEndpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) if err != nil { log.Errorf("%v", err) } @@ -299,12 +300,13 @@ func (sm *Manager) updateStatus(i *Instance) error { currentServiceCopy.Annotations[requestedIP] = i.dhcpInterfaceIP } - updatedService, err := sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service Spec [%s] : %v", i.serviceSnapshot.Name, err) - return err + 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) + return err + } } - ports := make([]v1.PortStatus, 0, len(i.serviceSnapshot.Spec.Ports)) for _, port := range i.serviceSnapshot.Spec.Ports { ports = append(ports, v1.PortStatus{ @@ -319,11 +321,13 @@ func (sm *Manager) updateStatus(i *Instance) error { Ports: ports, }) } - updatedService.Status.LoadBalancer.Ingress = ingresses - _, err = sm.clientSet.CoreV1().Services(updatedService.Namespace).UpdateStatus(context.TODO(), updatedService, metav1.UpdateOptions{}) - if err != nil { - log.Errorf("Error updating Service %s/%s Status: %v", i.serviceSnapshot.Namespace, i.serviceSnapshot.Name, err) - return err + if !cmp.Equal(currentService.Status.LoadBalancer.Ingress, ingresses) { + 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) + return err + } } return nil }) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 4161afed..b86e4db1 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -24,6 +24,7 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro for _, instance := range sm.serviceInstances { for _, cluster := range instance.clusters { + cluster.Network.DeleteRoute() cluster.Stop() } } diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index fccb1411..67b91cd3 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -71,6 +71,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser // We need to inspect the event and get ResourceVersion out of it switch event.Type { + case watch.Added, watch.Modified: ep, ok := event.Object.(*v1.Endpoints) if !ok { @@ -79,40 +80,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } // Build endpoints - var localendpoints []string - for subset := range ep.Subsets { - for address := range ep.Subsets[subset].Addresses { - // 1. Compare the hostname on the endpoint to the hostname - // 2. Compare the nodename on the endpoint to the hostname - // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint - - // 1. Compare the Hostname first (should be FQDN) - if id == ep.Subsets[subset].Addresses[address].Hostname { - log.Debugf("[endpoint] address: %s, hostname: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname) - localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - } else { - // 2. Compare the Nodename (from testing could be FQDN or short) - if ep.Subsets[subset].Addresses[address].NodeName != nil { - log.Debugf("[endpoint] address: %s, hostname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname, *ep.Subsets[subset].Addresses[address].NodeName) - if id == *ep.Subsets[subset].Addresses[address].NodeName { - localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - } else { - // 3. Compare to shortname - shortname, err := getShortname(id) - if err != nil { - log.Errorf("[endpoint] %v", err) - } else { - log.Debugf("[endpoint] address: %s, shortname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, shortname, *ep.Subsets[subset].Addresses[address].NodeName) - - if shortname == *ep.Subsets[subset].Addresses[address].NodeName { - localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - } - } - } - } - } - } - } + localendpoints := getLocalEndpoints(ep, id) // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -149,11 +117,11 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } // Set the service accordingly - if service.Annotations["kube-vip.io/egress"] == "true" { - service.Annotations["kube-vip.io/active-endpoint"] = lastKnownGoodEndpoint + if service.Annotations[egress] == "true" { + service.Annotations[activeEndpoint] = lastKnownGoodEndpoint } - if !leaderElectionActive { + if !leaderElectionActive && sm.config.EnableServicesElection { go func() { leaderContext, cancel = context.WithCancel(context.Background()) @@ -170,11 +138,36 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } else { leaderElectionActive = false break + } } }() } + + // There are local endpoints available on the node, therefore route(s) should be added to the table + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + err := cluster.Network.AddRoute() + if err != nil { + log.Errorf("[endpoint] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + } + } + } + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } + } else { + // There are no local enpoints - routes should be deleted + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && configuredLocalRoutes[string(service.UID)] { + sm.clearRoutes(service) + configuredLocalRoutes[string(service.UID)] = false + } + // If there are no local endpoints, and we had one then remove it and stop the leaderElection if lastKnownGoodEndpoint != "" { log.Warnf("[endpoint] existing [%s] has been removed, no remaining endpoints for leaderElection", lastKnownGoodEndpoint) @@ -186,9 +179,23 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser log.Debugf("[endpoint watcher] local endpoint(s) [%d], known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: + // Check if deleted endpoints were local endpoints for this node, if so, clear routes + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable { + ep, ok := event.Object.(*v1.Endpoints) + if !ok { + cancel() + return fmt.Errorf("unable to parse Kubernetes services from API watcher") + } + localEndpoints := getLocalEndpoints(ep, id) + if len(localEndpoints) > 0 { + sm.clearRoutes(service) + } + } + // Close the goroutine that will end the retry watcher, then exit the endpoint watcher function close(exitFunction) log.Infof("[endpoints] deleted stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) + return nil case watch.Error: errObject := apierrors.FromObject(event.Object) @@ -201,6 +208,59 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser return nil //nolint:govet } +func getLocalEndpoints(ep *v1.Endpoints, id string) []string { + var localendpoints []string + + for subset := range ep.Subsets { + for address := range ep.Subsets[subset].Addresses { + // 1. Compare the hostname on the endpoint to the hostname + // 2. Compare the nodename on the endpoint to the hostname + // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint + + // 1. Compare the Hostname first (should be FQDN) + if id == ep.Subsets[subset].Addresses[address].Hostname { + log.Debugf("[endpoint] address: %s, hostname: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname) + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } else { + // 2. Compare the Nodename (from testing could be FQDN or short) + if ep.Subsets[subset].Addresses[address].NodeName != nil { + log.Debugf("[endpoint] address: %s, hostname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname, *ep.Subsets[subset].Addresses[address].NodeName) + if id == *ep.Subsets[subset].Addresses[address].NodeName { + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } else { + // 3. Compare to shortname + shortname, err := getShortname(id) + if err != nil { + log.Errorf("[endpoint] %v", err) + } else { + log.Debugf("[endpoint] address: %s, shortname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, shortname, *ep.Subsets[subset].Addresses[address].NodeName) + + if shortname == *ep.Subsets[subset].Addresses[address].NodeName { + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } + } + } + } + } + } + } + return localendpoints +} + +func (sm *Manager) clearRoutes(service *v1.Service) { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + err := cluster.Network.DeleteRoute() + if err != nil && !strings.Contains(err.Error(), "no such process") { + log.Errorf("failed to delete route for %s: %s", cluster.Network.IP(), err.Error()) + } else { + log.Infof("deleted route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + } + } + } +} + func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1.Service) error { retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { // Retrieve the latest version of Deployment before attempting update @@ -215,7 +275,7 @@ func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1. currentServiceCopy.Annotations = make(map[string]string) } - currentServiceCopy.Annotations["kube-vip.io/active-endpoint"] = endpoint + currentServiceCopy.Annotations[activeEndpoint] = endpoint _, err = sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) if err != nil { diff --git a/pkg/manager/watch_endpointslices.go b/pkg/manager/watch_endpointslices.go new file mode 100644 index 00000000..6439b0fe --- /dev/null +++ b/pkg/manager/watch_endpointslices.go @@ -0,0 +1,252 @@ +package manager + +import ( + "context" + "fmt" + "sync" + + log "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" + watchtools "k8s.io/client-go/tools/watch" +) + +func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { + log.Infof("[endpointslices] watching for service [%s] in namespace [%s]", service.Name, service.Namespace) + // Use a restartable watcher, as this should help in the event of etcd or timeout issues + leaderContext, cancel := context.WithCancel(context.Background()) + var leaderElectionActive bool + defer cancel() + + labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{"kubernetes.io/service-name": service.Name}} + + opts := metav1.ListOptions{ + LabelSelector: labels.Set(labelSelector.MatchLabels).String(), + } + + rw, err := watchtools.NewRetryWatcher("1", &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return sm.clientSet.DiscoveryV1().EndpointSlices(service.Namespace).Watch(ctx, opts) + }, + }) + if err != nil { + cancel() + return fmt.Errorf("[endpointslices] error creating endpointslices watcher: %s", err.Error()) + } + + exitFunction := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + log.Debug("[endpointslices] context cancelled") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return + case <-sm.shutdownChan: + log.Debug("[endpointslices] shutdown called") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return + case <-exitFunction: + log.Debug("[endpointslices] function ending") + // Stop the retry watcher + rw.Stop() + // Cancel the context, which will in turn cancel the leadership + cancel() + return + } + }() + + ch := rw.ResultChan() + + for event := range ch { + lastKnownGoodEndpoint := "" + // We need to inspect the event and get ResourceVersion out of it + switch event.Type { + case watch.Added, watch.Modified: + + eps, ok := event.Object.(*discoveryv1.EndpointSlice) + if !ok { + cancel() + return fmt.Errorf("[endpointslices] unable to parse Kubernetes services from API watcher") + } + + // Build endpoints + localendpoints := getLocalEndpointsFromEndpointslices(eps, id) + + // Find out if we have any local endpoints + // if out endpoint is empty then populate it + // if not, go through the endpoints and see if ours still exists + // If we have a local endpoint then begin the leader Election, unless it's already running + // + + // Check that we have local endpoints + if len(localendpoints) != 0 { + // if we haven't populated one, then do so + if lastKnownGoodEndpoint != "" { + + // check out previous endpoint exists + stillExists := false + + for x := range localendpoints { + if localendpoints[x] == lastKnownGoodEndpoint { + stillExists = true + } + } + // If the last endpoint no longer exists, we cancel our leader Election + if !stillExists && leaderElectionActive { + log.Warnf("[endpointslices] existing endpoint [%s] has been removed, restarting leaderElection", lastKnownGoodEndpoint) + // Stop the existing leaderElection + cancel() + // Set our active endpoint to an existing one + lastKnownGoodEndpoint = localendpoints[0] + // disable last leaderElection flag + leaderElectionActive = false + } + + } else { + lastKnownGoodEndpoint = localendpoints[0] + } + + // Set the service accordingly + if service.Annotations[egress] == "true" { + service.Annotations[activeEndpoint] = lastKnownGoodEndpoint + } + + if !leaderElectionActive && sm.config.EnableServicesElection { + go func() { + leaderContext, cancel = context.WithCancel(context.Background()) + + // This is a blocking function, that will restart (in the event of failure) + for { + // if the context isn't cancelled restart + if leaderContext.Err() != context.Canceled { + leaderElectionActive = true + err = sm.StartServicesLeaderElection(leaderContext, service, wg) + if err != nil { + log.Error(err) + } + leaderElectionActive = false + } else { + leaderElectionActive = false + break + } + } + }() + } + + // There are local endpoints available on the node, therefore route(s) should be added to the table + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + err := cluster.Network.AddRoute() + if err != nil { + log.Errorf("[endpointslices] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpointslices] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + } + } + } + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } + } else { + // There are no local enpoints - routes should be deleted + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && configuredLocalRoutes[string(service.UID)] { + sm.clearRoutes(service) + configuredLocalRoutes[string(service.UID)] = false + leaderElectionActive = false + } + + // If there are no local endpoints, and we had one then remove it and stop the leaderElection + if lastKnownGoodEndpoint != "" { + log.Warnf("[endpointslices] existing endpoint [%s] has been removed, no remaining endpoints for leaderElection", lastKnownGoodEndpoint) + lastKnownGoodEndpoint = "" // reset endpoint + cancel() // stop services watcher + leaderElectionActive = false + } + } + log.Debugf("[endpointslices watcher] local endpoint(s) [%d], known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + + case watch.Deleted: + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable { + ep, ok := event.Object.(*v1.Endpoints) + if !ok { + cancel() + return fmt.Errorf("[endpointslices] unable to parse Kubernetes services from API watcher") + } + localEndpoints := getLocalEndpoints(ep, id) + if len(localEndpoints) > 0 { + sm.clearRoutes(service) + } + } + + // Close the goroutine that will end the retry watcher, then exit the endpoint watcher function + close(exitFunction) + log.Infof("[endpointslices] deleted stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) + return nil + case watch.Error: + errObject := apierrors.FromObject(event.Object) + statusErr, _ := errObject.(*apierrors.StatusError) + log.Errorf("[endpointslices] -> %v", statusErr) + } + } + close(exitFunction) + log.Infof("[endpointslices] stopping watching for [%s] in namespace [%s]", service.Name, service.Namespace) + return nil //nolint:govet +} + +func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id string) []string { + var localendpoints []string + for i := range eps.Endpoints { + for j := range eps.Endpoints[i].Addresses { + // 1. Compare the hostname on the endpoint to the hostname + // 2. Compare the nodename on the endpoint to the hostname + // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint + + // 1. Compare the Hostname first (should be FQDN) + if eps.Endpoints[i].Hostname != nil && id == *eps.Endpoints[i].Hostname { + log.Debugf("[endpointslices] address: %s, hostname: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname) + if *eps.Endpoints[i].Conditions.Serving { + localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + } + } else { + // 2. Compare the Nodename (from testing could be FQDN or short) + if eps.Endpoints[i].NodeName != nil { + if eps.Endpoints[i].Hostname != nil { + log.Debugf("[endpointslices] address: %s, hostname: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname, *eps.Endpoints[i].NodeName) + } else { + log.Debugf("[endpointslices] address: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].NodeName) + } + + if id == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { + localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + } else { + // 3. Compare to shortname + shortname, err := getShortname(id) + if err != nil { + log.Errorf("[endpointslices] %v", err) + } else { + log.Debugf("[endpointslices] address: %s, shortname: %s, node: %s", eps.Endpoints[i].Addresses[j], shortname, *eps.Endpoints[i].NodeName) + + if shortname == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { + localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + } + } + } + } + } + } + } + return localendpoints +} diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 7b406140..b6ce192e 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -32,12 +32,16 @@ var activeService map[string]bool // watchedService keeps track of services that are already being watched var watchedService map[string]bool +// watchedService keeps track of routes that has been configured on the node +var configuredLocalRoutes map[string]bool + func init() { // Set up the caches for monitoring existing active or watched services activeServiceLoadBalancerCancel = make(map[string]func()) activeServiceLoadBalancer = make(map[string]context.Context) activeService = make(map[string]bool) watchedService = make(map[string]bool) + configuredLocalRoutes = make(map[string]bool) } // This function handles the watching of a services endpoints and updates a load balancers endpoint configurations accordingly @@ -145,7 +149,12 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context wg.Add(1) activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) // Background the services election - if sm.config.EnableServicesElection { + // EnableServicesElection enabled + // watchEndpoint will do a ServicesElection by Service and understands local endpoints + // + // EnableRoutingTable enabled and EnableLeaderElection disabled + // watchEndpoint will also not do a leaderElection by service. + if sm.config.EnableServicesElection || (sm.config.EnableRoutingTable && !sm.config.EnableLeaderElection) { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Start an endpoint watcher if we're not watching it already if !watchedService[string(svc.UID)] { @@ -154,13 +163,31 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Add Endpoint watcher wg.Add(1) - err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) - if err != nil { - log.Error(err) + if !sm.config.EnableEndpointSlices { + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } + } else { + err = sm.watchEndpointSlices(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } } wg.Done() } }() + + if sm.config.EnableRoutingTable && !sm.config.EnableLeaderElection { + wg.Add(1) + go func() { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() + }() + } // We're now watching this service watchedService[string(svc.UID)] = true } @@ -203,6 +230,14 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context log.Infof("(svcs) [%s] has an ignore annotation for kube-vip", svc.Name) break } + + // If no leader election is enabled, delete routes here + if !sm.config.EnableLeaderElection && !sm.config.EnableServicesElection && + sm.config.EnableRoutingTable && configuredLocalRoutes[string(svc.UID)] { + configuredLocalRoutes[string(svc.UID)] = false + sm.clearRoutes(svc) + } + // If this is an active service then and additional leaderElection will handle stopping err := sm.deleteService(string(svc.UID)) if err != nil { @@ -211,7 +246,6 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Calls the cancel function of the context if activeServiceLoadBalancerCancel[string(svc.UID)] != nil { - activeServiceLoadBalancerCancel[string(svc.UID)]() } activeService[string(svc.UID)] = false From 9d640c5c44bf694891e7ec272dc1a6451db93936 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Thu, 11 Jan 2024 11:37:29 +0100 Subject: [PATCH 517/542] Fixed linter issue Signed-off-by: Patryk Strusiewicz-Surmacki --- go.mod | 2 +- pkg/manager/servicesLeader.go | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index ddc074ff..480fee52 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/florianl/go-conntrack v0.4.0 github.com/golang/protobuf v1.5.3 + github.com/google/go-cmp v0.6.0 github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 @@ -59,7 +60,6 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index b86e4db1..4d89abf5 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "strings" "sync" "time" @@ -24,7 +25,11 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro for _, instance := range sm.serviceInstances { for _, cluster := range instance.clusters { - cluster.Network.DeleteRoute() + err = cluster.Network.DeleteRoute() + if err != nil && !strings.Contains(err.Error(), "no such process") { + log.Errorf("error while deleting route %s on interface %s: %s", + cluster.Network.IP(), cluster.Network.Interface(), err.Error()) + } cluster.Stop() } } From 70a436ddf397e40e50d9f6c5ccd2ff6629b03507 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Fri, 12 Jan 2024 11:09:19 +0100 Subject: [PATCH 518/542] Improved logging. Fixed issue with endpointslices deletion event. Signed-off-by: Patryk Strusiewicz-Surmacki --- pkg/manager/watch_endpoints.go | 42 +++++++++++++----------- pkg/manager/watch_endpointslices.go | 50 ++++++++++++++++------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 67b91cd3..3c0526ce 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -6,6 +6,7 @@ import ( "strings" "sync" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -80,7 +81,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } // Build endpoints - localendpoints := getLocalEndpoints(ep, id) + localendpoints := getLocalEndpoints(ep, id, sm.config) // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -152,7 +153,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser if err != nil { log.Errorf("[endpoint] error adding route: %s\n", err.Error()) } else { - log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", + log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) } } @@ -176,7 +177,8 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser leaderElectionActive = false } } - log.Debugf("[endpoint watcher] local endpoint(s) [%d], known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + log.Debugf("[endpoint watcher] service %s/%s: local endpoint(s) [%d], known good [%s], active election [%t]", + service.Namespace, service.Name, len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: // Check if deleted endpoints were local endpoints for this node, if so, clear routes @@ -186,7 +188,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser cancel() return fmt.Errorf("unable to parse Kubernetes services from API watcher") } - localEndpoints := getLocalEndpoints(ep, id) + localEndpoints := getLocalEndpoints(ep, id, sm.config) if len(localEndpoints) > 0 { sm.clearRoutes(service) } @@ -208,9 +210,18 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser return nil //nolint:govet } -func getLocalEndpoints(ep *v1.Endpoints, id string) []string { +func getLocalEndpoints(ep *v1.Endpoints, id string, config *kubevip.Config) []string { var localendpoints []string + shortname, shortnameErr := getShortname(id) + if shortnameErr != nil { + if config.EnableRoutingTable && (!config.EnableLeaderElection && !config.EnableServicesElection) { + log.Debugf("[endpoint] %v, shortname will not be used", shortnameErr) + } else { + log.Errorf("[endpoint] %v", shortnameErr) + } + } + for subset := range ep.Subsets { for address := range ep.Subsets[subset].Addresses { // 1. Compare the hostname on the endpoint to the hostname @@ -218,28 +229,21 @@ func getLocalEndpoints(ep *v1.Endpoints, id string) []string { // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint // 1. Compare the Hostname first (should be FQDN) + log.Debugf("[endpoint] processing endpoint [%s]", ep.Subsets[subset].Addresses[address].IP) if id == ep.Subsets[subset].Addresses[address].Hostname { - log.Debugf("[endpoint] address: %s, hostname: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname) + log.Debugf("[endpoint] found local endpoint - address: %s, hostname: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname) localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) } else { // 2. Compare the Nodename (from testing could be FQDN or short) if ep.Subsets[subset].Addresses[address].NodeName != nil { - log.Debugf("[endpoint] address: %s, hostname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname, *ep.Subsets[subset].Addresses[address].NodeName) if id == *ep.Subsets[subset].Addresses[address].NodeName { + log.Debugf("[endpoint] found local endpoint - address: %s, hostname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, ep.Subsets[subset].Addresses[address].Hostname, *ep.Subsets[subset].Addresses[address].NodeName) + localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) + } else if shortnameErr == nil && shortname == *ep.Subsets[subset].Addresses[address].NodeName { + log.Debugf("[endpoint] found local endpoint - address: %s, shortname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, shortname, *ep.Subsets[subset].Addresses[address].NodeName) localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - } else { - // 3. Compare to shortname - shortname, err := getShortname(id) - if err != nil { - log.Errorf("[endpoint] %v", err) - } else { - log.Debugf("[endpoint] address: %s, shortname: %s, node: %s", ep.Subsets[subset].Addresses[address].IP, shortname, *ep.Subsets[subset].Addresses[address].NodeName) - - if shortname == *ep.Subsets[subset].Addresses[address].NodeName { - localendpoints = append(localendpoints, ep.Subsets[subset].Addresses[address].IP) - } - } } + } } } diff --git a/pkg/manager/watch_endpointslices.go b/pkg/manager/watch_endpointslices.go index 6439b0fe..c92afabb 100644 --- a/pkg/manager/watch_endpointslices.go +++ b/pkg/manager/watch_endpointslices.go @@ -5,6 +5,7 @@ import ( "fmt" "sync" + "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" @@ -81,7 +82,7 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * } // Build endpoints - localendpoints := getLocalEndpointsFromEndpointslices(eps, id) + localendpoints := getLocalEndpointsFromEndpointslices(eps, id, sm.config) // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -176,16 +177,17 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * leaderElectionActive = false } } - log.Debugf("[endpointslices watcher] local endpoint(s) [%d], known good [%s], active election [%t]", len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + log.Debugf("[endpointslices watcher] service %s/%s: local endpoint(s) [%d], known good [%s], active election [%t]", + service.Namespace, service.Name, len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable { - ep, ok := event.Object.(*v1.Endpoints) + eps, ok := event.Object.(*discoveryv1.EndpointSlice) if !ok { cancel() return fmt.Errorf("[endpointslices] unable to parse Kubernetes services from API watcher") } - localEndpoints := getLocalEndpoints(ep, id) + localEndpoints := getLocalEndpointsFromEndpointslices(eps, id, sm.config) if len(localEndpoints) > 0 { sm.clearRoutes(service) } @@ -206,8 +208,18 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * return nil //nolint:govet } -func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id string) []string { +func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id string, config *kubevip.Config) []string { var localendpoints []string + + shortname, shortnameErr := getShortname(id) + if shortnameErr != nil { + if config.EnableRoutingTable && (!config.EnableLeaderElection && !config.EnableServicesElection) { + log.Debugf("[endpoint] %v, shortname will not be used", shortnameErr) + } else { + log.Errorf("[endpoint] %v", shortnameErr) + } + } + for i := range eps.Endpoints { for j := range eps.Endpoints[i].Addresses { // 1. Compare the hostname on the endpoint to the hostname @@ -215,34 +227,26 @@ func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id stri // 3. Drop the FQDN to a shortname and compare to the nodename on the endpoint // 1. Compare the Hostname first (should be FQDN) + log.Debugf("[endpointslices] processing endpoint [%s]", eps.Endpoints[i].Addresses[j]) if eps.Endpoints[i].Hostname != nil && id == *eps.Endpoints[i].Hostname { - log.Debugf("[endpointslices] address: %s, hostname: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname) if *eps.Endpoints[i].Conditions.Serving { + log.Debugf("[endpointslices] found endpoint - address: %s, hostname: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname) localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) } } else { // 2. Compare the Nodename (from testing could be FQDN or short) if eps.Endpoints[i].NodeName != nil { - if eps.Endpoints[i].Hostname != nil { - log.Debugf("[endpointslices] address: %s, hostname: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname, *eps.Endpoints[i].NodeName) - } else { - log.Debugf("[endpointslices] address: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].NodeName) - } - if id == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { - localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) - } else { - // 3. Compare to shortname - shortname, err := getShortname(id) - if err != nil { - log.Errorf("[endpointslices] %v", err) + if eps.Endpoints[i].Hostname != nil { + log.Debugf("[endpointslices] found endpoint - address: %s, hostname: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].Hostname, *eps.Endpoints[i].NodeName) } else { - log.Debugf("[endpointslices] address: %s, shortname: %s, node: %s", eps.Endpoints[i].Addresses[j], shortname, *eps.Endpoints[i].NodeName) - - if shortname == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { - localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) - } + log.Debugf("[endpointslices] found endpoint - address: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].NodeName) } + localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + } else if shortnameErr != nil && shortname == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { + log.Debugf("[endpointslices] found endpoint - address: %s, shortname: %s, node: %s", eps.Endpoints[i].Addresses[j], shortname, *eps.Endpoints[i].NodeName) + localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + } } } From d9fc6a5848f4886908ef0301f507b024f4ff5c31 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Fri, 12 Jan 2024 13:27:00 +0100 Subject: [PATCH 519/542] Fixed typos and removed error check after route deletion Signed-off-by: Patryk Strusiewicz-Surmacki --- cmd/kube-vip.go | 2 +- pkg/kubevip/config_envvar.go | 2 +- pkg/manager/servicesLeader.go | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 2af0dd98..ae42574f 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -138,7 +138,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpointSlices, "enableEndpointSlices", false, "If enabled, kube-vip will only advertise services, but will use EndpointSLices instead of endpoints to get IPs of Pods") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpointSlices, "enableEndpointSlices", false, "If enabled, kube-vip will only advertise services, but will use EndpointSlices instead of endpoints to get IPs of Pods") // Prometheus HTTP Server kubeVipCmd.PersistentFlags().StringVar(&initConfig.PrometheusHTTPServer, "prometheusHTTPServer", ":2112", "Host and port used to expose Prometheus metrics via an HTTP server") diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 2fe55fc0..08f362a4 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -187,6 +187,6 @@ const ( //k8sConfigFile defines the path to the configfile used to speak with the API server k8sConfigFile = "k8s_config_file" - // enableEndpointSlices enables use of EndpointSLices instead of Endpoints + // enableEndpointSlices enables use of EndpointSlices instead of Endpoints enableEndpointSlices = "enable_endpointslices" ) diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index 4d89abf5..e953ae79 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "os" - "strings" "sync" "time" @@ -25,11 +24,7 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro for _, instance := range sm.serviceInstances { for _, cluster := range instance.clusters { - err = cluster.Network.DeleteRoute() - if err != nil && !strings.Contains(err.Error(), "no such process") { - log.Errorf("error while deleting route %s on interface %s: %s", - cluster.Network.IP(), cluster.Network.Interface(), err.Error()) - } + _ = cluster.Network.DeleteRoute() cluster.Stop() } } From 29f7536083d916d54f22124a2466aa55530a8cd2 Mon Sep 17 00:00:00 2001 From: Cellebyte Date: Sat, 13 Jan 2024 12:22:57 +0100 Subject: [PATCH 520/542] fix #723 and allow short hostnames as well --- pkg/manager/watch_endpoints.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index fccb1411..2cae63b8 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -238,7 +238,7 @@ func getShortname(hostname string) (string, error) { return "", fmt.Errorf("unable to find shortname from %s", hostname) } hostParts := strings.Split(hostname, ".") - if len(hostParts) > 1 { + if len(hostParts) >= 1 { return hostParts[0], nil } return "", fmt.Errorf("unable to find shortname from %s", hostname) From 40508a4c6dc78b9aedbf457b6a6a93f803ea7f98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 02:35:34 +0000 Subject: [PATCH 521/542] Bump k8s.io/klog/v2 from 2.110.1 to 2.120.0 Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.110.1 to 2.120.0. - [Release notes](https://github.com/kubernetes/klog/releases) - [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes/klog/compare/v2.110.1...v2.120.0) --- updated-dependencies: - dependency-name: k8s.io/klog/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index ddc074ff..1e64f82d 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.29.0 - k8s.io/klog/v2 v2.110.1 + k8s.io/klog/v2 v2.120.0 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.4.0 ) @@ -52,7 +52,7 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect diff --git a/go.sum b/go.sum index b5e23324..f9d953be 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -794,8 +794,8 @@ k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/klog/v2 v2.120.0 h1:z+q5mfovBj1fKFxiRzsa2DsJLPIVMk/KFL81LMOfK+8= +k8s.io/klog/v2 v2.120.0/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From 7f67c71582d65a8d4a9dd16b73ad15a1c1907682 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 02:47:32 +0000 Subject: [PATCH 522/542] Bump anchore/sbom-action from 0.15.1 to 0.15.3 Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.1 to 0.15.3. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Commits](https://github.com/anchore/sbom-action/compare/v0.15.1...v0.15.3) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index b4fb5af5..b74cf839 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -26,6 +26,6 @@ jobs: with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action - uses: anchore/sbom-action@v0.15.1 + uses: anchore/sbom-action@v0.15.3 with: format: cyclonedx-json From c3209d5c17ffad4786531180426b5cb555f8f5ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 03:01:12 +0000 Subject: [PATCH 523/542] Bump golang from 1.21.5-alpine3.18 to 1.21.6-alpine3.18 Bumps golang from 1.21.5-alpine3.18 to 1.21.6-alpine3.18. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile_iptables | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6092cb05..5ff57485 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.5-alpine3.18 as dev +FROM golang:1.21.6-alpine3.18 as dev RUN apk add --no-cache git ca-certificates make RUN adduser -D appuser COPY . /src/ diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 1a37c65c..6e3c2214 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:experimental -FROM golang:1.21.5-alpine3.18 as dev +FROM golang:1.21.6-alpine3.18 as dev RUN apk add --no-cache git make RUN adduser -D appuser COPY . /src/ From 3d559ba0ce801a8c8329178ca2be3f2147161e97 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Tue, 5 Dec 2023 16:44:29 +0100 Subject: [PATCH 524/542] Minimal implementation of DualStack Services support Signed-off-by: Patryk Strusiewicz-Surmacki --- cmd/kube-vip.go | 2 + pkg/cluster/cluster.go | 24 +- pkg/cluster/clusterDDNS.go | 15 +- pkg/cluster/clusterLeaderElection.go | 17 +- pkg/cluster/service.go | 342 ++++++++++++++------------- pkg/cluster/singleNode.go | 43 ++-- pkg/kubevip/config_environment.go | 16 ++ pkg/kubevip/config_envvar.go | 6 + pkg/kubevip/config_generator.go | 22 ++ pkg/kubevip/config_types.go | 6 + pkg/manager/instance.go | 9 +- pkg/manager/manager_arp.go | 3 +- pkg/manager/service_egress.go | 46 +++- pkg/manager/services.go | 188 ++++++++++----- pkg/manager/servicesLeader.go | 4 +- pkg/manager/watch_endpoints.go | 29 ++- pkg/manager/watch_endpointslices.go | 55 ++++- pkg/manager/watch_services.go | 23 +- pkg/vip/address.go | 84 ++++--- pkg/vip/dns.go | 11 +- pkg/vip/egress.go | 12 +- pkg/vip/util.go | 75 +++++- testing/e2e/e2e_test.go | 85 ++++++- testing/e2e/ip.go | 4 + testing/e2e/services/kind.go | 8 +- testing/e2e/services/tests.go | 1 + 26 files changed, 778 insertions(+), 352 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index ae42574f..7ab33d4a 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -138,6 +138,8 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableServiceSecurity, "onlyAllowTrafficServicePorts", false, "Only allow traffic to service ports, others will be dropped, defaults to false") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)") + kubeVipCmd.PersistentFlags().StringVar(&initConfig.DNSMode, "dnsMode", "first", "Name of the mode that DNS lookup will be performed (first, ipv4, ipv6, dual)") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DisableServiceUpdates, "disableServiceUpdates", false, "If true, kube-vip will process services as usal, but will not update service's Status.LoadBalancer.Ingress slice") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpointSlices, "enableEndpointSlices", false, "If enabled, kube-vip will only advertise services, but will use EndpointSlices instead of endpoints to get IPs of Pods") // Prometheus HTTP Server diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 1a45e4c4..f4ca0c6f 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -14,24 +14,24 @@ type Cluster struct { stop chan bool completed chan bool once sync.Once - Network vip.Network + Network []vip.Network } // InitCluster - Will attempt to initialise all of the required settings for the cluster func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) { - var network vip.Network + var networks []vip.Network var err error if !disableVIP { // Start the Virtual IP Networking configuration - network, err = startNetworking(c) + networks, err = startNetworking(c) if err != nil { return nil, err } } // Initialise the Cluster structure newCluster := &Cluster{ - Network: network, + Network: networks, } log.Debugf("init enable service security: %t", c.EnableServiceSecurity) @@ -39,19 +39,25 @@ func InitCluster(c *kubevip.Config, disableVIP bool) (*Cluster, error) { return newCluster, nil } -func startNetworking(c *kubevip.Config) (vip.Network, error) { +func startNetworking(c *kubevip.Config) ([]vip.Network, error) { address := c.VIP if c.Address != "" { address = c.Address } - network, err := vip.NewConfig(address, c.Interface, c.VIPSubnet, c.DDNS, c.RoutingTableID, c.RoutingTableType) - if err != nil { - return nil, err + addresses := vip.GetIPs(address) + + networks := []vip.Network{} + for _, addr := range addresses { + network, err := vip.NewConfig(addr, c.Interface, c.VIPSubnet, c.DDNS, c.RoutingTableID, c.RoutingTableType, c.DNSMode) + if err != nil { + return nil, err + } + networks = append(networks, network...) } - return network, nil + return networks, nil } // Stop - Will stop the Cluster and release VIP if needed diff --git a/pkg/cluster/clusterDDNS.go b/pkg/cluster/clusterDDNS.go index ebacad42..0cf21be5 100644 --- a/pkg/cluster/clusterDDNS.go +++ b/pkg/cluster/clusterDDNS.go @@ -13,11 +13,16 @@ import ( // dnsUpdater already have the functionality to keep trying resolve the IP // and update the VIP configuration if it changes func (cluster *Cluster) StartDDNS(ctx context.Context) error { - ddnsMgr := vip.NewDDNSManager(ctx, cluster.Network) - ip, err := ddnsMgr.Start() - if err != nil { - return err + for i := range cluster.Network { + ddnsMgr := vip.NewDDNSManager(ctx, cluster.Network[i]) + ip, err := ddnsMgr.Start() + if err != nil { + return err + } + if err = cluster.Network[i].SetIP(ip); err != nil { + return err + } } - return cluster.Network.SetIP(ip) + return nil } diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index 9d8501f3..1eebb02c 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -117,9 +117,12 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * }() // (attempt to) Remove the virtual IP, in case it already exists - err = cluster.Network.DeleteIP() - if err != nil { - log.Errorf("could not delete virtualIP: %v", err) + + for i := range cluster.Network { + err = cluster.Network[i].DeleteIP() + if err != nil { + log.Errorf("could not delete virtualIP: %v", err) + } } // Defer a function to check if the bgpServer has been created and if so attempt to close it @@ -195,9 +198,11 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * } } - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) + for i := range cluster.Network { + err := cluster.Network[i].DeleteIP() + if err != nil { + log.Warnf("%v", err) + } } log.Fatal("lost leadership, restarting kube-vip") diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index c5077a7c..0d657a98 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -33,108 +33,111 @@ func (cluster *Cluster) vipService(ctxArp, ctxDNS context.Context, c *kubevip.Co // Add Notification for SIGTERM (sent from Kubernetes) signal.Notify(signalChan, syscall.SIGTERM) - if cluster.Network.IsDDNS() { - if err := cluster.StartDDNS(ctxDNS); err != nil { - log.Error(err) - } - } - - // start the dns updater if address is dns - if cluster.Network.IsDNS() { - log.Infof("starting the DNS updater for the address %s", cluster.Network.DNSName()) - ipUpdater := vip.NewIPUpdater(cluster.Network) - ipUpdater.Run(ctxDNS) - } - - err = cluster.Network.AddIP() - if err != nil { - log.Fatalf("%v", err) - } + for i := range cluster.Network { - if c.EnableMetal { - // 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") - err = equinixmetal.AttachEIP(packetClient, c, id) - if err != nil { + if cluster.Network[i].IsDDNS() { + if err := cluster.StartDDNS(ctxDNS); err != nil { log.Error(err) } } - } - - 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.IP(), c.VIPCIDR) - log.Debugf("Attempting to advertise the address [%s] over BGP", cidrVip) - err = bgpServer.AddHost(cidrVip) - if err != nil { - log.Error(err) + // 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()) + ipUpdater := vip.NewIPUpdater(cluster.Network[i]) + ipUpdater.Run(ctxDNS) } - } - - if c.EnableLoadBalancer { - log.Infof("Starting IPVS LoadBalancer") - - lb, err := loadbalancer.NewIPVSLB(cluster.Network.IP(), c.LoadBalancerPort, c.LoadBalancerForwardingMethod) + err = cluster.Network[i].AddIP() if err != nil { - log.Errorf("Error creating IPVS LoadBalancer [%s]", err) + log.Fatalf("%v", err) } - go func() { - err = sm.NodeWatcher(lb, c.Port) - if err != nil { - log.Errorf("Error watching node labels [%s]", err) + if c.EnableMetal { + // 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") + err = equinixmetal.AttachEIP(packetClient, c, id) + if err != nil { + log.Error(err) + } } - }() - // Shutdown function that will wait on this signal, unless we call it ourselves - go func() { - <-signalChan - err = lb.RemoveIPVSLB() + } + + 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) + + err = bgpServer.AddHost(cidrVip) if err != nil { - log.Errorf("Error stopping IPVS LoadBalancer [%s]", err) + log.Error(err) } - log.Info("Stopping IPVS LoadBalancer") - }() - } + } - if c.EnableARP { - // ctxArp, cancelArp = context.WithCancel(context.Background()) + if c.EnableLoadBalancer { - ipString := cluster.Network.IP() - isIPv6 := vip.IsIPv6(ipString) + log.Infof("Starting IPVS LoadBalancer") - var ndp *vip.NdpResponder - if isIPv6 { - ndp, err = vip.NewNDPResponder(c.Interface) + lb, err := loadbalancer.NewIPVSLB(cluster.Network[i].IP(), c.LoadBalancerPort, c.LoadBalancerForwardingMethod) if err != nil { - log.Fatalf("failed to create new NDP Responder") + log.Errorf("Error creating IPVS LoadBalancer [%s]", err) } + + go func() { + err = sm.NodeWatcher(lb, c.Port) + if err != nil { + log.Errorf("Error watching node labels [%s]", err) + } + }() + // Shutdown function that will wait on this signal, unless we call it ourselves + go func() { + <-signalChan + err = lb.RemoveIPVSLB() + if err != nil { + log.Errorf("Error stopping IPVS LoadBalancer [%s]", err) + } + log.Info("Stopping IPVS LoadBalancer") + }() } - go func(ctx context.Context) { - if ndp != nil { - defer ndp.Close() - } - log.Infof("Gratuitous Arp broadcast will repeat every 3 seconds for [%s]", ipString) - for { - select { - case <-ctx.Done(): // if cancel() execute - return - default: - cluster.ensureIPAndSendGratuitous(c.Interface, ndp) + if c.EnableARP { + // ctxArp, cancelArp = context.WithCancel(context.Background()) + + go func(ctx context.Context) { + ipString := cluster.Network[i].IP() + isIPv6 := vip.IsIPv6(ipString) + + var ndp *vip.NdpResponder + if isIPv6 { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } } - time.Sleep(3 * time.Second) - } - }(ctxArp) - } - if c.EnableRoutingTable { - err = cluster.Network.AddRoute() - if err != nil { - log.Warnf("%v", err) + if ndp != nil { + defer ndp.Close() + } + log.Infof("Gratuitous Arp broadcast will repeat every 3 seconds for [%s]", ipString) + for { + select { + case <-ctx.Done(): // if cancel() execute + return + default: + cluster.ensureIPAndSendGratuitous(c.Interface, ndp) + } + time.Sleep(3 * time.Second) + } + }(ctxArp) + } + + if c.EnableRoutingTable { + err = cluster.Network[i].AddRoute() + if err != nil { + log.Warnf("%v", err) + } } } @@ -151,63 +154,68 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("Attempted to clean existing VIP => %v", err) - } - if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) { - err = cluster.Network.AddRoute() - if err != nil { - log.Warnf("%v", err) - } - } else if !c.EnableRoutingTable { - err = cluster.Network.AddIP() + for i := range cluster.Network { + network := cluster.Network[i] + + err := network.DeleteIP() if err != nil { - log.Warnf("%v", err) + log.Warnf("Attempted to clean existing VIP => %v", err) } - } - if c.EnableARP { - // ctxArp, cancelArp = context.WithCancel(context.Background()) - - ipString := cluster.Network.IP() - - var ndp *vip.NdpResponder - if vip.IsIPv6(ipString) { - ndp, err = vip.NewNDPResponder(c.Interface) + if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) { + err = network.AddRoute() if err != nil { - log.Fatalf("failed to create new NDP Responder") + log.Warnf("%v", err) + } + } else if !c.EnableRoutingTable { + err = network.AddIP() + if err != nil { + log.Warnf("%v", err) } } - go func(ctx context.Context) { - if ndp != nil { - defer ndp.Close() + + if c.EnableARP { + // ctxArp, cancelArp = context.WithCancel(context.Background()) + + ipString := network.IP() + + var ndp *vip.NdpResponder + if vip.IsIPv6(ipString) { + ndp, err = vip.NewNDPResponder(c.Interface) + if err != nil { + log.Fatalf("failed to create new NDP Responder") + } } - log.Debugf("(svcs) broadcasting ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) - - for { - select { - case <-ctx.Done(): // if cancel() execute - log.Debugf("(svcs) ending ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) - return - default: - cluster.ensureIPAndSendGratuitous(c.Interface, ndp) + go func(ctx context.Context) { + if ndp != nil { + defer ndp.Close() } - if c.ArpBroadcastRate < 500 { - log.Errorf("arp broadcast rate is [%d], this shouldn't be lower that 300ms (defaulting to 3000)", c.ArpBroadcastRate) - c.ArpBroadcastRate = 3000 + log.Debugf("(svcs) broadcasting ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) + + for { + select { + case <-ctx.Done(): // if cancel() execute + log.Debugf("(svcs) ending ARP update for %s via %s, every %dms", ipString, c.Interface, c.ArpBroadcastRate) + return + default: + cluster.ensureIPAndSendGratuitous(c.Interface, ndp) + } + if c.ArpBroadcastRate < 500 { + log.Errorf("arp broadcast rate is [%d], this shouldn't be lower that 300ms (defaulting to 3000)", c.ArpBroadcastRate) + c.ArpBroadcastRate = 3000 + } + time.Sleep(time.Duration(c.ArpBroadcastRate) * time.Millisecond) } - time.Sleep(time.Duration(c.ArpBroadcastRate) * time.Millisecond) - } - }(ctxArp) - } + }(ctxArp) + } - 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.IP(), c.VIPCIDR) - log.Debugf("(svcs) attempting to advertise the address [%s] over BGP", cidrVip) - err = bgp.AddHost(cidrVip) - if err != nil { - log.Error(err) + if c.EnableBGP { + // 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) + err = bgp.AddHost(cidrVip) + if err != nil { + log.Error(err) + } } } @@ -217,9 +225,10 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser cancelArp() if c.EnableRoutingTable && (c.EnableLeaderElection || c.EnableServicesElection) { - err = cluster.Network.DeleteRoute() - if err != nil { - log.Warnf("%v", err) + for i := range cluster.Network { + if err := cluster.Network[i].DeleteRoute(); err != nil { + log.Warnf("%v", err) + } } close(cluster.completed) @@ -227,10 +236,12 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser } log.Info("[LOADBALANCER] Stopping load balancers") - log.Infof("[VIP] Releasing the Virtual IP [%s]", c.VIP) - err = cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) + + for i := range cluster.Network { + log.Infof("[VIP] Releasing the Virtual IP [%s]", cluster.Network[i].IP()) + if err := cluster.Network[i].DeleteIP(); err != nil { + log.Warnf("%v", err) + } } close(cluster.completed) @@ -241,41 +252,44 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser // either a gratuitous ARP or gratuitous NDP. Re-adds the interface if it is IPv6 // and in a dadfailed state. func (cluster *Cluster) ensureIPAndSendGratuitous(iface string, ndp *vip.NdpResponder) { - ipString := cluster.Network.IP() - isIPv6 := vip.IsIPv6(ipString) - // Check if IP is dadfailed - if cluster.Network.IsDADFAIL() { - log.Warnf("IP address is in dadfailed state, removing [%s] from interface [%s]", ipString, iface) - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) + for i := range cluster.Network { + ipString := cluster.Network[i].IP() + isIPv6 := vip.IsIPv6(ipString) + // Check if IP is dadfailed + if cluster.Network[i].IsDADFAIL() { + log.Warnf("IP address is in dadfailed state, removing [%s] from interface [%s]", ipString, iface) + err := cluster.Network[i].DeleteIP() + if err != nil { + log.Warnf("%v", err) + } } - } - // Ensure the address exists on the interface before attempting to ARP - set, err := cluster.Network.IsSet() - if err != nil { - log.Warnf("%v", err) - } - if !set { - log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, iface) - err = cluster.Network.AddIP() + // Ensure the address exists on the interface before attempting to ARP + set, err := cluster.Network[i].IsSet() if err != nil { log.Warnf("%v", err) } - } - - if isIPv6 { - // Gratuitous NDP, will broadcast new MAC <-> IPv6 address - err := ndp.SendGratuitous(ipString) - if err != nil { - log.Warnf("%v", err) + if !set { + log.Warnf("Re-applying the VIP configuration [%s] to the interface [%s]", ipString, iface) + err = cluster.Network[i].AddIP() + if err != nil { + log.Warnf("%v", err) + } } - } else { - // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address - err := vip.ARPSendGratuitous(ipString, iface) - if err != nil { - log.Warnf("%v", err) + + if isIPv6 { + // Gratuitous NDP, will broadcast new MAC <-> IPv6 address + err := ndp.SendGratuitous(ipString) + if err != nil { + log.Warnf("%v", err) + } + } else { + // Gratuitous ARP, will broadcast to new MAC <-> IPv4 address + err := vip.ARPSendGratuitous(ipString, iface) + if err != nil { + log.Warnf("%v", err) + } } } + } diff --git a/pkg/cluster/singleNode.go b/pkg/cluster/singleNode.go index e7d871d3..da983a8f 100644 --- a/pkg/cluster/singleNode.go +++ b/pkg/cluster/singleNode.go @@ -23,24 +23,26 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro cluster.stop = make(chan bool, 1) cluster.completed = make(chan bool, 1) - if !disableVIP { - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("Attempted to clean existing VIP => %v", err) - } + for i := range cluster.Network { + if !disableVIP { + err := cluster.Network[i].DeleteIP() + if err != nil { + log.Warnf("Attempted to clean existing VIP => %v", err) + } - err = cluster.Network.AddIP() - if err != nil { - log.Warnf("%v", err) - } + err = cluster.Network[i].AddIP() + if err != nil { + log.Warnf("%v", err) + } - } + } - if c.EnableARP { - // Gratuitous ARP, will broadcast to new MAC <-> IP - err := vip.ARPSendGratuitous(cluster.Network.IP(), c.Interface) - if err != nil { - log.Warnf("%v", err) + if c.EnableARP { + // Gratuitous ARP, will broadcast to new MAC <-> IP + err := vip.ARPSendGratuitous(cluster.Network[i].IP(), c.Interface) + if err != nil { + log.Warnf("%v", err) + } } } @@ -48,11 +50,12 @@ func (cluster *Cluster) StartSingleNode(c *kubevip.Config, disableVIP bool) erro <-cluster.stop if !disableVIP { - - log.Info("[VIP] Releasing the Virtual IP") - err := cluster.Network.DeleteIP() - if err != nil { - log.Warnf("%v", err) + for i := range cluster.Network { + log.Infof("[VIP] Releasing the Virtual IP [%s]", cluster.Network[i].IP()) + err := cluster.Network[i].DeleteIP() + if err != nil { + log.Warnf("%v", err) + } } } close(cluster.completed) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 8dd449eb..1f820421 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -313,6 +313,22 @@ func ParseEnvironment(c *Config) error { c.RoutingTableType = int(i) } + // DNS mode + env = os.Getenv(dnsMode) + if env != "" { + c.DNSMode = env + } + + // Disable updates for services (status.LoadBalancer.Ingress will not be updated) + env = os.Getenv(disableServiceUpdates) + if env != "" { + b, err := strconv.ParseBool(env) + if err != nil { + return err + } + c.DisableServiceUpdates = b + } + // BGP Server options env = os.Getenv(bgpEnable) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 08f362a4..aa3de266 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -187,6 +187,12 @@ const ( //k8sConfigFile defines the path to the configfile used to speak with the API server k8sConfigFile = "k8s_config_file" + // dnsMode defines mode that DNS lookup will be performed with (first, ipv4, ipv6, dual) + dnsMode = "dns_mode" + + // disableServiceUpdates disables service updating + disableServiceUpdates = "disable_service_updates" + // enableEndpointSlices enables use of EndpointSlices instead of Endpoints enableEndpointSlices = "enable_endpointslices" ) diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index b60a82a4..3d6e5373 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -170,6 +170,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod newEnvironment = append(newEnvironment, cidr...) } + if c.DNSMode != "" { + // build environment variables + dnsModeSelector := []corev1.EnvVar{ + { + Name: dnsMode, + Value: c.DNSMode, + }, + } + newEnvironment = append(newEnvironment, dnsModeSelector...) + } + // If we're doing the hybrid mode if c.EnableControlPlane { cp := []corev1.EnvVar{ @@ -483,6 +494,17 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod }) } + if c.DisableServiceUpdates { + // Disable service updates + disServiceUpdates := []corev1.EnvVar{ + { + Name: disableServiceUpdates, + Value: strconv.FormatBool(c.DisableServiceUpdates), + }, + } + newEnvironment = append(newEnvironment, disServiceUpdates...) + } + newManifest := &corev1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 08994c02..1edaa452 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -158,6 +158,12 @@ type Config struct { // K8sConfigFile, this is the path to the config file used to speak with the API server K8sConfigFile string `yaml:"k8sConfigFile"` + // DNSMode, this will set the mode DSN lookup will be performed (first, ipv4, ipv6, dual) + DNSMode string `yaml:"dnsDualStackMode"` + + // DisableServiceUpdates, if true, kube-vip will only advertise service, but it will not update service's Status.LoadBalancer.Ingress slice + DisableServiceUpdates bool `yaml:"disableServiceUpdates"` + // EnableEndpointSlices, if enabled, EndpointSlices will be used instead of Endpoints EnableEndpointSlices bool `yaml:"enableEndpointSlices"` } diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 488d6f18..ce5b2fee 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -67,6 +67,8 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { RoutingTableType: config.RoutingTableType, ArpBroadcastRate: config.ArpBroadcastRate, EnableServiceSecurity: config.EnableServiceSecurity, + DNSMode: config.DNSMode, + DisableServiceUpdates: config.DisableServiceUpdates, }) } @@ -124,9 +126,12 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { log.Errorf("Failed to add Service %s/%s", svc.Namespace, svc.Name) return nil, err } - c.Network.SetServicePorts(svc) - instance.clusters = append(instance.clusters, c) + for i := range c.Network { + c.Network[i].SetServicePorts(svc) + } + + instance.clusters = append(instance.clusters, c) } return instance, nil diff --git a/pkg/manager/manager_arp.go b/pkg/manager/manager_arp.go index 477fc5b8..4a963a03 100644 --- a/pkg/manager/manager_arp.go +++ b/pkg/manager/manager_arp.go @@ -14,6 +14,7 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" "github.com/kube-vip/kube-vip/pkg/cluster" + "github.com/kube-vip/kube-vip/pkg/iptables" "github.com/kube-vip/kube-vip/pkg/vip" ) @@ -102,7 +103,7 @@ func (sm *Manager) startARP() error { // This will tidy any dangling kube-vip iptables rules if os.Getenv("EGRESS_CLEAN") != "" { - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, sm.config.ServiceNamespace) + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, sm.config.ServiceNamespace, iptables.ProtocolIPv4) if err != nil { log.Warnf("(egress) Unable to clean any dangling egress rules [%v]", err) log.Warn("(egress) Can be ignored in non iptables release of kube-vip") diff --git a/pkg/manager/service_egress.go b/pkg/manager/service_egress.go index c0c0dfdb..dc2b803c 100644 --- a/pkg/manager/service_egress.go +++ b/pkg/manager/service_egress.go @@ -7,6 +7,7 @@ import ( "os" "strings" + "github.com/kube-vip/kube-vip/pkg/iptables" "github.com/kube-vip/kube-vip/pkg/vip" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -43,6 +44,16 @@ func (sm *Manager) iptablesCheck() error { return nil } +func getSameFamilyCidr(source, ip string) string { + cidrs := strings.Split(source, ",") + for _, cidr := range cidrs { + if vip.IsIPv4(cidr) == vip.IsIPv4(ip) { + return cidr + } + } + return "" +} + func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, namespace string) error { // serviceCIDR, podCIDR, err := sm.AutoDiscoverCIDRs() // if err != nil { @@ -53,18 +64,32 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, namespace str var podCidr, serviceCidr string if sm.config.EgressPodCidr != "" { - podCidr = sm.config.EgressPodCidr + podCidr = getSameFamilyCidr(sm.config.EgressPodCidr, podIP) } else { + // There's no default IPv6 pod CIDR, therefore we silently back off if CIDR s not specified. + if !vip.IsIPv4(podIP) { + return nil + } podCidr = defaultPodCIDR } if sm.config.EgressServiceCidr != "" { - serviceCidr = sm.config.EgressServiceCidr + serviceCidr = getSameFamilyCidr(sm.config.EgressServiceCidr, vipIP) } else { + // There's no default IPv6 service CIDR, therefore we silently back off if CIDR s not specified. + if !vip.IsIPv4(vipIP) { + return nil + } serviceCidr = defaultServiceCIDR } - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace) + protocol := iptables.ProtocolIPv4 + + if vip.IsIPv6(vipIP) { + protocol = iptables.ProtocolIPv6 + } + + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace, protocol) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } @@ -88,7 +113,13 @@ func (sm *Manager) configureEgress(vipIP, podIP, destinationPorts, namespace str if err != nil { return fmt.Errorf("error adding rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } - err = i.AppendReturnRulesForMarking(vip.MangleChainName, podIP+"/32") + + mask := "/32" + if !vip.IsIPv4(podIP) { + mask = "/128" + } + + err = i.AppendReturnRulesForMarking(vip.MangleChainName, podIP+mask) if err != nil { return fmt.Errorf("error adding marking rules to mangle chain [%s], error [%s]", vip.MangleChainName, err) } @@ -158,7 +189,12 @@ func (sm *Manager) AutoDiscoverCIDRs() (serviceCIDR, podCIDR string, err error) } func (sm *Manager) TeardownEgress(podIP, vipIP, destinationPorts, namespace string) error { - i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace) + protocol := iptables.ProtocolIPv4 + if vip.IsIPv6(podIP) { + protocol = iptables.ProtocolIPv6 + } + + i, err := vip.CreateIptablesClient(sm.config.EgressWithNftables, namespace, protocol) if err != nil { return fmt.Errorf("error Creating iptables client [%s]", err) } diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 494897ad..e8b307bd 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "slices" "strings" "sync" "time" @@ -26,6 +27,7 @@ const ( egressDestinationPorts = "kube-vip.io/egress-destination-ports" egressSourcePorts = "kube-vip.io/egress-source-ports" activeEndpoint = "kube-vip.io/active-endpoint" + activeEndpointIPv6 = "kube-vip.io/active-endpoint-ipv6" flushContrack = "kube-vip.io/flush-conntrack" loadbalancerIPAnnotation = "kube-vip.io/loadbalancerIPs" loadbalancerHostname = "kube-vip.io/loadbalancerHostname" @@ -41,33 +43,40 @@ func (sm *Manager) syncServices(_ context.Context, svc *v1.Service, wg *sync.Wai newServiceAddresses := fetchServiceAddresses(svc) newServiceUID := string(svc.UID) - firstServiceAddress := "" - if len(newServiceAddresses) > 0 { - firstServiceAddress = newServiceAddresses[0] + ingressIPs := []string{} + + for _, ingress := range svc.Status.LoadBalancer.Ingress { + ingressIPs = append(ingressIPs, ingress.IP) } + shouldBreake := false + for x := range sm.serviceInstances { - if sm.serviceInstances[x].UID == newServiceUID { - log.Debugf("isDHCP: %t, newServiceAddresses: %s", sm.serviceInstances[x].isDHCP, newServiceAddresses) - // If the found instance's DHCP configuration doesn't match the new service, delete it. - if (sm.serviceInstances[x].isDHCP && firstServiceAddress != "0.0.0.0") || - (!sm.serviceInstances[x].isDHCP && firstServiceAddress == "0.0.0.0") || - (!sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && - firstServiceAddress != svc.Status.LoadBalancer.Ingress[0].IP) || - (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) || - (sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && - sm.serviceInstances[x].dhcpInterfaceIP != svc.Status.LoadBalancer.Ingress[0].IP) { - if err := sm.deleteService(newServiceUID); err != nil { - return err + if shouldBreake { + break + } + for _, newServiceAddress := range newServiceAddresses { + log.Debugf("isDHCP: %t, newServiceAddress: %s", sm.serviceInstances[x].isDHCP, newServiceAddress) + if sm.serviceInstances[x].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") || + (!sm.serviceInstances[x].isDHCP && newServiceAddress == "0.0.0.0") || + (!sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && !slices.Contains(ingressIPs, newServiceAddress)) || + (len(svc.Status.LoadBalancer.Ingress) > 0 && !comparePortsAndPortStatuses(svc)) || + (sm.serviceInstances[x].isDHCP && len(svc.Status.LoadBalancer.Ingress) > 0 && !slices.Contains(ingressIPs, sm.serviceInstances[x].dhcpInterfaceIP)) { + if err := sm.deleteService(newServiceUID); err != nil { + return err + } + shouldBreake = true + break } - break + foundInstance = true } - foundInstance = true } } // This instance wasn't found, we need to add it to the manager - if !foundInstance && firstServiceAddress != "" { + if !foundInstance && len(newServiceAddresses) > 0 { if err := sm.addService(svc); err != nil { return err } @@ -97,7 +106,7 @@ func (sm *Manager) addService(svc *v1.Service) error { return err } - log.Infof("(svcs) adding VIP(s) [%s] for [%s/%s]", newService.VIPs, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + log.Infof("(svcs) adding VIP [%s] for [%s/%s]", newService.VIPs, newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) for x := range newService.vipConfigs { newService.clusters[x].StartLoadBalancerService(newService.vipConfigs[x], sm.bgpServer) @@ -111,8 +120,10 @@ func (sm *Manager) addService(svc *v1.Service) error { log.Debugf("IP %s may have changed", ip) newService.vipConfigs[0].VIP = ip newService.dhcpInterfaceIP = ip - if err := sm.updateStatus(newService); err != nil { - log.Warnf("error updating svc: %s", err) + if !sm.config.DisableServiceUpdates { + if err := sm.updateStatus(newService); err != nil { + log.Warnf("error updating svc: %s", err) + } } } log.Debugf("IP update channel closed, stopping") @@ -121,51 +132,70 @@ func (sm *Manager) addService(svc *v1.Service) error { sm.serviceInstances = append(sm.serviceInstances, newService) - if err := sm.updateStatus(newService); err != nil { - // delete service to collect garbage - if deleteErr := sm.deleteService(newService.UID); err != nil { - return deleteErr + if !sm.config.DisableServiceUpdates { + log.Debugf("(svcs) will update [%s/%s]", newService.serviceSnapshot.Namespace, newService.serviceSnapshot.Name) + if err := sm.updateStatus(newService); err != nil { + // delete service to collect garbage + if deleteErr := sm.deleteService(newService.UID); err != nil { + return deleteErr + } + return err } - return err } - // TODO: Currently this only implements egress for the primary load balancer - // IP of the service serviceIPs := fetchServiceAddresses(svc) // Check if we need to flush any conntrack connections (due to some dangling conntrack connections) - if svc.Annotations[flushContrack] == "true" && len(serviceIPs) > 0 { + if svc.Annotations[flushContrack] == "true" { log.Debugf("Flushing conntrack rules for service [%s]", svc.Name) - serviceIP := serviceIPs[0] - err = vip.DeleteExistingSessions(serviceIP, false) - if err != nil { - log.Errorf("Error flushing any remaining egress connections [%s]", err) - } - err = vip.DeleteExistingSessions(serviceIP, true) - if err != nil { - log.Errorf("Error flushing any remaining ingress connections [%s]", err) + for _, serviceIP := range serviceIPs { + err = vip.DeleteExistingSessions(serviceIP, false) + if err != nil { + log.Errorf("Error flushing any remaining egress connections [%s]", err) + } + err = vip.DeleteExistingSessions(serviceIP, true) + if err != nil { + log.Errorf("Error flushing any remaining ingress connections [%s]", 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) - serviceIP := serviceIPs[0] if svc.Annotations[activeEndpoint] != "" { // We will need to modify the iptables rules err = sm.iptablesCheck() if err != nil { log.Errorf("Error configuring egress for loadbalancer [%s]", err) } - err = sm.configureEgress(serviceIP, svc.Annotations[activeEndpoint], svc.Annotations[egressDestinationPorts], svc.Namespace) - if err != nil { - log.Errorf("Error configuring egress for loadbalancer [%s]", err) - } else { - err = sm.updateServiceEndpointAnnotation(svc.Annotations[activeEndpoint], svc) + errList := []error{} + for _, serviceIP := range serviceIPs { + podIPs := svc.Annotations[activeEndpoint] + if sm.config.EnableEndpointSlices && vip.IsIPv6(serviceIP) { + podIPs = svc.Annotations[activeEndpointIPv6] + } + err = sm.configureEgress(serviceIP, podIPs, svc.Annotations[egressDestinationPorts], svc.Namespace) if err != nil { - log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) + errList = append(errList, err) + log.Errorf("Error configuring egress for loadbalancer [%s]", err) } } + if len(errList) == 0 { + if !sm.config.EnableEndpointSlices { + err = sm.updateServiceEndpointAnnotation(svc.Annotations[activeEndpoint], svc) + if err != nil { + log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) + } + } else { + err = sm.updateServiceEndpointSlicesAnnotation(svc.Annotations[activeEndpoint], + svc.Annotations[activeEndpointIPv6], svc) + if err != nil { + log.Errorf("Error configuring egress annotation for loadbalancer [%s]", err) + } + } + + } } } @@ -238,7 +268,6 @@ func (sm *Manager) deleteService(uid string) error { // 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) err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[activeEndpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) if err != nil { @@ -259,14 +288,16 @@ func (sm *Manager) deleteService(uid string) error { func (sm *Manager) upnpMap(s *Instance) { // If upnp is enabled then update the gateway/router with the address // TODO - work out if we need to mapping.Reclaim() - // TODO: Handle upnp in the dualstack case - if sm.upnp != nil && len(s.VIPs) == 1 { - log.Infof("[UPNP] Adding map to [%s:%d - %s]", s.VIPs[0], s.Port, s.serviceSnapshot.Name) - if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, s.VIPs[0], strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { - log.Infof("service should be accessible externally on port [%d]", s.Port) - } else { - sm.upnp.Reclaim() - log.Errorf("unable to map port to gateway [%s]", err.Error()) + // TODO - check if this implementation for dualstack is correct + if sm.upnp != nil { + for _, vip := range s.VIPs { + log.Infof("[UPNP] Adding map to [%s:%d - %s]", vip, s.Port, s.serviceSnapshot.Name) + if err := sm.upnp.AddPortMapping(int(s.Port), int(s.Port), 0, vip, strings.ToUpper(s.Type), s.serviceSnapshot.Name); err == nil { + log.Infof("service should be accessible externally on port [%d]", s.Port) + } else { + sm.upnp.Reclaim() + log.Errorf("unable to map port to gateway [%s]", err.Error()) + } } } } @@ -307,6 +338,7 @@ func (sm *Manager) updateStatus(i *Instance) error { return err } } + ports := make([]v1.PortStatus, 0, len(i.serviceSnapshot.Spec.Ports)) for _, port := range i.serviceSnapshot.Spec.Ports { ports = append(ports, v1.PortStatus{ @@ -314,12 +346,29 @@ func (sm *Manager) updateStatus(i *Instance) error { Protocol: port.Protocol, }) } - var ingresses []v1.LoadBalancerIngress - for _, vipConfig := range i.vipConfigs { - ingresses = append(ingresses, v1.LoadBalancerIngress{ - IP: vipConfig.VIP, - Ports: ports, - }) + + ingresses := []v1.LoadBalancerIngress{} + + for _, c := range i.vipConfigs { + if !vip.IsIP(c.VIP) { + ips, err := vip.LookupHost(c.VIP, sm.config.DNSMode) + if err != nil { + return err + } + for _, ip := range ips { + i := v1.LoadBalancerIngress{ + IP: ip, + Ports: ports, + } + ingresses = append(ingresses, i) + } + } else { + i := v1.LoadBalancerIngress{ + IP: c.VIP, + Ports: ports, + } + ingresses = append(ingresses, i) + } } if !cmp.Equal(currentService.Status.LoadBalancer.Ingress, ingresses) { currentService.Status.LoadBalancer.Ingress = ingresses @@ -341,10 +390,10 @@ func (sm *Manager) updateStatus(i *Instance) error { // fetchServiceAddresses tries to get the addresses from annotations // kube-vip.io/loadbalancerIPs, then from spec.loadbalancerIP -// May return []string{""} (with length 1) if neither exist. func fetchServiceAddresses(s *v1.Service) []string { + annotationAvailable := false if s.Annotations != nil { - if v, ok := s.Annotations[loadbalancerIPAnnotation]; ok { + if v, annotationAvailable := s.Annotations[loadbalancerIPAnnotation]; annotationAvailable { ips := strings.Split(v, ",") var trimmedIPs []string for _, ip := range ips { @@ -353,5 +402,20 @@ func fetchServiceAddresses(s *v1.Service) []string { return trimmedIPs } } - return []string{s.Spec.LoadBalancerIP} + + if !annotationAvailable { + if len(s.Status.LoadBalancer.Ingress) > 0 { + addresses := []string{} + for _, ingress := range s.Status.LoadBalancer.Ingress { + addresses = append(addresses, ingress.IP) + } + return addresses + } + } + + if s.Spec.LoadBalancerIP != "" { + return []string{s.Spec.LoadBalancerIP} + } + + return []string{} } diff --git a/pkg/manager/servicesLeader.go b/pkg/manager/servicesLeader.go index e953ae79..1904a17f 100644 --- a/pkg/manager/servicesLeader.go +++ b/pkg/manager/servicesLeader.go @@ -24,7 +24,9 @@ func (sm *Manager) startServicesWatchForLeaderElection(ctx context.Context) erro for _, instance := range sm.serviceInstances { for _, cluster := range instance.clusters { - _ = cluster.Network.DeleteRoute() + for i := range cluster.Network { + _ = cluster.Network[i].DeleteRoute() + } cluster.Stop() } } diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index c2489c0e..4f7012ef 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -139,7 +139,6 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } else { leaderElectionActive = false break - } } }() @@ -149,12 +148,14 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { if instance := sm.findServiceInstance(service); instance != nil { for _, cluster := range instance.clusters { - err := cluster.Network.AddRoute() - if err != nil { - log.Errorf("[endpoint] error adding route: %s\n", err.Error()) - } else { - log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", - cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + for i := range cluster.Network { + err := cluster.Network[i].AddRoute() + if err != nil { + log.Errorf("[endpoint] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + } } } } @@ -254,12 +255,14 @@ func getLocalEndpoints(ep *v1.Endpoints, id string, config *kubevip.Config) []st func (sm *Manager) clearRoutes(service *v1.Service) { if instance := sm.findServiceInstance(service); instance != nil { for _, cluster := range instance.clusters { - err := cluster.Network.DeleteRoute() - if err != nil && !strings.Contains(err.Error(), "no such process") { - log.Errorf("failed to delete route for %s: %s", cluster.Network.IP(), err.Error()) - } else { - log.Infof("deleted route: %s, service: %s/%s, interface: %s, table: %d", - cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + for i := range cluster.Network { + err := cluster.Network[i].DeleteRoute() + if err != nil && !strings.Contains(err.Error(), "no such process") { + log.Errorf("failed to delete route for %s: %s", cluster.Network[i].IP(), err.Error()) + } else { + log.Infof("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) + } } } } diff --git a/pkg/manager/watch_endpointslices.go b/pkg/manager/watch_endpointslices.go index c92afabb..8014094e 100644 --- a/pkg/manager/watch_endpointslices.go +++ b/pkg/manager/watch_endpointslices.go @@ -15,6 +15,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" + "k8s.io/client-go/util/retry" ) func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service *v1.Service, wg *sync.WaitGroup) error { @@ -71,6 +72,7 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * for event := range ch { lastKnownGoodEndpoint := "" + activeEndpointAnnotation := activeEndpoint // We need to inspect the event and get ResourceVersion out of it switch event.Type { case watch.Added, watch.Modified: @@ -81,6 +83,10 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * return fmt.Errorf("[endpointslices] unable to parse Kubernetes services from API watcher") } + if eps.AddressType == discoveryv1.AddressTypeIPv6 { + activeEndpointAnnotation = activeEndpointIPv6 + } + // Build endpoints localendpoints := getLocalEndpointsFromEndpointslices(eps, id, sm.config) @@ -120,7 +126,7 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * // Set the service accordingly if service.Annotations[egress] == "true" { - service.Annotations[activeEndpoint] = lastKnownGoodEndpoint + service.Annotations[activeEndpointAnnotation] = lastKnownGoodEndpoint } if !leaderElectionActive && sm.config.EnableServicesElection { @@ -149,12 +155,14 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { if instance := sm.findServiceInstance(service); instance != nil { for _, cluster := range instance.clusters { - err := cluster.Network.AddRoute() - if err != nil { - log.Errorf("[endpointslices] error adding route: %s\n", err.Error()) - } else { - log.Infof("[endpointslices] added route: %s, service: %s/%s, interface: %s, table: %d", - cluster.Network.IP(), service.Namespace, service.Name, cluster.Network.Interface(), sm.config.RoutingTableID) + for i := range cluster.Network { + err := cluster.Network[i].AddRoute() + if err != nil { + log.Errorf("[endpointslices] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpointslices] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + } } } } @@ -208,6 +216,38 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * return nil //nolint:govet } +func (sm *Manager) updateServiceEndpointSlicesAnnotation(endpoint, endpointIPv6 string, service *v1.Service) error { + retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of Deployment before attempting update + // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver + currentService, err := sm.clientSet.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{}) + if err != nil { + return err + } + + currentServiceCopy := currentService.DeepCopy() + if currentServiceCopy.Annotations == nil { + currentServiceCopy.Annotations = make(map[string]string) + } + + currentServiceCopy.Annotations[activeEndpoint] = endpoint + currentServiceCopy.Annotations[activeEndpointIPv6] = endpointIPv6 + + _, err = sm.clientSet.CoreV1().Services(currentService.Namespace).Update(context.TODO(), currentServiceCopy, metav1.UpdateOptions{}) + if err != nil { + log.Errorf("Error updating Service Spec [%s] : %v", currentServiceCopy.Name, err) + return err + } + return nil + }) + + if retryErr != nil { + log.Errorf("Failed to set Services: %v", retryErr) + return retryErr + } + return nil +} + func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id string, config *kubevip.Config) []string { var localendpoints []string @@ -243,6 +283,7 @@ func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id stri log.Debugf("[endpointslices] found endpoint - address: %s, node: %s", eps.Endpoints[i].Addresses[j], *eps.Endpoints[i].NodeName) } localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) + // 3. Compare to shortname } else if shortnameErr != nil && shortname == *eps.Endpoints[i].NodeName && *eps.Endpoints[i].Conditions.Serving { log.Debugf("[endpointslices] found endpoint - address: %s, shortname: %s, node: %s", eps.Endpoints[i].Addresses[j], shortname, *eps.Endpoints[i].NodeName) localendpoints = append(localendpoints, eps.Endpoints[i].Addresses[j]) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index b6ce192e..272723a0 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -105,9 +105,10 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context break } + svcAddresses := fetchServiceAddresses(svc) + // We only care about LoadBalancer services that have been allocated an address - serviceAddresses := fetchServiceAddresses(svc) - if len(serviceAddresses) == 0 || serviceAddresses[0] == "" { + if len(svcAddresses) <= 0 { break } @@ -132,13 +133,15 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // The modified event should only be triggered if the service has been modified (i.e. moved somewhere else) if event.Type == watch.Modified { - //log.Debugf("(svcs) Retreiving local addresses, to ensure that this modified address doesn't exist") - f, err := vip.GarbageCollect(sm.config.Interface, svc.Spec.LoadBalancerIP) - if err != nil { - log.Errorf("(svcs) cleaning existing address error: [%s]", err.Error()) - } - if f { - log.Warnf("(svcs) already found existing address [%s] on adapter [%s]", svc.Spec.LoadBalancerIP, sm.config.Interface) + for _, addr := range svcAddresses { + //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()) + } + if f { + log.Warnf("(svcs) already found existing address [%s] on adapter [%s]", addr, sm.config.Interface) + } } } // Scenarios: @@ -161,7 +164,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // background the endpoint watcher go func() { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Add Endpoint watcher + // Add Endpoint or EndpointSlices watcher wg.Add(1) if !sm.config.EnableEndpointSlices { err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 086b76a3..93b2574b 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -66,60 +66,80 @@ func netlinkParse(addr string) (*netlink.Addr, error) { } // NewConfig will attempt to provide an interface to the kernel network configuration -func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID int, tableType int) (Network, error) { - result := &network{} +func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID int, tableType int, dnsMode string) ([]Network, error) { + networks := []Network{} - link, err := netlink.LinkByName(iface) - if err != nil { - return result, errors.Wrapf(err, "could not get link for interface '%s'", iface) - } + if IsIP(address) { + result := &network{} - result.link = link - result.routeTable = tableID - result.routingTableType = tableType + link, err := netlink.LinkByName(iface) + if err != nil { + return networks, errors.Wrapf(err, "could not get link for interface '%s'", iface) + } + + result.link = link + result.routeTable = tableID + result.routingTableType = tableType - if IsIP(address) { // Check if the subnet needs overriding if subnet != "" { result.address, err = netlink.ParseAddr(address + subnet) if err != nil { - return result, errors.Wrapf(err, "could not parse address '%s'", address) + return networks, errors.Wrapf(err, "could not parse address '%s'", address) } } else { result.address, err = netlinkParse(address) if err != nil { - return result, errors.Wrapf(err, "could not parse address '%s'", address) + return networks, errors.Wrapf(err, "could not parse address '%s'", address) } } // Ensure we don't have a global address on loopback if iface == "lo" { result.address.Scope = unix.RT_SCOPE_HOST } - return result, nil - } + networks = append(networks, result) + } else { + // try to resolve the address + ips, err := LookupHost(address, dnsMode) + if err != nil { + // return early for ddns if no IP is allocated for the domain + // when leader starts, should do get IP from DHCP for the domain + if isDDNS { + return networks, nil + } + return nil, err + } - // address is DNS - result.isDDNS = isDDNS - result.dnsName = address - // try to resolve the address - ip, err := lookupHost(address) - if err != nil { - // return early for ddns if no IP is allocated for the domain - // when leader starts, should do get IP from DHCP for the domain - if isDDNS { - return result, nil + for _, ip := range ips { + + result := &network{} + + link, err := netlink.LinkByName(iface) + if err != nil { + return networks, errors.Wrapf(err, "could not get link for interface '%s'", iface) + } + + result.link = link + result.routeTable = tableID + result.routingTableType = tableType + + // address is DNS + result.isDDNS = isDDNS + result.dnsName = address + + // we're able to resolve store this as the initial IP + if result.address, err = netlinkParse(ip); err != nil { + return networks, err + } + // set ValidLft so that the VIP expires if the DNS entry is updated, otherwise it'll be refreshed by the DNS prober + result.address.ValidLft = defaultValidLft + + networks = append(networks, result) } - return nil, err - } - // we're able to resolve store this as the initial IP - if result.address, err = netlinkParse(ip); err != nil { - return result, err } - // set ValidLft so that the VIP expires if the DNS entry is updated, otherwise it'll be refreshed by the DNS prober - result.address.ValidLft = defaultValidLft - return result, err + return networks, nil } // AddRoute - Add an IP address to a route table diff --git a/pkg/vip/dns.go b/pkg/vip/dns.go index 63d15c03..fbaaa121 100644 --- a/pkg/vip/dns.go +++ b/pkg/vip/dns.go @@ -32,15 +32,20 @@ func (d *ipUpdater) Run(ctx context.Context) { log.Infof("stop ipUpdater") return default: - ip, err := lookupHost(d.vip.DNSName()) + mode := "ipv4" + if IsIPv6(d.vip.IP()) { + mode = "ipv6" + } + + ip, err := LookupHost(d.vip.DNSName(), mode) if err != nil { log.Warnf("cannot lookup %s: %v", d.vip.DNSName(), err) // fallback to renewing the existing IP - ip = d.vip.IP() + ip = []string{d.vip.IP()} } log.Infof("setting %s as an IP", ip) - if err := d.vip.SetIP(ip); err != nil { + if err := d.vip.SetIP(ip[0]); err != nil { log.Errorf("setting %s as an IP: %v", ip, err) } diff --git a/pkg/vip/egress.go b/pkg/vip/egress.go index 36138194..9ce34817 100644 --- a/pkg/vip/egress.go +++ b/pkg/vip/egress.go @@ -33,11 +33,19 @@ type Egress struct { comment string } -func CreateIptablesClient(nftables bool, namespace string) (*Egress, error) { +func CreateIptablesClient(nftables bool, namespace string, protocol iptables.Protocol) (*Egress, error) { log.Infof("[egress] Creating an iptables client, nftables mode [%t]", nftables) e := new(Egress) var err error - e.ipTablesClient, err = iptables.New(iptables.EnableNFTables(nftables)) + + options := []iptables.Option{} + options = append(options, iptables.EnableNFTables(nftables)) + + if protocol == iptables.ProtocolIPv6 { + options = append(options, iptables.IPFamily(iptables.ProtocolIPv6), iptables.Timeout(5)) + } + + e.ipTablesClient, err = iptables.New(options...) e.comment = Comment + "-" + namespace return e, err } diff --git a/pkg/vip/util.go b/pkg/vip/util.go index 8608c5f1..77b0b3cb 100644 --- a/pkg/vip/util.go +++ b/pkg/vip/util.go @@ -14,15 +14,60 @@ import ( ) // LookupHost resolves dnsName and return an IP or an error -func lookupHost(dnsName string) (string, error) { - addrs, err := net.LookupHost(dnsName) +func LookupHost(dnsName, dnsMode string) ([]string, error) { + result, err := net.LookupHost(dnsName) if err != nil { - return "", err + return nil, err + } + if len(result) == 0 { + return nil, errors.Errorf("empty address for %s", dnsName) + } + addrs := []string{} + switch dnsMode { + case "ipv4", "ipv6", "dual": + a, err := getIPbyFamily(result, dnsMode) + if err != nil { + return nil, err + } + addrs = append(addrs, a...) + default: + addrs = append(addrs, result[0]) + } + + return addrs, nil +} + +func getIPbyFamily(addresses []string, family string) ([]string, error) { + var checkers []func(string) bool + families := []string{} + if family == "dual" || family == "ipv4" { + checkers = append(checkers, IsIPv4) + families = append(families, "IPv4") + } + if family == "dual" || family == "ipv6" { + checkers = append(checkers, IsIPv6) + families = append(families, "IPv6") + } + + addrs := []string{} + for i, c := range checkers { + addr, err := getIPbyChecker(addresses, c) + if err != nil { + return nil, fmt.Errorf("error getting %s address: %w", families[i], err) + } + addrs = append(addrs, addr) } - if len(addrs) == 0 { - return "", errors.Errorf("empty address for %s", dnsName) + + return addrs, nil +} + +func getIPbyChecker(addresses []string, checker func(string) bool) (string, error) { + for _, addr := range addresses { + if checker(addr) { + return addr, nil + } } - return addrs[0], nil + return "", fmt.Errorf("address not found") } // IsIP returns if address is an IP or not @@ -77,8 +122,15 @@ func GetDefaultGatewayInterface() (*net.Interface, error) { return nil, err } + routes6, err := netlink.RouteList(nil, syscall.AF_INET6) + if err != nil { + return nil, err + } + + routes = append(routes, routes6...) + for _, route := range routes { - if route.Dst == nil || route.Dst.String() == "0.0.0.0/0" { + if route.Dst == nil || route.Dst.String() == "0.0.0.0/0" || route.Dst.String() == "::/0" { if route.LinkIndex <= 0 { return nil, errors.New("Found default route but could not determine interface") } @@ -126,3 +178,12 @@ func GenerateMac() (mac string) { log.Infof("Generated mac: %s", mac) return mac } + +func GetIPs(vip string) []string { + addresses := []string{} + vips := strings.Split(vip, ",") + for _, v := range vips { + addresses = append(addresses, strings.TrimSpace(v)) + } + return addresses +} diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 6997c3e6..29cc8d02 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -27,6 +27,7 @@ import ( "github.com/onsi/gomega/format" "github.com/onsi/gomega/gexec" + "github.com/kube-vip/kube-vip/pkg/vip" "github.com/kube-vip/kube-vip/testing/e2e" ) @@ -270,6 +271,87 @@ var _ = Describe("kube-vip broadcast neighbor", func() { assertControlPlaneIsRoutable(ipv6VIP, 1*time.Second, 30*time.Second) }) }) + + Describe("kube-vip DualStack functionality", func() { + var ( + clusterConfig kindconfigv1alpha4.Cluster + vips []string + ipDualStackVIP string + ) + + BeforeEach(func() { + clusterName = fmt.Sprintf("%s-dualstack", filepath.Base(tempDirPath)) + + clusterConfig = kindconfigv1alpha4.Cluster{ + Networking: kindconfigv1alpha4.Networking{ + IPFamily: kindconfigv1alpha4.DualStackFamily, + }, + Nodes: []kindconfigv1alpha4.Node{}, + } + + manifestPath := filepath.Join(tempDirPath, "kube-vip-dualstack.yaml") + + for i := 0; i < 3; i++ { + nodeConfig := kindconfigv1alpha4.Node{ + Role: kindconfigv1alpha4.ControlPlaneRole, + ExtraMounts: []kindconfigv1alpha4.Mount{ + { + HostPath: manifestPath, + ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + }, + }, + } + // Override the kind image version + if k8sImagePath != "" { + nodeConfig.Image = k8sImagePath + } + clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) + } + + ipDualStackVIP = e2e.GenerateDualStackVIP() + vips = vip.GetIPs(ipDualStackVIP) + + manifestFile, err := os.Create(manifestPath) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile.Close() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ + ControlPlaneVIP: ipDualStackVIP, + ImagePath: imagePath, + })).To(Succeed()) + }) + + It("provides an DualStack VIP address for the Kubernetes control plane nodes", func() { + + By(withTimestamp("creating a kind cluster with multiple control plane nodes")) + createKindCluster(logger, &clusterConfig, clusterName) + + By(withTimestamp("loading local docker image to kind cluster")) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv4 VIP")) + // Allow enough time for control plane nodes to load the docker image and + // use the default timeout for establishing a connection to the VIP + assertControlPlaneIsRoutable(vips[0], time.Duration(0), 20*time.Second) + + By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) + // Allow enough time for control plane nodes to load the docker image and + // use the default timeout for establishing a connection to the VIP + assertControlPlaneIsRoutable(vips[1], time.Duration(0), 20*time.Second) + + By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) + killLeader(vips[0], clusterName) + + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv4 VIP with little downtime")) + // Allow at most 20 seconds of downtime when polling the control plane nodes + assertControlPlaneIsRoutable(vips[0], 1*time.Second, 20*time.Second) + + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv6 VIP with little downtime")) + // Allow at most 120 seconds of downtime when polling the control plane nodes + assertControlPlaneIsRoutable(vips[1], 1*time.Second, 20*time.Second) + }) + }) }) func createKindCluster(logger log.Logger, config *v1alpha4.Cluster, clusterName string) { @@ -317,8 +399,7 @@ func killLeader(leaderIPAddr string, clusterName string) { "docker", "exec", name, "ip", "addr", ) cmd.Stdout = cmdOut - - Eventually(cmd.Run).Should(Succeed()) + Eventually(cmd.Run(), "20s").Should(Succeed()) if strings.Contains(cmdOut.String(), leaderIPAddr) { leaderName = name diff --git a/testing/e2e/ip.go b/testing/e2e/ip.go index df4a3d80..ad2cc70d 100644 --- a/testing/e2e/ip.go +++ b/testing/e2e/ip.go @@ -102,6 +102,10 @@ func GenerateIPv4VIP() string { return "" } +func GenerateDualStackVIP() string { + return GenerateIPv4VIP() + "," + GenerateIPv6VIP() +} + func getKindNetworkSubnetCIDRs() []string { cmd := exec.Command( "docker", "inspect", "kind", diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index 28db707a..14b7cf0f 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -110,7 +110,13 @@ func (config *testConfig) createKind() error { _, _ = cmd.CombinedOutput() } } - cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") + + globalRange := "172.18.100.10-172.18.100.30" + if config.IPv6 { + globalRange = "fd34:70db:8529:1e3d:0000:0000:0000:0010-fd34:70db:8529:1e3d:0000:0000:0000:0030" + } + + cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global="+globalRange) if _, err := cmd.CombinedOutput(); err != nil { return err } diff --git a/testing/e2e/services/tests.go b/testing/e2e/services/tests.go index a6103689..96f207a9 100644 --- a/testing/e2e/services/tests.go +++ b/testing/e2e/services/tests.go @@ -48,6 +48,7 @@ func main() { _, t.ignoreEgress = os.LookupEnv("IGNORE_EGRESS") _, t.ignoreDualStack = os.LookupEnv("IGNORE_DUALSTACK") _, t.retainCluster = os.LookupEnv("RETAIN_CLUSTER") + _, t.IPv6 = os.LookupEnv("IPV6_FAMILY") flag.StringVar(&t.ImagePath, "imagepath", "plndr/kube-vip:action", "") flag.BoolVar(&t.ControlPlane, "ControlPlane", false, "") From 8ced01382ffafeefb17a5b6666aadc08507de77e Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Mon, 15 Jan 2024 21:41:17 +0100 Subject: [PATCH 525/542] Reintroduced e2e test changes Signed-off-by: Patryk Strusiewicz-Surmacki --- testing/e2e/e2e_test.go | 66 ++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 29cc8d02..8e5752fa 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -274,9 +274,8 @@ var _ = Describe("kube-vip broadcast neighbor", func() { Describe("kube-vip DualStack functionality", func() { var ( - clusterConfig kindconfigv1alpha4.Cluster - vips []string - ipDualStackVIP string + clusterConfig kindconfigv1alpha4.Cluster + dualstackVIP string ) BeforeEach(func() { @@ -308,8 +307,7 @@ var _ = Describe("kube-vip broadcast neighbor", func() { clusterConfig.Nodes = append(clusterConfig.Nodes, nodeConfig) } - ipDualStackVIP = e2e.GenerateDualStackVIP() - vips = vip.GetIPs(ipDualStackVIP) + dualstackVIP = e2e.GenerateDualStackVIP() manifestFile, err := os.Create(manifestPath) Expect(err).NotTo(HaveOccurred()) @@ -317,39 +315,67 @@ var _ = Describe("kube-vip broadcast neighbor", func() { defer manifestFile.Close() Expect(kubeVIPManifestTemplate.Execute(manifestFile, e2e.KubevipManifestValues{ - ControlPlaneVIP: ipDualStackVIP, + ControlPlaneVIP: dualstackVIP, ImagePath: imagePath, + ConfigPath: configPath, })).To(Succeed()) + + if v129 { + // create a seperate manifest + manifestPath2 := filepath.Join(tempDirPath, "kube-vip-ipv6-first.yaml") + + // change the path of the mount to the new file + clusterConfig.Nodes[0].ExtraMounts[0].HostPath = manifestPath2 + + manifestFile2, err := os.Create(manifestPath2) + Expect(err).NotTo(HaveOccurred()) + + defer manifestFile2.Close() + + Expect(kubeVIPManifestTemplate.Execute(manifestFile2, e2e.KubevipManifestValues{ + ControlPlaneVIP: dualstackVIP, + ImagePath: imagePath, + ConfigPath: "/etc/kubernetes/super-admin.conf", // Change the kuberenetes file + })).To(Succeed()) + } }) - It("provides an DualStack VIP address for the Kubernetes control plane nodes", func() { + It("provides an DualStack VIP addresses for the Kubernetes control plane nodes", func() { + go func() { + time.Sleep(30 * time.Second) + By(withTimestamp("loading local docker image to kind cluster")) + e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + }() + + vips := vip.GetIPs(dualstackVIP) By(withTimestamp("creating a kind cluster with multiple control plane nodes")) createKindCluster(logger, &clusterConfig, clusterName) - By(withTimestamp("loading local docker image to kind cluster")) - e2e.LoadDockerImageToKind(logger, imagePath, clusterName) + By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) + // Allow enough time for control plane nodes to load the docker image and + // use the default timeout for establishing a connection to the VIP + assertControlPlaneIsRoutable(vips[1], time.Duration(0), 20*time.Second) By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv4 VIP")) // Allow enough time for control plane nodes to load the docker image and // use the default timeout for establishing a connection to the VIP assertControlPlaneIsRoutable(vips[0], time.Duration(0), 20*time.Second) - By(withTimestamp("checking that the Kubernetes control plane nodes are accessible via the assigned IPv6 VIP")) - // Allow enough time for control plane nodes to load the docker image and - // use the default timeout for establishing a connection to the VIP - assertControlPlaneIsRoutable(vips[1], time.Duration(0), 20*time.Second) + // wait for a bit + By(withTimestamp("sitting for a few seconds to hopefully allow the roles to have been created in the cluster")) + time.Sleep(30 * time.Second) By(withTimestamp("killing the leader Kubernetes control plane node to trigger a fail-over scenario")) - killLeader(vips[0], clusterName) + killLeader(vips[1], clusterName) - By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv4 VIP with little downtime")) + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv6 VIP with little downtime")) // Allow at most 20 seconds of downtime when polling the control plane nodes - assertControlPlaneIsRoutable(vips[0], 1*time.Second, 20*time.Second) + assertControlPlaneIsRoutable(vips[1], 1*time.Second, 30*time.Second) - By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv6 VIP with little downtime")) - // Allow at most 120 seconds of downtime when polling the control plane nodes - assertControlPlaneIsRoutable(vips[1], 1*time.Second, 20*time.Second) + By(withTimestamp("checking that the Kubernetes control plane nodes are still accessible via the assigned IPv4 VIP with little downtime")) + // Allow at most 20 seconds of downtime when polling the control plane nodes + assertControlPlaneIsRoutable(vips[0], 1*time.Second, 30*time.Second) }) }) }) @@ -399,7 +425,7 @@ func killLeader(leaderIPAddr string, clusterName string) { "docker", "exec", name, "ip", "addr", ) cmd.Stdout = cmdOut - Eventually(cmd.Run(), "20s").Should(Succeed()) + Eventually(cmd.Run(), "600s").Should(Succeed()) if strings.Contains(cmdOut.String(), leaderIPAddr) { leaderName = name From eff0d21820693abc5f6b5cfcec00eecc8d8c3c9c Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Tue, 16 Jan 2024 13:31:39 +0100 Subject: [PATCH 526/542] Fixed typo Signed-off-by: Patryk Strusiewicz-Surmacki --- cmd/kube-vip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 7ab33d4a..3c88b4df 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -139,7 +139,7 @@ func init() { kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableNodeLabeling, "enableNodeLabeling", false, "Enable leader node labeling with \"kube-vip.io/has-ip=\", defaults to false") kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesLeaseName, "servicesLeaseName", "plndr-svcs-lock", "Name of the lease that is used for leader election for services (in arp mode)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.DNSMode, "dnsMode", "first", "Name of the mode that DNS lookup will be performed (first, ipv4, ipv6, dual)") - kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DisableServiceUpdates, "disableServiceUpdates", false, "If true, kube-vip will process services as usal, but will not update service's Status.LoadBalancer.Ingress slice") + kubeVipCmd.PersistentFlags().BoolVar(&initConfig.DisableServiceUpdates, "disableServiceUpdates", false, "If true, kube-vip will process services as usual, but will not update service's Status.LoadBalancer.Ingress slice") kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableEndpointSlices, "enableEndpointSlices", false, "If enabled, kube-vip will only advertise services, but will use EndpointSlices instead of endpoints to get IPs of Pods") // Prometheus HTTP Server From bb2c03335f9d97e9968a50366be6d72da3a02e10 Mon Sep 17 00:00:00 2001 From: Marcel Fest Date: Tue, 16 Jan 2024 13:57:58 +0100 Subject: [PATCH 527/542] Added cli-options for the bgp holdtime and keepalive Signed-off-by: Marcel Fest --- cmd/kube-vip.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index ae42574f..bd467c9b 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -106,6 +106,8 @@ func init() { kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIF, "sourceIF", "", "The source interface for bgp peering (not to be used with sourceIP)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPConfig.SourceIP, "sourceIP", "", "The source address for bgp peering (not to be used with sourceIF)") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPConfig.AS, "localAS", 65000, "The local AS number for the bgp server") + kubeVipCmd.PersistentFlags().Uint64Var(&initConfig.BGPConfig.HoldTime, "bgpHoldTimer", 30, "The hold timer for all bgp peers (it defines the time a session is held)") + kubeVipCmd.PersistentFlags().Uint64Var(&initConfig.BGPConfig.KeepaliveInterval, "bgpKeepAliveInterval", 10, "The keepalive interval for all bgp peers (it defines the heartbeat of keepalive messages)") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Address, "peerAddress", "", "The address of a BGP peer") kubeVipCmd.PersistentFlags().Uint32Var(&initConfig.BGPPeerConfig.AS, "peerAS", 65000, "The AS number for a BGP peer") kubeVipCmd.PersistentFlags().StringVar(&initConfig.BGPPeerConfig.Password, "peerPass", "", "The md5 password for a BGP peer") From bbb0c8681230de4cd5e4467e696cac181301ddbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 12:43:50 +0000 Subject: [PATCH 528/542] Bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index f91c6a7a..aacf4937 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/osrg/gobgp/v3 v3.19.0 github.com/packethost/packngo v0.31.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_golang v1.18.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 @@ -74,7 +74,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/packet v1.1.2 // indirect @@ -87,9 +87,9 @@ require ( github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect @@ -106,7 +106,7 @@ require ( golang.org/x/crypto v0.17.0 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index f7b6db56..131e93b4 100644 --- a/go.sum +++ b/go.sum @@ -250,8 +250,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= @@ -316,15 +316,15 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -504,8 +504,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 1c4c11098ee32e686a0f6c40f4f87e36ca82e82c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 12:44:21 +0000 Subject: [PATCH 529/542] Bump github.com/osrg/gobgp/v3 from 3.19.0 to 3.22.0 Bumps [github.com/osrg/gobgp/v3](https://github.com/osrg/gobgp) from 3.19.0 to 3.22.0. - [Release notes](https://github.com/osrg/gobgp/releases) - [Changelog](https://github.com/osrg/gobgp/blob/master/.goreleaser.yml) - [Commits](https://github.com/osrg/gobgp/compare/v3.19.0...v3.22.0) --- updated-dependencies: - dependency-name: github.com/osrg/gobgp/v3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f91c6a7a..1dc7d1c8 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/mdlayher/ndp v1.0.1 github.com/onsi/ginkgo/v2 v2.13.2 github.com/onsi/gomega v1.30.0 - github.com/osrg/gobgp/v3 v3.19.0 + github.com/osrg/gobgp/v3 v3.22.0 github.com/packethost/packngo v0.31.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 diff --git a/go.sum b/go.sum index f7b6db56..ede02dbf 100644 --- a/go.sum +++ b/go.sum @@ -296,8 +296,8 @@ github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/osrg/gobgp/v3 v3.19.0 h1:SHjeu707EVp5h2LR8qLxDz/PzFU6oO+jhquGzGsigTI= -github.com/osrg/gobgp/v3 v3.19.0/go.mod h1:TszzyYD/31jXlljifRhxFEmPsITEloZmGU5CTN21W18= +github.com/osrg/gobgp/v3 v3.22.0 h1:HKCk9+8hV5GQ4c35NuV8q+eKSnsScf+0v7oXB6jS8wU= +github.com/osrg/gobgp/v3 v3.22.0/go.mod h1:4fbscYpsCk14EO16nTWAdJyErO4MbAZ2zLJmsmeXu/k= github.com/packethost/packngo v0.31.0 h1:LLH90ardhULWbagBIc3I3nl2uU75io0a7AwY6hyi0S4= github.com/packethost/packngo v0.31.0/go.mod h1:Io6VJqzkiqmIEQbpOjeIw9v8q9PfcTEq8TEY/tMQsfw= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= From 2e39d510e4bcf8a9cde52bcdb77b805dc590bd3b Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Thu, 18 Jan 2024 12:47:08 +0000 Subject: [PATCH 530/542] Consistent logging Signed-off-by: Dan Finneran --- pkg/bgp/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/bgp/server.go b/pkg/bgp/server.go index faafaf0b..8d9da11d 100644 --- a/pkg/bgp/server.go +++ b/pkg/bgp/server.go @@ -3,11 +3,11 @@ package bgp import ( "context" "fmt" - "log" "time" 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 +42,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.Println(p) + log.Infof("[BGP] %s", p.String()) if peerStateChangeCallback != nil { peerStateChangeCallback(p) } From deb0afb3a30c6319611fd822f9617e7fa79ce283 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 02:09:00 +0000 Subject: [PATCH 531/542] Bump k8s.io/klog/v2 from 2.120.0 to 2.120.1 Bumps [k8s.io/klog/v2](https://github.com/kubernetes/klog) from 2.120.0 to 2.120.1. - [Release notes](https://github.com/kubernetes/klog/releases) - [Changelog](https://github.com/kubernetes/klog/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes/klog/compare/v2.120.0...v2.120.1) --- updated-dependencies: - dependency-name: k8s.io/klog/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9dd3eb7e..07847ca4 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.29.0 - k8s.io/klog/v2 v2.120.0 + k8s.io/klog/v2 v2.120.1 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index 477e1918..011f1294 100644 --- a/go.sum +++ b/go.sum @@ -794,8 +794,8 @@ k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/klog/v2 v2.120.0 h1:z+q5mfovBj1fKFxiRzsa2DsJLPIVMk/KFL81LMOfK+8= -k8s.io/klog/v2 v2.120.0/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= From e85d8cd6c743a1ee90bcad3af7814e0b817982bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 02:09:10 +0000 Subject: [PATCH 532/542] Bump github.com/onsi/ginkgo/v2 from 2.13.2 to 2.15.0 Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.13.2 to 2.15.0. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.15.0) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 9dd3eb7e..1bec0317 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 - github.com/onsi/ginkgo/v2 v2.13.2 + github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/gomega v1.30.0 github.com/osrg/gobgp/v3 v3.22.0 github.com/packethost/packngo v0.31.0 @@ -104,14 +104,14 @@ require ( github.com/xlab/pkgconfig v0.0.0-20170226114623-cea12a0fd245 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.17.0 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sync v0.4.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.16.1 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect diff --git a/go.sum b/go.sum index 477e1918..57080e43 100644 --- a/go.sum +++ b/go.sum @@ -292,8 +292,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= -github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/osrg/gobgp/v3 v3.22.0 h1:HKCk9+8hV5GQ4c35NuV8q+eKSnsScf+0v7oXB6jS8wU= @@ -447,8 +447,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -493,8 +493,8 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -517,8 +517,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -648,8 +648,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From fa1b2c965a6958f2234ff3cd2833154e6a416cb3 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Wed, 17 Jan 2024 17:43:54 +0100 Subject: [PATCH 533/542] No-leader-election mode for BGP and fixes for routing table mode Signed-off-by: Patryk Strusiewicz-Surmacki --- pkg/cluster/service.go | 2 +- pkg/manager/instance.go | 32 +++--- pkg/manager/manager_table.go | 1 - pkg/manager/services.go | 6 +- pkg/manager/watch_endpoints.go | 159 ++++++++++++++++++++++------ pkg/manager/watch_endpointslices.go | 144 +++++++++++++++++++------ pkg/manager/watch_services.go | 49 ++++++++- 7 files changed, 309 insertions(+), 84 deletions(-) diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 0d657a98..445ee779 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -208,7 +208,7 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser }(ctxArp) } - if c.EnableBGP { + 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) diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index ce5b2fee..41422a1f 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -55,20 +55,24 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { for _, address := range instanceAddresses { // Generate new Virtual IP configuration newVips = append(newVips, &kubevip.Config{ - VIP: address, - Interface: serviceInterface, - SingleNode: true, - EnableARP: config.EnableARP, - EnableBGP: config.EnableBGP, - VIPCIDR: config.VIPCIDR, - VIPSubnet: config.VIPSubnet, - EnableRoutingTable: config.EnableRoutingTable, - RoutingTableID: config.RoutingTableID, - RoutingTableType: config.RoutingTableType, - ArpBroadcastRate: config.ArpBroadcastRate, - EnableServiceSecurity: config.EnableServiceSecurity, - DNSMode: config.DNSMode, - DisableServiceUpdates: config.DisableServiceUpdates, + VIP: address, + Interface: serviceInterface, + SingleNode: true, + EnableARP: config.EnableARP, + EnableBGP: config.EnableBGP, + VIPCIDR: config.VIPCIDR, + VIPSubnet: config.VIPSubnet, + EnableRoutingTable: config.EnableRoutingTable, + RoutingTableID: config.RoutingTableID, + RoutingTableType: config.RoutingTableType, + ArpBroadcastRate: config.ArpBroadcastRate, + EnableServiceSecurity: config.EnableServiceSecurity, + DNSMode: config.DNSMode, + DisableServiceUpdates: config.DisableServiceUpdates, + EnableServicesElection: config.EnableServicesElection, + KubernetesLeaderElection: kubevip.KubernetesLeaderElection{ + EnableLeaderElection: config.EnableLeaderElection, + }, }) } diff --git a/pkg/manager/manager_table.go b/pkg/manager/manager_table.go index 6d9749e4..8527b53f 100644 --- a/pkg/manager/manager_table.go +++ b/pkg/manager/manager_table.go @@ -107,7 +107,6 @@ func (sm *Manager) startTableMode() error { }, }) } else { - // TODO: this needs to be called periodically or do I need to wrap it somehow with a cancel context? log.Infof("beginning watching services without leader election") err = sm.servicesWatcher(ctx, sm.syncServices) if err != nil { diff --git a/pkg/manager/services.go b/pkg/manager/services.go index e8b307bd..c3e7c4ee 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -259,10 +259,12 @@ func (sm *Manager) deleteService(uid string) error { } } // TODO: Implement dual-stack loadbalancer support if BGP is enabled - if serviceInstance.vipConfigs[0].EnableBGP { + if serviceInstance.vipConfigs[0].EnableBGP && ((sm.config.EnableLeaderElection || sm.config.EnableServicesElection) || configuredLocalRoutes[uid]) { cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfigs[0].VIP, serviceInstance.vipConfigs[0].VIPCIDR) err := sm.bgpServer.DelHost(cidrVip) - return err + if err != nil { + return fmt.Errorf("error deleting BGP host: %v", err) + } } // We will need to tear down the egress diff --git a/pkg/manager/watch_endpoints.go b/pkg/manager/watch_endpoints.go index 4f7012ef..6091de6d 100644 --- a/pkg/manager/watch_endpoints.go +++ b/pkg/manager/watch_endpoints.go @@ -81,7 +81,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } // Build endpoints - localendpoints := getLocalEndpoints(ep, id, sm.config) + var endpoints []string + if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && !sm.config.EnableLeaderElection && !sm.config.EnableServicesElection && + service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster { + endpoints = getAllEndpoints(ep) + } else { + endpoints = getLocalEndpoints(ep, id, sm.config) + } // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -90,15 +96,15 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser // // Check that we have local endpoints - if len(localendpoints) != 0 { + if len(endpoints) != 0 { // if we haven't populated one, then do so if lastKnownGoodEndpoint != "" { // check out previous endpoint exists stillExists := false - for x := range localendpoints { - if localendpoints[x] == lastKnownGoodEndpoint { + for x := range endpoints { + if endpoints[x] == lastKnownGoodEndpoint { stillExists = true } } @@ -108,13 +114,13 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser // Stop the existing leaderElection cancel() // Set our active endpoint to an existing one - lastKnownGoodEndpoint = localendpoints[0] + lastKnownGoodEndpoint = endpoints[0] // disable last leaderElection flag leaderElectionActive = false } } else { - lastKnownGoodEndpoint = localendpoints[0] + lastKnownGoodEndpoint = endpoints[0] } // Set the service accordingly @@ -131,7 +137,7 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser // if the context isn't cancelled restart if leaderContext.Err() != context.Canceled { leaderElectionActive = true - err = sm.StartServicesLeaderElection(leaderContext, service, wg) + err := sm.StartServicesLeaderElection(leaderContext, service, wg) if err != nil { log.Error(err) } @@ -144,30 +150,75 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser }() } - // There are local endpoints available on the node, therefore route(s) should be added to the table - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { - if instance := sm.findServiceInstance(service); instance != nil { - for _, cluster := range instance.clusters { - for i := range cluster.Network { - err := cluster.Network[i].AddRoute() - if err != nil { - log.Errorf("[endpoint] error adding route: %s\n", err.Error()) - } else { - log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", - cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + // There are local endpoints available on the node + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && !configuredLocalRoutes[string(service.UID)] { + // If routing table mode is enabled - routes should be added per node + if sm.config.EnableRoutingTable { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + err := cluster.Network[i].AddRoute() + if err != nil { + log.Errorf("[endpoint] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpoint] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } } } } } - configuredLocalRoutes[string(service.UID)] = true - leaderElectionActive = true - } + // If BGP mode is enabled - hosts should be added per node + if sm.config.EnableBGP { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR) + log.Debugf("[endpoint] Attempting to advertise BGP service: %s", address) + err := sm.bgpServer.AddHost(address) + if err != nil { + log.Errorf("[endpoint] error adding BGP host %s\n", err.Error()) + } else { + log.Infof("[endpoint] added BGP host: %s, service: %s/%s", address, service.Namespace, service.Name) + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } + } + } + } + } + } } else { - // There are no local enpoints - routes should be deleted - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && configuredLocalRoutes[string(service.UID)] { - sm.clearRoutes(service) - configuredLocalRoutes[string(service.UID)] = false + // There are no local enpoints + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && configuredLocalRoutes[string(service.UID)] { + // If routing table mode is enabled - routes should be deleted + if sm.config.EnableRoutingTable { + sm.clearRoutes(service) + configuredLocalRoutes[string(service.UID)] = false + } + + // If BGP mode is enabled - routes should be deleted + if sm.config.EnableBGP { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + 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: %s\n", address, err.Error()) + } else { + log.Infof("[endpoint] deleted BGP host: %s, service: %s/%s", + address, service.Namespace, service.Name) + configuredLocalRoutes[string(service.UID)] = false + leaderElectionActive = false + } + } + } + } + } } // If there are no local endpoints, and we had one then remove it and stop the leaderElection @@ -179,19 +230,37 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser } } log.Debugf("[endpoint watcher] service %s/%s: local endpoint(s) [%d], known good [%s], active election [%t]", - service.Namespace, service.Name, len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + service.Namespace, service.Name, len(endpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: - // Check if deleted endpoints were local endpoints for this node, if so, clear routes - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable { + // When no-leader-elecition mode + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection { + // find all existing local endpoints ep, ok := event.Object.(*v1.Endpoints) if !ok { cancel() return fmt.Errorf("unable to parse Kubernetes services from API watcher") } - localEndpoints := getLocalEndpoints(ep, id, sm.config) - if len(localEndpoints) > 0 { - sm.clearRoutes(service) + + var endpoints []string + if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && !sm.config.EnableLeaderElection && !sm.config.EnableServicesElection && + service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster { + endpoints = getAllEndpoints(ep) + } else { + endpoints = getLocalEndpoints(ep, id, sm.config) + } + + // If there were local endpoints deleted + if len(endpoints) > 0 { + // Delete all routes in routing table mode + if sm.config.EnableRoutingTable { + sm.clearRoutes(service) + } + + // Delete all hosts in BGP mode + if sm.config.EnableBGP { + sm.clearBGPHosts(service) + } } } @@ -211,6 +280,17 @@ func (sm *Manager) watchEndpoint(ctx context.Context, id string, service *v1.Ser return nil //nolint:govet } +func getAllEndpoints(ep *v1.Endpoints) []string { + endpoints := []string{} + for subset := range ep.Subsets { + for address := range ep.Subsets[subset].Addresses { + addr := strings.Split(ep.Subsets[subset].Addresses[address].IP, "/") + endpoints = append(endpoints, addr[0]) + } + } + return endpoints +} + func getLocalEndpoints(ep *v1.Endpoints, id string, config *kubevip.Config) []string { var localendpoints []string @@ -268,6 +348,23 @@ func (sm *Manager) clearRoutes(service *v1.Service) { } } +func (sm *Manager) clearBGPHosts(service *v1.Service) { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + 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()) + } else { + log.Infof("[endpoint] deleted BGP host: %s, service: %s/%s", + address, service.Namespace, service.Name) + } + } + } + } +} + func (sm *Manager) updateServiceEndpointAnnotation(endpoint string, service *v1.Service) error { retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { // Retrieve the latest version of Deployment before attempting update diff --git a/pkg/manager/watch_endpointslices.go b/pkg/manager/watch_endpointslices.go index 8014094e..0ce3e70c 100644 --- a/pkg/manager/watch_endpointslices.go +++ b/pkg/manager/watch_endpointslices.go @@ -88,7 +88,13 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * } // Build endpoints - localendpoints := getLocalEndpointsFromEndpointslices(eps, id, sm.config) + var endpoints []string + if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && !sm.config.EnableLeaderElection && !sm.config.EnableServicesElection && + service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster { + endpoints = getAllEndpointsFromEndpointslices(eps) + } else { + endpoints = getLocalEndpointsFromEndpointslices(eps, id, sm.config) + } // Find out if we have any local endpoints // if out endpoint is empty then populate it @@ -97,15 +103,15 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * // // Check that we have local endpoints - if len(localendpoints) != 0 { + if len(endpoints) != 0 { // if we haven't populated one, then do so if lastKnownGoodEndpoint != "" { // check out previous endpoint exists stillExists := false - for x := range localendpoints { - if localendpoints[x] == lastKnownGoodEndpoint { + for x := range endpoints { + if endpoints[x] == lastKnownGoodEndpoint { stillExists = true } } @@ -115,13 +121,13 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * // Stop the existing leaderElection cancel() // Set our active endpoint to an existing one - lastKnownGoodEndpoint = localendpoints[0] + lastKnownGoodEndpoint = endpoints[0] // disable last leaderElection flag leaderElectionActive = false } } else { - lastKnownGoodEndpoint = localendpoints[0] + lastKnownGoodEndpoint = endpoints[0] } // Set the service accordingly @@ -138,7 +144,7 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * // if the context isn't cancelled restart if leaderContext.Err() != context.Canceled { leaderElectionActive = true - err = sm.StartServicesLeaderElection(leaderContext, service, wg) + err := sm.StartServicesLeaderElection(leaderContext, service, wg) if err != nil { log.Error(err) } @@ -151,30 +157,75 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * }() } - // There are local endpoints available on the node, therefore route(s) should be added to the table - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && !configuredLocalRoutes[string(service.UID)] { - if instance := sm.findServiceInstance(service); instance != nil { - for _, cluster := range instance.clusters { - for i := range cluster.Network { - err := cluster.Network[i].AddRoute() - if err != nil { - log.Errorf("[endpointslices] error adding route: %s\n", err.Error()) - } else { - log.Infof("[endpointslices] added route: %s, service: %s/%s, interface: %s, table: %d", - cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + // There are local endpoints available on the node + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && !configuredLocalRoutes[string(service.UID)] { + // If routing table mode is enabled - routes should be added per node + if sm.config.EnableRoutingTable { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + err := cluster.Network[i].AddRoute() + if err != nil { + log.Errorf("[endpointslices] error adding route: %s\n", err.Error()) + } else { + log.Infof("[endpointslices] added route: %s, service: %s/%s, interface: %s, table: %d", + cluster.Network[i].IP(), service.Namespace, service.Name, cluster.Network[i].Interface(), sm.config.RoutingTableID) + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } + } + } + } + } + + // If BGP mode is enabled - hosts should be added per node + if sm.config.EnableBGP { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR) + log.Debugf("[endpointslices] Attempting to advertise BGP service: %s", address) + err := sm.bgpServer.AddHost(address) + if err != nil { + log.Errorf("[endpointslices] error adding BGP host %s\n", err.Error()) + } else { + log.Infof("[endpointslices] added BGP host: %s, service: %s/%s", address, service.Namespace, service.Name) + configuredLocalRoutes[string(service.UID)] = true + leaderElectionActive = true + } } } } } - configuredLocalRoutes[string(service.UID)] = true - leaderElectionActive = true } } else { - // There are no local enpoints - routes should be deleted - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable && configuredLocalRoutes[string(service.UID)] { - sm.clearRoutes(service) - configuredLocalRoutes[string(service.UID)] = false - leaderElectionActive = false + // There are no local enpoints + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && configuredLocalRoutes[string(service.UID)] { + // If routing table mode is enabled - routes should be deleted + if sm.config.EnableRoutingTable { + sm.clearRoutes(service) + configuredLocalRoutes[string(service.UID)] = false + } + + // If BGP mode is enabled - routes should be deleted + if sm.config.EnableBGP { + if instance := sm.findServiceInstance(service); instance != nil { + for _, cluster := range instance.clusters { + for i := range cluster.Network { + address := fmt.Sprintf("%s/%s", cluster.Network[i].IP(), sm.config.VIPCIDR) + err := sm.bgpServer.DelHost(address) + if err != nil { + log.Errorf("[endpointslices] error deleting BGP host%s: %s\n", address, err.Error()) + } else { + log.Infof("[endpointslices] deleted BGP host: %s, service: %s/%s", + address, service.Namespace, service.Name) + configuredLocalRoutes[string(service.UID)] = false + leaderElectionActive = false + } + } + } + } + } } // If there are no local endpoints, and we had one then remove it and stop the leaderElection @@ -186,18 +237,37 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * } } log.Debugf("[endpointslices watcher] service %s/%s: local endpoint(s) [%d], known good [%s], active election [%t]", - service.Namespace, service.Name, len(localendpoints), lastKnownGoodEndpoint, leaderElectionActive) + service.Namespace, service.Name, len(endpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: - if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection && sm.config.EnableRoutingTable { + // When no-leade-elecition mode + if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection { + // find all existing local endpoints eps, ok := event.Object.(*discoveryv1.EndpointSlice) if !ok { cancel() - return fmt.Errorf("[endpointslices] unable to parse Kubernetes services from API watcher") + return fmt.Errorf("unable to parse Kubernetes services from API watcher") + } + + var endpoints []string + if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && !sm.config.EnableLeaderElection && !sm.config.EnableServicesElection && + service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster { + endpoints = getAllEndpointsFromEndpointslices(eps) + } else { + endpoints = getLocalEndpointsFromEndpointslices(eps, id, sm.config) } - localEndpoints := getLocalEndpointsFromEndpointslices(eps, id, sm.config) - if len(localEndpoints) > 0 { - sm.clearRoutes(service) + + // If there were local endpints deleted + if len(endpoints) > 0 { + // Delete all routes in routing table mode + if sm.config.EnableRoutingTable { + sm.clearRoutes(service) + } + + // Delete all hosts in BGP mode + if sm.config.EnableBGP { + sm.clearBGPHosts(service) + } } } @@ -254,9 +324,9 @@ func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id stri shortname, shortnameErr := getShortname(id) if shortnameErr != nil { if config.EnableRoutingTable && (!config.EnableLeaderElection && !config.EnableServicesElection) { - log.Debugf("[endpoint] %v, shortname will not be used", shortnameErr) + log.Debugf("[endpointslices] %v, shortname will not be used", shortnameErr) } else { - log.Errorf("[endpoint] %v", shortnameErr) + log.Errorf("[endpointslices] %v", shortnameErr) } } @@ -295,3 +365,11 @@ func getLocalEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice, id stri } return localendpoints } + +func getAllEndpointsFromEndpointslices(eps *discoveryv1.EndpointSlice) []string { + endpoints := []string{} + for _, ep := range eps.Endpoints { + endpoints = append(endpoints, ep.Addresses...) + } + return endpoints +} diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 272723a0..5a49b135 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -157,7 +157,8 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // // EnableRoutingTable enabled and EnableLeaderElection disabled // watchEndpoint will also not do a leaderElection by service. - if sm.config.EnableServicesElection || (sm.config.EnableRoutingTable && !sm.config.EnableLeaderElection) { + if sm.config.EnableServicesElection || + ((sm.config.EnableRoutingTable || sm.config.EnableBGP) && (!sm.config.EnableLeaderElection && !sm.config.EnableServicesElection)) { if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { // Start an endpoint watcher if we're not watching it already if !watchedService[string(svc.UID)] { @@ -181,7 +182,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context } }() - if sm.config.EnableRoutingTable && !sm.config.EnableLeaderElection { + if (sm.config.EnableRoutingTable || sm.config.EnableBGP) && (!sm.config.EnableLeaderElection && !sm.config.EnableServicesElection) { wg.Add(1) go func() { err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) @@ -194,6 +195,34 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // We're now watching this service watchedService[string(svc.UID)] = true } + } else if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && (!sm.config.EnableLeaderElection && !sm.config.EnableServicesElection) { + go func() { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeCluster { + // Add Endpoint watcher + wg.Add(1) + if !sm.config.EnableEndpointSlices { + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } + } else { + err = sm.watchEndpointSlices(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } + } + wg.Done() + } + }() + + wg.Add(1) + go func() { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() + }() } else { // Increment the waitGroup before the service Func is called (Done is completed in there) wg.Add(1) @@ -254,6 +283,22 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context activeService[string(svc.UID)] = false watchedService[string(svc.UID)] = false } + + if (sm.config.EnableBGP || sm.config.EnableRoutingTable) && sm.config.EnableLeaderElection && !sm.config.EnableServicesElection { + if sm.config.EnableBGP { + instance := sm.findServiceInstance(svc) + for _, vip := range instance.vipConfigs { + 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()) + } + } + } else { + sm.clearRoutes(svc) + } + } + log.Infof("(svcs) [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used From 947c7bc8c0a3cdc161bf5eb4e7c81f4f054c6171 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Thu, 25 Jan 2024 18:41:14 +0100 Subject: [PATCH 534/542] Increased http test timeout Signed-off-by: Patryk Strusiewicz-Surmacki --- testing/e2e/services/services.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index 7e181320..33b896a0 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -358,7 +358,7 @@ func (config *testConfig) startServiceTest(ctx context.Context, clientset *kuber func httpTest(address string) error { log.Infof("🕷️ testing HTTP request against [%s]", address) Client := http.Client{ - Timeout: 1 * time.Second, + Timeout: 2 * time.Second, } ip := net.ParseIP(address) if ip == nil { @@ -380,7 +380,7 @@ func httpTest(address string) error { return nil } - time.Sleep(time.Second) + time.Sleep(time.Second * 2) } return err } From fe9b669fc30e53012aab4224a6d436249b26870d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 02:19:46 +0000 Subject: [PATCH 535/542] Bump alpine from 3.19.0 to 3.19.1 Bumps alpine from 3.19.0 to 3.19.1. --- updated-dependencies: - dependency-name: alpine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile_iptables | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile_iptables b/Dockerfile_iptables index 1a37c65c..803cc1f3 100644 --- a/Dockerfile_iptables +++ b/Dockerfile_iptables @@ -11,7 +11,7 @@ RUN --mount=type=cache,sharing=locked,id=gomod,target=/go/pkg/mod/cache \ --mount=type=cache,sharing=locked,id=goroot,target=/root/.cache/go-build \ CGO_ENABLED=0 GOOS=linux make build -FROM alpine:3.19.0 +FROM alpine:3.19.1 # Update pkgs and add iptables RUN apk upgrade && \ apk add --no-cache iptables From e6e2e2b0a0caae23ddefa55a18cd587bc7e76e14 Mon Sep 17 00:00:00 2001 From: Patryk Strusiewicz-Surmacki Date: Wed, 31 Jan 2024 11:40:09 +0100 Subject: [PATCH 536/542] Fixed typo Signed-off-by: Patryk Strusiewicz-Surmacki --- pkg/manager/watch_endpointslices.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/manager/watch_endpointslices.go b/pkg/manager/watch_endpointslices.go index 0ce3e70c..04a00cc9 100644 --- a/pkg/manager/watch_endpointslices.go +++ b/pkg/manager/watch_endpointslices.go @@ -240,7 +240,7 @@ func (sm *Manager) watchEndpointSlices(ctx context.Context, id string, service * service.Namespace, service.Name, len(endpoints), lastKnownGoodEndpoint, leaderElectionActive) case watch.Deleted: - // When no-leade-elecition mode + // When no-leader-elecition mode if !sm.config.EnableServicesElection && !sm.config.EnableLeaderElection { // find all existing local endpoints eps, ok := event.Object.(*discoveryv1.EndpointSlice) From 7a93f6fd04d39b2b8b12db2067e571d15e64926f Mon Sep 17 00:00:00 2001 From: ii2day Date: Sun, 4 Feb 2024 15:34:26 +0800 Subject: [PATCH 537/542] fix: Using log instead of fmt.print Signed-off-by: ii2day --- cmd/kube-vip-kubeadm.go | 5 ++--- cmd/kube-vip-manifests.go | 8 +++----- pkg/equinixmetal/bgp.go | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index 0646e097..db16d1c4 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -1,7 +1,6 @@ package cmd import ( - "fmt" "os" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -54,7 +53,7 @@ var kubeKubeadmInit = &cobra.Command{ } cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - fmt.Println(cfg) + log.Info(cfg) }, } @@ -89,6 +88,6 @@ var kubeKubeadmJoin = &cobra.Command{ // Generate manifest and print cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - fmt.Println(cfg) + log.Info(cfg) }, } diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index 442cdba3..b4e91201 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -1,8 +1,6 @@ package cmd import ( - "fmt" - "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -54,7 +52,7 @@ var kubeManifestPod = &cobra.Command{ } cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - fmt.Println(cfg) + log.Info(cfg) }, } @@ -79,7 +77,7 @@ var kubeManifestDaemon = &cobra.Command{ } cfg := kubevip.GenerateDaemonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) - fmt.Println(cfg) + log.Info(cfg) }, } @@ -103,6 +101,6 @@ var kubeManifestRbac = &cobra.Command{ cfg := kubevip.GenerateSA() b, _ := yaml.Marshal(cfg) - fmt.Println(string(b)) + log.Info(string(b)) }, } diff --git a/pkg/equinixmetal/bgp.go b/pkg/equinixmetal/bgp.go index 5f113aa6..95b12a03 100644 --- a/pkg/equinixmetal/bgp.go +++ b/pkg/equinixmetal/bgp.go @@ -25,7 +25,7 @@ func BGPLookup(c *packngo.Client, k *kubevip.Config) error { return fmt.Errorf("Unable to find local/this device in Equinix Metal API") } - fmt.Printf("Querying BGP settings for [%s]", thisDevice.Hostname) + log.Infof("Querying BGP settings for [%s]", thisDevice.Hostname) neighbours, _, err := c.Devices.ListBGPNeighbors(thisDevice.ID, &packngo.ListOptions{}) if err != nil { return err From c994b09f27dfba833383f61d6abcab6ecdcdbd35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 02:55:11 +0000 Subject: [PATCH 538/542] Bump anchore/sbom-action from 0.15.3 to 0.15.8 Bumps [anchore/sbom-action](https://github.com/anchore/sbom-action) from 0.15.3 to 0.15.8. - [Release notes](https://github.com/anchore/sbom-action/releases) - [Commits](https://github.com/anchore/sbom-action/compare/v0.15.3...v0.15.8) --- updated-dependencies: - dependency-name: anchore/sbom-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/anchore-syft.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/anchore-syft.yml b/.github/workflows/anchore-syft.yml index b74cf839..ad8e884f 100644 --- a/.github/workflows/anchore-syft.yml +++ b/.github/workflows/anchore-syft.yml @@ -26,6 +26,6 @@ jobs: with: ref: ${{ github.ref_name }} - name: Anchore SBOM Action - uses: anchore/sbom-action@v0.15.3 + uses: anchore/sbom-action@v0.15.8 with: format: cyclonedx-json From 55c6e6418fb2804dd0ca184acc1a11c93638311e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:24:47 +0000 Subject: [PATCH 539/542] Bump k8s.io/apimachinery from 0.29.0 to 0.29.1 Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.29.0 to 0.29.1. - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.29.0...v0.29.1) --- updated-dependencies: - dependency-name: k8s.io/apimachinery dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 778f16fc..43b284ab 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.29.0 - k8s.io/apimachinery v0.29.0 + k8s.io/apimachinery v0.29.1 k8s.io/client-go v0.29.0 k8s.io/klog/v2 v2.120.1 sigs.k8s.io/kind v0.20.0 diff --git a/go.sum b/go.sum index 201a1c31..31b68ffd 100644 --- a/go.sum +++ b/go.sum @@ -790,8 +790,8 @@ honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= +k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= +k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= From e9d2542c467bdcaebbdecc35bd3895dc9c00cde4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 08:36:33 +0000 Subject: [PATCH 540/542] Bump k8s.io/client-go from 0.29.0 to 0.29.1 Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.29.0 to 0.29.1. - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.29.0...v0.29.1) --- updated-dependencies: - dependency-name: k8s.io/client-go dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 43b284ab..02b6f8fd 100644 --- a/go.mod +++ b/go.mod @@ -32,9 +32,9 @@ require ( golang.org/x/sys v0.16.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.29.0 + k8s.io/api v0.29.1 k8s.io/apimachinery v0.29.1 - k8s.io/client-go v0.29.0 + k8s.io/client-go v0.29.1 k8s.io/klog/v2 v2.120.1 sigs.k8s.io/kind v0.20.0 sigs.k8s.io/yaml v1.4.0 diff --git a/go.sum b/go.sum index 31b68ffd..4bbbffa9 100644 --- a/go.sum +++ b/go.sum @@ -788,12 +788,12 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= +k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= +k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A= +k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= From b64243a3da4d5ac11d379b71f587994117c0d73d Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Tue, 6 Feb 2024 11:01:44 +0100 Subject: [PATCH 541/542] Update ci.yaml fixes issue with file descriptors --- .github/workflows/ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c4fca5af..b139e663 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -49,6 +49,8 @@ jobs: runs-on: ubuntu-latest name: E2E ARP tests steps: + - name: Ensure fs wont cause issues + run: sudo sysctl fs.inotify.max_user_instances=8192 && sudo sysctl fs.inotify.max_user_watches=524288 - name: Checkout code uses: actions/checkout@v4 - name: Install Go From f933079da00ac260cff4995a121b1b31d5218900 Mon Sep 17 00:00:00 2001 From: Wout Van De Wiel Date: Tue, 6 Feb 2024 18:14:40 +0100 Subject: [PATCH 542/542] fix: print manifests to stdout Signed-off-by: Wout Van De Wiel --- cmd/kube-vip-kubeadm.go | 8 ++++---- cmd/kube-vip-manifests.go | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cmd/kube-vip-kubeadm.go b/cmd/kube-vip-kubeadm.go index db16d1c4..9db4b5aa 100644 --- a/cmd/kube-vip-kubeadm.go +++ b/cmd/kube-vip-kubeadm.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "os" "github.com/kube-vip/kube-vip/pkg/kubevip" @@ -51,9 +52,9 @@ var kubeKubeadmInit = &cobra.Command{ _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - log.Info(cfg) + cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) + fmt.Println(cfg) // output manifest to stdout }, } @@ -86,8 +87,7 @@ var kubeKubeadmJoin = &cobra.Command{ log.Fatalf("Unable to find file [%s]", kubeConfigPath) } - // Generate manifest and print cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - log.Info(cfg) + fmt.Println(cfg) // output manifest to stdout }, } diff --git a/cmd/kube-vip-manifests.go b/cmd/kube-vip-manifests.go index b4e91201..089000c8 100644 --- a/cmd/kube-vip-manifests.go +++ b/cmd/kube-vip-manifests.go @@ -1,6 +1,8 @@ package cmd import ( + "fmt" + "github.com/kube-vip/kube-vip/pkg/kubevip" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -50,9 +52,9 @@ var kubeManifestPod = &cobra.Command{ _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) - log.Info(cfg) + cfg := kubevip.GeneratePodManifestFromConfig(&initConfig, Release.Version, inCluster) + fmt.Println(cfg) // output manifest to stdout }, } @@ -75,9 +77,9 @@ var kubeManifestDaemon = &cobra.Command{ _ = cmd.Help() log.Fatalln("No address is specified for kube-vip to expose services on") } - cfg := kubevip.GenerateDaemonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) - log.Info(cfg) + cfg := kubevip.GenerateDaemonsetManifestFromConfig(&initConfig, Release.Version, inCluster, taint) + fmt.Println(cfg) // output manifest to stdout }, } @@ -100,7 +102,6 @@ var kubeManifestRbac = &cobra.Command{ } cfg := kubevip.GenerateSA() b, _ := yaml.Marshal(cfg) - - log.Info(string(b)) + fmt.Println(string(b)) // output manifest to stdout }, }

    ^?C|A{)CI9|J@|STUmqt8+=0CS^7T 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񺊪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 z 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%0A0D+kRUf|jO{@VL?qJ&l=$&FriyUsPY&VqO20 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 z z^><6>E*bf?e(rXeE3m}qwfAOMv$GB38Le-$KzlcSKq>Cc!U_b|I6KswnuW%0AG%bE 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 diff --git a/testing/e2e/e2e_suite_test.go b/testing/e2e/e2e_suite_test.go index 6ac6be60..eb0e543b 100644 --- a/testing/e2e/e2e_suite_test.go +++ b/testing/e2e/e2e_suite_test.go @@ -12,7 +12,7 @@ import ( kindconfigv1alpha4 "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" "sigs.k8s.io/kind/pkg/cluster" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index 68e7171f..a38252a3 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -28,7 +28,7 @@ import ( load "sigs.k8s.io/kind/pkg/cmd/kind/load/docker-image" "sigs.k8s.io/kind/pkg/log" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" ) From bac763e3f4350446d5616a019146927fe3581a54 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 14:04:33 +0000 Subject: [PATCH 403/542] more tidying Signed-off-by: Dan Finneran --- go.mod | 3 --- go.sum | 25 ------------------------- 2 files changed, 28 deletions(-) diff --git a/go.mod b/go.mod index 69a16795..709d42a7 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 github.com/mdlayher/ndp v1.0.1 - github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.10 github.com/osrg/gobgp/v3 v3.17.0 @@ -74,7 +73,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nxadm/tail v1.4.8 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect @@ -105,7 +103,6 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect diff --git a/go.sum b/go.sum index 862532dd..43e40d9b 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,6 @@ github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckR github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -106,7 +104,6 @@ github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTr github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -190,7 +187,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -285,17 +281,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= @@ -427,7 +414,6 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -450,7 +436,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -498,7 +483,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -509,11 +493,8 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -540,7 +521,6 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -626,7 +606,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -747,15 +726,11 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From ab7ceb8933d2f5979ae3a77cc9fd21379aff06de Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 14:45:16 +0000 Subject: [PATCH 404/542] more fixes Signed-off-by: Dan Finneran --- go.mod | 3 +++ go.sum | 25 +++++++++++++++++++++++++ testing/kubeadm/create_ctr.sh | 12 ++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 709d42a7..07e751d3 100644 --- a/go.mod +++ b/go.mod @@ -73,6 +73,8 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect @@ -103,6 +105,7 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect diff --git a/go.sum b/go.sum index 43e40d9b..862532dd 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,8 @@ github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckR github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -104,6 +106,7 @@ github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTr github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -187,6 +190,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -281,8 +285,17 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= @@ -414,6 +427,7 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -436,6 +450,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -483,6 +498,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -493,8 +509,11 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -521,6 +540,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -606,6 +626,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -726,11 +747,15 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/testing/kubeadm/create_ctr.sh b/testing/kubeadm/create_ctr.sh index 3ebf3b29..aae51575 100755 --- a/testing/kubeadm/create_ctr.sh +++ b/testing/kubeadm/create_ctr.sh @@ -9,11 +9,11 @@ source ./testing/logging.bash install_deps() { echo "Installing Kubernetes dependencies for Kubernetes $kubernetes_version on all nodes" - ssh $NODE01 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE02 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE03 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE04 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" - ssh $NODE05 "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE01 "sudo rm /etc/apt/sources.list.d/* && curl -4 -s -L https://dl.k8s.io/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE02 "sudo rm /etc/apt/sources.list.d/* && curl -4 -s -L https://dl.k8s.io/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE03 "sudo rm /etc/apt/sources.list.d/* && curl -4 -s -L https://dl.k8s.io/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE04 "sudo rm /etc/apt/sources.list.d/* && curl -4 -s -L https://dl.k8s.io/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" + ssh $NODE05 "sudo rm /etc/apt/sources.list.d/* && curl -4 -s -L https://dl.k8s.io/apt/doc/apt-key.gpg | sudo apt-key add && sudo apt-add-repository \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" && sudo apt-get update -q && sudo apt-get install -qy --allow-downgrades kubelet=$kubernetes_version-00 kubectl=$kubernetes_version-00 kubeadm=$kubernetes_version-00" } first_node() { @@ -42,7 +42,7 @@ first_node() { logr "INFO" "Deploying Calico to the Kubernetes Cluster" ssh $NODE01 "kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml" >> $logfile logr "INFO" "Retrieving Join command" - JOIN_CMD=$(ssh $NODE01 " sudo kubeadm token create --print-join-command 2> /dev/null") + JOIN_CMD=$(ssh $NODE01 "kubeadm token create --print-join-command 2> /dev/null") } From 92e13761e450063f806a877fce754c75f4574c00 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Sun, 13 Aug 2023 15:04:39 +0000 Subject: [PATCH 405/542] MORE AND MORE FIXES Signed-off-by: Dan Finneran --- Makefile | 2 +- go.mod | 3 --- go.sum | 25 ------------------------- 3 files changed, 1 insertion(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 3581cd34..5f245c1e 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,7 @@ manifests: @-rm ./kube-vip e2e-tests: - E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/ginkgo -tags=e2e -v -p testing/e2e + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo -tags=e2e -v -p testing/e2e service-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services diff --git a/go.mod b/go.mod index 07e751d3..709d42a7 100644 --- a/go.mod +++ b/go.mod @@ -73,8 +73,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect @@ -105,7 +103,6 @@ require ( google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect diff --git a/go.sum b/go.sum index 862532dd..43e40d9b 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,6 @@ github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckR github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -106,7 +104,6 @@ github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTr github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= @@ -190,7 +187,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -285,17 +281,8 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= @@ -427,7 +414,6 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -450,7 +436,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -498,7 +483,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -509,11 +493,8 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -540,7 +521,6 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -626,7 +606,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -747,15 +726,11 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 5f9dc0a997d93ec4d39ec4ab6498b71aa4d5005f Mon Sep 17 00:00:00 2001 From: Jason Kossis Date: Mon, 14 Aug 2023 08:13:17 -0400 Subject: [PATCH 406/542] initial commit Signed-off-by: Jason Kossis --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5f245c1e..d8f637bb 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL := $(TARGET) # These will be provided to the target -VERSION := v0.6.0 +VERSION := v0.6.1 BUILD := `git rev-parse HEAD` From 74f6785f340ca224293835261144dc45a3bb520c Mon Sep 17 00:00:00 2001 From: James Connor Date: Tue, 15 Aug 2023 15:24:20 +0100 Subject: [PATCH 407/542] Compilation fixes again --- pkg/k8s/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index 2241eec8..b002c90c 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -31,10 +31,10 @@ func NewClientset(configPath string, inCluster bool, hostname string) (*kubernet } func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { + cfg, err := rest.InClusterConfig() + if kubeconfig != "" && !inCluster { cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - } else { - cfg, err := rest.InClusterConfig() } if err != nil { From aa9cb9a49b8cc5b29c0153db62ae898d610961a2 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 15:21:32 +0000 Subject: [PATCH 408/542] Some BIG OLDE e2e tests! Signed-off-by: Dan Finneran --- .github/workflows/ci.yaml | 6 +- Makefile | 7 +- testing/e2e/e2e_test.go | 6 +- testing/e2e/kube-vip.yaml.tmpl | 6 +- testing/e2e/services/controlplane.go | 160 ++++++++++++++++++++++++++ testing/e2e/services/kind-config.yaml | 4 +- testing/e2e/services/kind.go | 114 ++++++++++++++++-- testing/e2e/services/kubernetes.go | 17 ++- testing/e2e/services/services.go | 112 +++++++----------- testing/e2e/services/tests.go | 120 +++++++++++++++++++ 10 files changed, 453 insertions(+), 99 deletions(-) create mode 100644 testing/e2e/services/controlplane.go create mode 100644 testing/e2e/services/tests.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 959f1976..c9a1dff2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,9 +20,7 @@ jobs: run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.53.3 - name: checks run: make check - - name: test docker build - run: make dockerx86Action - - name: e2e controlplane - run: DOCKERTAG=action make e2e-tests + - name: test docker build (with iptables) + run: make dockerx86ActionIPTables - name: e2e services run: DOCKERTAG=action make service-tests diff --git a/Makefile b/Makefile index 5f245c1e..88d0d9db 100644 --- a/Makefile +++ b/Makefile @@ -81,6 +81,11 @@ dockerx86Action: @docker buildx build --platform linux/amd64 --load -t $(REPOSITORY)/$(TARGET):action . @echo New Multi Architecture Docker image created +dockerx86ActionIPTables: + @-rm ./kube-vip + @docker buildx build --platform linux/amd64 -f ./Dockerfile_iptables --load -t $(REPOSITORY)/$(TARGET):action . + @echo New Multi Architecture Docker image created + dockerLocal: @-rm ./kube-vip @docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le,linux/s390x --load -t $(REPOSITORY)/$(TARGET):$(DOCKERTAG) . @@ -115,4 +120,4 @@ e2e-tests: E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run github.com/onsi/ginkgo/v2/ginkgo -tags=e2e -v -p testing/e2e service-tests: - E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services + E2E_IMAGE_PATH=$(REPOSITORY)/$(TARGET):$(DOCKERTAG) go run ./testing/e2e/services -Services diff --git a/testing/e2e/e2e_test.go b/testing/e2e/e2e_test.go index a38252a3..714b9207 100644 --- a/testing/e2e/e2e_test.go +++ b/testing/e2e/e2e_test.go @@ -30,6 +30,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/onsi/gomega/format" "github.com/onsi/gomega/gexec" ) @@ -97,8 +98,9 @@ var _ = Describe("kube-vip broadcast neighbor", func() { manifestPath := filepath.Join(tempDirPath, "kube-vip-ipv4.yaml") - for i := 0; i < 3; i++ { + for i := 0; i < 2; i++ { clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{ + Role: kindconfigv1alpha4.ControlPlaneRole, ExtraMounts: []kindconfigv1alpha4.Mount{ { HostPath: manifestPath, @@ -211,7 +213,7 @@ func createKindCluster(logger log.Logger, config *v1alpha4.Cluster, clusterName cluster.ProviderWithLogger(logger), cluster.ProviderWithDocker(), ) - + format.UseStringerRepresentation = true // Otherwise error stacks have binary format. Expect(provider.Create( clusterName, cluster.CreateWithV1Alpha4Config(config), diff --git a/testing/e2e/kube-vip.yaml.tmpl b/testing/e2e/kube-vip.yaml.tmpl index 2a82d1f7..c5620914 100644 --- a/testing/e2e/kube-vip.yaml.tmpl +++ b/testing/e2e/kube-vip.yaml.tmpl @@ -8,7 +8,9 @@ spec: containers: - name: kube-vip args: - - start + - manager + - --prometheusHTTPServer + - "" env: - name: vip_arp value: "true" @@ -24,6 +26,8 @@ spec: value: "3" - name: vip_retryperiod value: "1" + - name: cp_enable + value: "true" image: "{{ .ImagePath }}" imagePullPolicy: Never securityContext: diff --git a/testing/e2e/services/controlplane.go b/testing/e2e/services/controlplane.go new file mode 100644 index 00000000..734b9072 --- /dev/null +++ b/testing/e2e/services/controlplane.go @@ -0,0 +1,160 @@ +package main + +import ( + "bufio" + "bytes" + "context" + "encoding/binary" + "fmt" + "html/template" + "io" + "io/ioutil" + "net" + "os" + "os/exec" + "path/filepath" + "strings" + + log "github.com/sirupsen/logrus" + "k8s.io/client-go/kubernetes" +) + +func getKindNetworkSubnetCIDRs() ([]string, error) { + cmd := exec.Command( + "docker", "inspect", "kind", + "--format", `{{ range $i, $a := .IPAM.Config }}{{ println .Subnet }}{{ end }}`, + ) + cmdOut := new(bytes.Buffer) + cmd.Stdout = cmdOut + err := cmd.Run() + if err != nil { + return nil, err + } + reader := bufio.NewReader(cmdOut) + + cidrs := []string{} + for { + line, readErr := reader.ReadString('\n') + if readErr != nil && readErr != io.EOF { + return nil, fmt.Errorf("error finding subnet CIDRs in the Docker \"kind\" network, %s", err) + } + + cidrs = append(cidrs, strings.TrimSpace(line)) + if readErr == io.EOF { + break + } + } + + return cidrs, nil +} + +func generateIPv4VIP() (string, error) { + cidrs, err := getKindNetworkSubnetCIDRs() + if err != nil { + return "", err + } + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + if err != nil { + return "", parseErr + } + if ip.To4() != nil { + mask := binary.BigEndian.Uint32(ipNet.Mask) + start := binary.BigEndian.Uint32(ipNet.IP) + end := (start & mask) | (^mask) + + chosenVIP := make([]byte, 4) + binary.BigEndian.PutUint32(chosenVIP, end-5) + return net.IP(chosenVIP).String(), nil + } + } + return "", fmt.Errorf("could not find any IPv4 CIDRs in the Docker \"kind\" network") +} + +func generateIPv6VIP() (string, error) { + cidrs, err := getKindNetworkSubnetCIDRs() + if err != nil { + return "", err + } + for _, cidr := range cidrs { + ip, ipNet, parseErr := net.ParseCIDR(cidr) + if err != nil { + return "", parseErr + } + if ip.To4() == nil { + lowerMask := binary.BigEndian.Uint64(ipNet.Mask[8:]) + lowerStart := binary.BigEndian.Uint64(ipNet.IP[8:]) + lowerEnd := (lowerStart & lowerMask) | (^lowerMask) + + chosenVIP := make([]byte, 16) + // Copy upper half into chosenVIP + copy(chosenVIP, ipNet.IP[0:8]) + // Copy lower half into chosenVIP + binary.BigEndian.PutUint64(chosenVIP[8:], lowerEnd-5) + return net.IP(chosenVIP).String(), nil + } + } + return "", fmt.Errorf("could not find any IPv6 CIDRs in the Docker \"kind\" network") + +} + +func (config *testConfig) manifestGen() error { + curDir, err := os.Getwd() + if err != nil { + return err + } + templatePath := filepath.Join(curDir, "testing/e2e/kube-vip.yaml.tmpl") + + kubeVIPManifestTemplate, err := template.New("kube-vip.yaml.tmpl").ParseFiles(templatePath) + if err != nil { + return err + } + tempDirPath, err := ioutil.TempDir("", "kube-vip-test") + if err != nil { + return err + } + + var manifestFile *os.File + + if config.IPv6 { + config.Name = fmt.Sprintf("%s-ipv6", filepath.Base(tempDirPath)) + config.ManifestPath = filepath.Join(tempDirPath, "kube-vip-ipv6.yaml") + manifestFile, err = os.Create(config.ManifestPath) + if err != nil { + return err + } + defer manifestFile.Close() + + config.ControlPlaneAddress, err = generateIPv6VIP() + if err != nil { + return err + } + } else { + config.Name = fmt.Sprintf("%s-ipv4", filepath.Base(tempDirPath)) + config.ManifestPath = filepath.Join(tempDirPath, "kube-vip-ipv4.yaml") + manifestFile, err = os.Create(config.ManifestPath) + if err != nil { + return err + } + defer manifestFile.Close() + + config.ControlPlaneAddress, err = generateIPv4VIP() + if err != nil { + return err + } + } + log.Infof("🗃️ Manifest path %s", config.ManifestPath) + err = kubeVIPManifestTemplate.Execute(manifestFile, kubevipManifestValues{ + ControlPlaneVIP: config.ControlPlaneAddress, + ImagePath: config.ImagePath, + }) + return err +} + +func (config *testConfig) startTest(ctx context.Context, clientset *kubernetes.Clientset) error { + if config.ControlPlaneAddress == "" { + log.Fatal("no control plane address exists") + } + + return nil +} diff --git a/testing/e2e/services/kind-config.yaml b/testing/e2e/services/kind-config.yaml index 58644b0d..2eaffe06 100644 --- a/testing/e2e/services/kind-config.yaml +++ b/testing/e2e/services/kind-config.yaml @@ -3,7 +3,9 @@ kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane +- role: control-plane +- role: control-plane - role: worker - role: worker - role: worker -EOF + diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index e9e2e1c8..3f941762 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -1,7 +1,10 @@ package main import ( + "bytes" + "fmt" "os/exec" + "strings" "time" log "github.com/sirupsen/logrus" @@ -13,7 +16,18 @@ import ( var provider *cluster.Provider -func createKind(imagePath string) error { +type kubevipManifestValues struct { + ControlPlaneVIP string + ImagePath string +} + +type nodeAddresses struct { + node string + addresses []string +} + +func (config *testConfig) createKind() error { + clusterConfig := kindconfigv1alpha4.Cluster{ Networking: kindconfigv1alpha4.Networking{ IPFamily: kindconfigv1alpha4.IPv4Family, @@ -22,17 +36,39 @@ func createKind(imagePath string) error { { Role: kindconfigv1alpha4.ControlPlaneRole, }, - { - Role: kindconfigv1alpha4.WorkerRole, - }, - { - Role: kindconfigv1alpha4.WorkerRole, - }, - { - Role: kindconfigv1alpha4.WorkerRole, - }, }, } + if config.IPv6 { + // Change Networking Family + clusterConfig.Networking.IPFamily = kindconfigv1alpha4.IPv6Family + } + + if config.ControlPlane { + err := config.manifestGen() + if err != nil { + return err + } + + // Add two additional control plane nodes (3) + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{Role: kindconfigv1alpha4.ControlPlaneRole}) + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{Role: kindconfigv1alpha4.ControlPlaneRole}) + + // Add the extra static pod manifest + mount := kindconfigv1alpha4.Mount{ + HostPath: config.ManifestPath, + ContainerPath: "/etc/kubernetes/manifests/kube-vip.yaml", + } + for x := range clusterConfig.Nodes { + if clusterConfig.Nodes[x].Role == kindconfigv1alpha4.ControlPlaneRole { + clusterConfig.Nodes[x].ExtraMounts = append(clusterConfig.Nodes[x].ExtraMounts, mount) + } + } + } else { + // Add three additional worker nodes + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{Role: kindconfigv1alpha4.WorkerRole}) + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{Role: kindconfigv1alpha4.WorkerRole}) + clusterConfig.Nodes = append(clusterConfig.Nodes, kindconfigv1alpha4.Node{Role: kindconfigv1alpha4.WorkerRole}) + } provider = cluster.NewProvider(cluster.ProviderWithLogger(cmd.NewLogger()), cluster.ProviderWithDocker()) clusters, err := provider.List() @@ -53,11 +89,25 @@ func createKind(imagePath string) error { } loadImageCmd := load.NewCommand(cmd.NewLogger(), cmd.StandardIOStreams()) - loadImageCmd.SetArgs([]string{"--name", "services", imagePath}) + loadImageCmd.SetArgs([]string{"--name", "services", config.ImagePath}) err = loadImageCmd.Execute() if err != nil { return err } + nodes, err := provider.ListNodes("services") + if err != nil { + return err + } + + // HMMM, if we want to run workloads on the control planes (todo) + if config.ControlPlane { + for x := range nodes { + cmd := exec.Command("kubectl", "taint", "nodes", nodes[x].String(), "node-role.kubernetes.io/control-plane:NoSchedule-") + if _, err := cmd.CombinedOutput(); err != nil { + //return err + } + } + } cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") if _, err := cmd.CombinedOutput(); err != nil { return err @@ -80,3 +130,45 @@ func deleteKind() error { log.Info("🧽 deleting Kind cluster") return provider.Delete("services", "") } + +func getAddressesOnNodes() ([]nodeAddresses, error) { + nodesConfig := []nodeAddresses{} + nodes, err := provider.ListNodes("services") + if err != nil { + return nodesConfig, err + } + for x := range nodes { + var b bytes.Buffer + + exec := nodes[x].Command("hostname", "--all-ip-addresses") + exec.SetStderr(&b) + exec.SetStdin(&b) + exec.SetStdout(&b) + err = exec.Run() + if err != nil { + return nodesConfig, err + } + nodesConfig = append(nodesConfig, nodeAddresses{ + node: nodes[x].String(), + addresses: strings.Split(b.String(), " "), + }) + } + return nodesConfig, nil +} + +func checkNodesForDuplicateAddresses(nodes []nodeAddresses, address string) error { + var foundOnNode []string + // Iterate over all nodes to find addresses, where there is an address match add to array + for x := range nodes { + for y := range nodes[x].addresses { + if nodes[x].addresses[y] == address { + foundOnNode = append(foundOnNode, nodes[x].node) + } + } + } + // If one address is on mulitple nodes, then something has gone wrong + if len(foundOnNode) > 1 { + return fmt.Errorf("‼️ multiple nodes [%s] have address [%s]", strings.Join(foundOnNode, " "), address) + } + return nil +} diff --git a/testing/e2e/services/kubernetes.go b/testing/e2e/services/kubernetes.go index 65182819..114c204c 100644 --- a/testing/e2e/services/kubernetes.go +++ b/testing/e2e/services/kubernetes.go @@ -33,7 +33,7 @@ type deployment struct { name string } -func (d *deployment) createKVDs(ctx context.Context, clientset *kubernetes.Clientset) error { +func (d *deployment) createKVDs(ctx context.Context, clientset *kubernetes.Clientset, imagepath string) error { ds := appsv1.DaemonSet{ ObjectMeta: metav1.ObjectMeta{ Name: "kube-vip-ds", @@ -92,7 +92,7 @@ func (d *deployment) createKVDs(ctx context.Context, clientset *kubernetes.Clien Value: "true", }, }, - Image: "plndr/kube-vip:dev", + Image: imagepath, Name: "kube-vip", SecurityContext: &v1.SecurityContext{ Capabilities: &v1.Capabilities{ @@ -193,7 +193,7 @@ func (d *deployment) createDeployment(ctx context.Context, clientset *kubernetes return nil } -func (s *service) createService(ctx context.Context, clientset *kubernetes.Clientset) (string, string, error) { +func (s *service) createService(ctx context.Context, clientset *kubernetes.Clientset) (currentLeader string, loadBalancerAddress string, err error) { svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: s.name, @@ -228,7 +228,7 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien } log.Infof("🌍 creating service [%s]", svc.Name) - _, err := clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, svc, metav1.CreateOptions{}) + _, err = clientset.CoreV1().Services(v1.NamespaceDefault).Create(ctx, svc, metav1.CreateOptions{}) if err != nil { log.Fatal(err) } @@ -247,8 +247,7 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien rw.Stop() }() ready := false - testAddress := "" - currentLeader := "" + // Used for tracking an active endpoint / pod for event := range ch { @@ -264,7 +263,7 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien if len(svc.Status.LoadBalancer.Ingress) != 0 { log.Infof("🔎 found load balancer address [%s] on node [%s]", svc.Status.LoadBalancer.Ingress[0].IP, svc.Annotations["kube-vip.io/vipHost"]) ready = true - testAddress = svc.Status.LoadBalancer.Ingress[0].IP + loadBalancerAddress = svc.Status.LoadBalancer.Ingress[0].IP currentLeader = svc.Annotations["kube-vip.io/vipHost"] } } @@ -276,11 +275,11 @@ func (s *service) createService(ctx context.Context, clientset *kubernetes.Clien } } if s.testHTTP { - err = httpTest(testAddress) + err = httpTest(loadBalancerAddress) if err != nil { return "", "", fmt.Errorf("web retrieval timeout ") } } - return currentLeader, testAddress, nil + return currentLeader, loadBalancerAddress, nil } diff --git a/testing/e2e/services/services.go b/testing/e2e/services/services.go index bc3babde..ed815235 100644 --- a/testing/e2e/services/services.go +++ b/testing/e2e/services/services.go @@ -7,13 +7,11 @@ import ( "net" "net/http" "os" - "path/filepath" "time" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" - "github.com/kube-vip/kube-vip/pkg/k8s" log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,59 +24,14 @@ import ( // 1. Create a deployment // 2. Expose the deployment -func main() { - log.Info("🔬 beginning e2e tests") - - var testCount int - imagePath := os.Getenv("E2E_IMAGE_PATH") - - _, ignoreSimple := os.LookupEnv("IGNORE_SIMPLE") - _, ignoreDeployments := os.LookupEnv("IGNORE_DEPLOY") - _, ignoreLeaderFailover := os.LookupEnv("IGNORE_LEADER") - _, ignoreLeaderActive := os.LookupEnv("IGNORE_ACTIVE") - _, ignoreLocalDeploy := os.LookupEnv("IGNORE_LOCALDEPLOY") - _, ignoreEgress := os.LookupEnv("IGNORE_EGRESS") - _, retainCluster := os.LookupEnv("RETAIN_CLUSTER") - err := createKind(imagePath) - - if !retainCluster { - if err != nil { - log.Fatal(err) - } - defer func() { - err := deleteKind() - if err != nil { - log.Fatal(err) - } - }() - } else { - if err != nil { - log.Warn(err) - } - } - +func (config *testConfig) startServiceTest(ctx context.Context, clientset *kubernetes.Clientset) { nodeTolerate := os.Getenv("NODE_TOLERATE") d := "kube-vip-deploy" s := "kube-vip-service" l := "kube-vip-deploy-leader" - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() - homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") - clientset, err := k8s.NewClientset(homeConfigPath, false, "") - if err != nil { - log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) - } - log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) - - deploy := deployment{} - err = deploy.createKVDs(ctx, clientset) - if err != nil { - log.Error(err) - } - - if !ignoreSimple { + if !config.ignoreSimple { // Simple Deployment test log.Infof("🧪 ---> simple deployment <---") deploy := deployment{ @@ -87,7 +40,7 @@ func main() { replicas: 2, server: true, } - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -99,7 +52,7 @@ func main() { if err != nil { log.Error(err) } else { - testCount++ + config.successCounter++ } log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) @@ -112,7 +65,7 @@ func main() { log.Fatal(err) } } - if !ignoreDeployments { + if !config.ignoreDeployments { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments <---") deploy := deployment{ @@ -121,7 +74,7 @@ func main() { replicas: 2, server: true, } - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -137,7 +90,7 @@ func main() { if err != nil { log.Fatal(err) } - testCount++ + config.successCounter++ } for i := 1; i < 5; i++ { log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) @@ -152,7 +105,7 @@ func main() { log.Fatal(err) } } - if !ignoreLeaderFailover { + if !config.ignoreLeaderFailover { // Failover tests log.Infof("🧪 ---> leader failover deployment (local policy) <---") @@ -162,7 +115,7 @@ func main() { replicas: 2, server: true, } - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -172,7 +125,7 @@ func main() { policyLocal: true, testHTTP: true, } - leader, _, err := svc.createService(ctx, clientset) + leader, lbAddress, err := svc.createService(ctx, clientset) if err != nil { log.Error(err) } @@ -181,7 +134,18 @@ func main() { if err != nil { log.Error(err) } else { - testCount++ + config.successCounter++ + } + + // Get all addresses on all nodes + nodes, err := getAddressesOnNodes() + if err != nil { + log.Error(err) + } + // Make sure we don't exist in two places + err = checkNodesForDuplicateAddresses(nodes, lbAddress) + if err != nil { + log.Fatal(err) } log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) @@ -196,7 +160,7 @@ func main() { } } - if !ignoreLeaderActive { + if !config.ignoreLeaderActive { // pod Failover tests log.Infof("🧪 ---> active pod failover deployment (local policy) <---") deploy := deployment{ @@ -205,7 +169,7 @@ func main() { replicas: 1, server: true, } - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -223,7 +187,7 @@ func main() { if err != nil { log.Error(err) } else { - testCount++ + config.successCounter++ } log.Infof("🧹 deleting Service [%s], deployment [%s]", s, d) @@ -236,7 +200,7 @@ func main() { log.Fatal(err) } } - if !ignoreLocalDeploy { + if !config.ignoreLocalDeploy { // Multiple deployment tests log.Infof("🧪 ---> multiple deployments (local policy) <---") deploy := deployment{ @@ -245,7 +209,7 @@ func main() { replicas: 2, server: true, } - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -255,11 +219,19 @@ func main() { name: fmt.Sprintf("%s-%d", s, i), testHTTP: true, } - _, _, err = svc.createService(ctx, clientset) + _, lbAddress, err := svc.createService(ctx, clientset) + if err != nil { + log.Fatal(err) + } + config.successCounter++ + nodes, err := getAddressesOnNodes() + if err != nil { + log.Error(err) + } + err = checkNodesForDuplicateAddresses(nodes, lbAddress) if err != nil { log.Fatal(err) } - testCount++ } for i := 1; i < 5; i++ { log.Infof("🧹 deleting service [%s]", fmt.Sprintf("%s-%d", s, i)) @@ -275,7 +247,7 @@ func main() { } } - if !ignoreEgress { + if !config.ignoreEgress { // pod Failover tests log.Infof("🧪 ---> egress IP re-write (local policy) <---") var egress string @@ -299,7 +271,7 @@ func main() { } log.Infof("📠 found local address [%s]", deploy.address) // Create a deployment that connects back to this machines IP address - err = deploy.createDeployment(ctx, clientset) + err := deploy.createDeployment(ctx, clientset) if err != nil { log.Fatal(err) } @@ -311,7 +283,7 @@ func main() { testHTTP: false, } - _, egress, err := svc.createService(ctx, clientset) + _, egress, err = svc.createService(ctx, clientset) if err != nil { log.Fatal(err) } @@ -319,7 +291,7 @@ func main() { for i := 1; i < 5; i++ { if found { log.Infof("🕵️ egress has correct IP address") - testCount++ + config.successCounter++ break } time.Sleep(time.Second * 1) @@ -337,7 +309,7 @@ func main() { if err != nil { log.Fatal(err) } - log.Infof("🏆 Testing Complete [%d] passed", testCount) + log.Infof("🏆 Testing Complete [%d] passed", config.successCounter) } } diff --git a/testing/e2e/services/tests.go b/testing/e2e/services/tests.go new file mode 100644 index 00000000..b3355bf2 --- /dev/null +++ b/testing/e2e/services/tests.go @@ -0,0 +1,120 @@ +package main + +import ( + "context" + "flag" + "os" + "path/filepath" + + "github.com/kube-vip/kube-vip/pkg/k8s" + log "github.com/sirupsen/logrus" +) + +type testConfig struct { + successCounter int + + ImagePath string + + ControlPlane bool + // control plane settings + Name string + ControlPlaneAddress string + ManifestPath string + IPv6 bool + + Services bool + // service tests + ignoreSimple bool + ignoreDeployments bool + ignoreLeaderFailover bool + ignoreLeaderActive bool + ignoreLocalDeploy bool + ignoreEgress bool + retainCluster bool +} + +func main() { + var t testConfig + + t.ImagePath = os.Getenv("E2E_IMAGE_PATH") + + _, t.ignoreSimple = os.LookupEnv("IGNORE_SIMPLE") + _, t.ignoreDeployments = os.LookupEnv("IGNORE_DEPLOY") + _, t.ignoreLeaderFailover = os.LookupEnv("IGNORE_LEADER") + _, t.ignoreLeaderActive = os.LookupEnv("IGNORE_ACTIVE") + _, t.ignoreLocalDeploy = os.LookupEnv("IGNORE_LOCALDEPLOY") + _, t.ignoreEgress = os.LookupEnv("IGNORE_EGRESS") + _, t.retainCluster = os.LookupEnv("RETAIN_CLUSTER") + + flag.StringVar(&t.ImagePath, "imagepath", "plndr/kube-vip:action", "") + flag.BoolVar(&t.ControlPlane, "ControlPlane", false, "") + flag.BoolVar(&t.Services, "Services", false, "") + + flag.Parse() + + log.Infof("🔬 beginning e2e tests, image: [%s]", t.ImagePath) + + if t.ControlPlane { + err := t.createKind() + if !t.retainCluster { + if err != nil { + log.Fatal(err) + } + defer func() { + err := deleteKind() + if err != nil { + log.Fatal(err) + } + }() + } else { + if err != nil { + log.Warn(err) + } + } + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") + clientset, err := k8s.NewClientset(homeConfigPath, false, "") + if err != nil { + log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) + } + log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + t.startTest(ctx, clientset) + } + + if t.Services { + err := t.createKind() + if !t.retainCluster { + if err != nil { + log.Fatal(err) + } + defer func() { + err := deleteKind() + if err != nil { + log.Fatal(err) + } + }() + } else { + if err != nil { + log.Warn(err) + } + } + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") + clientset, err := k8s.NewClientset(homeConfigPath, false, "") + if err != nil { + log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) + } + log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + + // Deplopy the daemonset for kube-vip + deploy := deployment{} + err = deploy.createKVDs(ctx, clientset, t.ImagePath) + if err != nil { + log.Error(err) + } + t.startServiceTest(ctx, clientset) + } + +} From 6a71e264da352d6c71b0f9de90e5e68b10b5075d Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 15:25:30 +0000 Subject: [PATCH 409/542] This makes sure we check if a services is active Signed-off-by: Dan Finneran --- pkg/manager/watch_services.go | 110 ++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index fdfdcfcd..454a5b7a 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -128,78 +128,82 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context // Scenarios: // 1. - wg.Add(1) - activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) - // Background the services election - if sm.config.EnableServicesElection { - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Start an endpoint watcher if we're not watching it already - if !watchedService[string(svc.UID)] { - // background the endpoint watcher - go func() { - if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { - // Add Endpoint watcher - wg.Add(1) - err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) - if err != nil { - log.Error(err) + if !activeService[string(svc.UID)] { + wg.Add(1) + activeServiceLoadBalancer[string(svc.UID)], activeServiceLoadBalancerCancel[string(svc.UID)] = context.WithCancel(context.TODO()) + // Background the services election + if sm.config.EnableServicesElection { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Start an endpoint watcher if we're not watching it already + if !watchedService[string(svc.UID)] { + // background the endpoint watcher + go func() { + if svc.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal { + // Add Endpoint watcher + wg.Add(1) + err = sm.watchEndpoint(activeServiceLoadBalancer[string(svc.UID)], id, svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() } - wg.Done() + }() + // We're now watching this service + watchedService[string(svc.UID)] = true + } + } else { + // Increment the waitGroup before the service Func is called (Done is completed in there) + wg.Add(1) + go func() { + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) } + wg.Done() }() - // We're now watching this service - watchedService[string(svc.UID)] = true } + activeService[string(svc.UID)] = true } else { // Increment the waitGroup before the service Func is called (Done is completed in there) wg.Add(1) - go func() { - err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) - if err != nil { - log.Error(err) - } - wg.Done() - }() - } - } else { - // Increment the waitGroup before the service Func is called (Done is completed in there) - wg.Add(1) - err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) - if err != nil { - log.Error(err) + err = serviceFunc(activeServiceLoadBalancer[string(svc.UID)], svc, &wg) + if err != nil { + log.Error(err) + } + wg.Done() } - wg.Done() } case watch.Deleted: svc, ok := event.Object.(*v1.Service) if !ok { return fmt.Errorf("unable to parse Kubernetes services from API watcher") } + if activeService[string(svc.UID)] { - // We only care about LoadBalancer services - if svc.Spec.Type != v1.ServiceTypeLoadBalancer { - break - } + // We only care about LoadBalancer services + if svc.Spec.Type != v1.ServiceTypeLoadBalancer { + break + } - // We can ignore this service - if svc.Annotations["kube-vip.io/ignore"] == "true" { - log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) - break - } - // If this is an active service then and additional leaderElection will handle stopping - err := sm.deleteService(string(svc.UID)) - if err != nil { - log.Error(err) - } + // We can ignore this service + if svc.Annotations["kube-vip.io/ignore"] == "true" { + log.Infof("service [%s] has an ignore annotation for kube-vip", svc.Name) + break + } + // If this is an active service then and additional leaderElection will handle stopping + err := sm.deleteService(string(svc.UID)) + if err != nil { + log.Error(err) + } - // Calls the cancel function of the context - if activeServiceLoadBalancerCancel[string(svc.UID)] != nil { + // Calls the cancel function of the context + if activeServiceLoadBalancerCancel[string(svc.UID)] != nil { - activeServiceLoadBalancerCancel[string(svc.UID)]() + activeServiceLoadBalancerCancel[string(svc.UID)]() + } + activeService[string(svc.UID)] = false + watchedService[string(svc.UID)] = false } - activeService[string(svc.UID)] = false - watchedService[string(svc.UID)] = false - log.Infof("service [%s/%s] has been deleted", svc.Namespace, svc.Name) case watch.Bookmark: // Un-used From bc63ed2ee56ecbea61323784ea1c1011b20f1fa7 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 15:32:25 +0000 Subject: [PATCH 410/542] lint fixes Signed-off-by: Dan Finneran --- testing/e2e/services/controlplane.go | 14 ++++++-------- testing/e2e/services/kind.go | 8 +++----- testing/e2e/services/tests.go | 21 ++++++++++++--------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/testing/e2e/services/controlplane.go b/testing/e2e/services/controlplane.go index 734b9072..8ab1634b 100644 --- a/testing/e2e/services/controlplane.go +++ b/testing/e2e/services/controlplane.go @@ -3,7 +3,6 @@ package main import ( "bufio" "bytes" - "context" "encoding/binary" "fmt" "html/template" @@ -16,7 +15,6 @@ import ( "strings" log "github.com/sirupsen/logrus" - "k8s.io/client-go/kubernetes" ) func getKindNetworkSubnetCIDRs() ([]string, error) { @@ -151,10 +149,10 @@ func (config *testConfig) manifestGen() error { return err } -func (config *testConfig) startTest(ctx context.Context, clientset *kubernetes.Clientset) error { - if config.ControlPlaneAddress == "" { - log.Fatal("no control plane address exists") - } +// func (config *testConfig) startTest(ctx context.Context, clientset *kubernetes.Clientset) error { +// if config.ControlPlaneAddress == "" { +// log.Fatal("no control plane address exists") +// } - return nil -} +// return nil +// } diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index 3f941762..5961a367 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -102,10 +102,8 @@ func (config *testConfig) createKind() error { // HMMM, if we want to run workloads on the control planes (todo) if config.ControlPlane { for x := range nodes { - cmd := exec.Command("kubectl", "taint", "nodes", nodes[x].String(), "node-role.kubernetes.io/control-plane:NoSchedule-") - if _, err := cmd.CombinedOutput(); err != nil { - //return err - } + cmd := exec.Command("kubectl", "taint", "nodes", nodes[x].String(), "node-role.kubernetes.io/control-plane:NoSchedule-") //nolint:all + cmd.CombinedOutput() } } cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") @@ -166,7 +164,7 @@ func checkNodesForDuplicateAddresses(nodes []nodeAddresses, address string) erro } } } - // If one address is on mulitple nodes, then something has gone wrong + // If one address is on multiple nodes, then something has gone wrong if len(foundOnNode) > 1 { return fmt.Errorf("‼️ multiple nodes [%s] have address [%s]", strings.Join(foundOnNode, " "), address) } diff --git a/testing/e2e/services/tests.go b/testing/e2e/services/tests.go index b3355bf2..a5400fa9 100644 --- a/testing/e2e/services/tests.go +++ b/testing/e2e/services/tests.go @@ -71,15 +71,18 @@ func main() { log.Warn(err) } } - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() - homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") - clientset, err := k8s.NewClientset(homeConfigPath, false, "") - if err != nil { - log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) - } - log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) - t.startTest(ctx, clientset) + // ctx, cancel := context.WithCancel(context.TODO()) + // defer cancel() + // homeConfigPath := filepath.Join(os.Getenv("HOME"), ".kube", "config") + // clientset, err := k8s.NewClientset(homeConfigPath, false, "") + // if err != nil { + // log.Fatalf("could not create k8s clientset from external file: %q: %v", homeConfigPath, err) + // } + // log.Debugf("Using external Kubernetes configuration from file [%s]", homeConfigPath) + // err = t.startTest(ctx, clientset) + // if err != nil { + // log.Fatal(err) + // } } if t.Services { From a18e26dbc389da9e11a09f95ca46a5ad5dbbc55f Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 16:46:19 +0000 Subject: [PATCH 411/542] more_lint Signed-off-by: Dan Finneran --- testing/e2e/services/controlplane.go | 3 +-- testing/e2e/services/kind.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/e2e/services/controlplane.go b/testing/e2e/services/controlplane.go index 8ab1634b..9dcca25d 100644 --- a/testing/e2e/services/controlplane.go +++ b/testing/e2e/services/controlplane.go @@ -7,7 +7,6 @@ import ( "fmt" "html/template" "io" - "io/ioutil" "net" "os" "os/exec" @@ -107,7 +106,7 @@ func (config *testConfig) manifestGen() error { if err != nil { return err } - tempDirPath, err := ioutil.TempDir("", "kube-vip-test") + tempDirPath, err := os.MkdirTemp("", "kube-vip-test") if err != nil { return err } diff --git a/testing/e2e/services/kind.go b/testing/e2e/services/kind.go index 5961a367..78310349 100644 --- a/testing/e2e/services/kind.go +++ b/testing/e2e/services/kind.go @@ -103,7 +103,7 @@ func (config *testConfig) createKind() error { if config.ControlPlane { for x := range nodes { cmd := exec.Command("kubectl", "taint", "nodes", nodes[x].String(), "node-role.kubernetes.io/control-plane:NoSchedule-") //nolint:all - cmd.CombinedOutput() + _, _ = cmd.CombinedOutput() } } cmd := exec.Command("kubectl", "create", "configmap", "--namespace", "kube-system", "kubevip", "--from-literal", "range-global=172.18.100.10-172.18.100.30") From baba79e6adf457e953b41a6a8e4351feb3e1b584 Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 18:16:58 +0000 Subject: [PATCH 412/542] Fix to main Signed-off-by: Dan Finneran --- pkg/k8s/client.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index b002c90c..2414ef1d 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -32,15 +32,17 @@ func NewClientset(configPath string, inCluster bool, hostname string) (*kubernet func restConfig(kubeconfig string, inCluster bool) (*rest.Config, error) { cfg, err := rest.InClusterConfig() - + if kubeconfig != "" && !inCluster { - cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig) } - + if err != nil { return nil, err } - + + // Override some of the defaults allowing a little bit more flexibility speaking with the API server + // these should hopefully be redundant, however issues will still be logged. cfg.QPS = 100 cfg.Burst = 250 return cfg, nil From 92338ae74ff936d18fb6c673c655ba22fb459fda Mon Sep 17 00:00:00 2001 From: Dan Finneran Date: Tue, 15 Aug 2023 18:40:47 +0000 Subject: [PATCH 413/542] action fix Signed-off-by: Dan Finneran --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 75d55714..87fd2e2b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -53,7 +53,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -67,4 +67,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From b4f55546700da6a1f53e679dbdab1b5f7785d716 Mon Sep 17 00:00:00 2001 From: usiegl00 <50933431+usiegl00@users.noreply.github.com> Date: Thu, 17 Aug 2023 05:03:36 +0900 Subject: [PATCH 414/542] Fix dos through checking for remaining services before releasing ip. Fixes #600 Signed-off-by: usiegl00 <50933431+usiegl00@users.noreply.github.com> --- pkg/manager/services.go | 43 ++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index f3708609..f6fd6604 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -167,6 +167,7 @@ func (sm *Manager) deleteService(uid string) error { defer sm.mutex.Unlock() var updatedInstances []*Instance + var serviceInstance *Instance found := false for x := range sm.serviceInstances { log.Debugf("Looking for [%s], found [%s]", uid, sm.serviceInstances[x].UID) @@ -176,10 +177,26 @@ func (sm *Manager) deleteService(uid string) error { } else { // Flip the found when we match found = true - sm.serviceInstances[x].cluster.Stop() - if sm.serviceInstances[x].isDHCP { - sm.serviceInstances[x].dhcpClient.Stop() - macvlan, err := netlink.LinkByName(sm.serviceInstances[x].dhcpInterface) + serviceInstance = sm.serviceInstances[x] + } + } + // If we've been through all services and not found the correct one then error + if !found { + // TODO: - fix UX + // return fmt.Errorf("unable to find/stop service [%s]", uid) + return nil + } else { + shared := false + for x := range updatedInstances { + if updatedInstances[x].Vip == serviceInstance.Vip { + shared = true + } + } + if !shared { + serviceInstance.cluster.Stop() + if serviceInstance.isDHCP { + serviceInstance.dhcpClient.Stop() + macvlan, err := netlink.LinkByName(serviceInstance.dhcpInterface) if err != nil { return fmt.Errorf("error finding VIP Interface: %v", err) } @@ -189,18 +206,18 @@ func (sm *Manager) deleteService(uid string) error { return fmt.Errorf("error deleting DHCP Link : %v", err) } } - if sm.serviceInstances[x].vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", sm.serviceInstances[x].vipConfig.VIP, sm.serviceInstances[x].vipConfig.VIPCIDR) + if serviceInstance.vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfig.VIP, serviceInstance.vipConfig.VIPCIDR) err := sm.bgpServer.DelHost(cidrVip) return err } // We will need to tear down the egress - if sm.serviceInstances[x].serviceSnapshot.Annotations[egress] == "true" { - if sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint] != "" { + if serviceInstance.serviceSnapshot.Annotations[egress] == "true" { + if serviceInstance.serviceSnapshot.Annotations[endpoint] != "" { - log.Infof("service [%s] has an egress re-write enabled", sm.serviceInstances[x].serviceSnapshot.Name) - err := sm.TeardownEgress(sm.serviceInstances[x].serviceSnapshot.Annotations[endpoint], sm.serviceInstances[x].serviceSnapshot.Spec.LoadBalancerIP, sm.serviceInstances[x].serviceSnapshot.Annotations[egressDestinationPorts], sm.serviceInstances[x].serviceSnapshot.Namespace) + log.Infof("service [%s] has an egress re-write enabled", serviceInstance.serviceSnapshot.Name) + err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[endpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) if err != nil { log.Errorf("%v", err) } @@ -208,12 +225,6 @@ func (sm *Manager) deleteService(uid string) error { } } } - // If we've been through all services and not found the correct one then error - if !found { - // TODO: - fix UX - // return fmt.Errorf("unable to find/stop service [%s]", uid) - return nil - } // Update the service array sm.serviceInstances = updatedInstances From 9c84c5695965aabc7747bb41d81fb4382c9adab8 Mon Sep 17 00:00:00 2001 From: usiegl00 <50933431+usiegl00@users.noreply.github.com> Date: Fri, 18 Aug 2023 03:42:40 +0900 Subject: [PATCH 415/542] Fix formatting to pass lint. Signed-off-by: usiegl00 <50933431+usiegl00@users.noreply.github.com> --- pkg/manager/services.go | 61 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/pkg/manager/services.go b/pkg/manager/services.go index f6fd6604..77a0dd3f 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -185,42 +185,41 @@ func (sm *Manager) deleteService(uid string) error { // TODO: - fix UX // return fmt.Errorf("unable to find/stop service [%s]", uid) return nil - } else { - shared := false - for x := range updatedInstances { - if updatedInstances[x].Vip == serviceInstance.Vip { - shared = true - } + } + shared := false + for x := range updatedInstances { + if updatedInstances[x].Vip == serviceInstance.Vip { + shared = true } - if !shared { - serviceInstance.cluster.Stop() - if serviceInstance.isDHCP { - serviceInstance.dhcpClient.Stop() - macvlan, err := netlink.LinkByName(serviceInstance.dhcpInterface) - if err != nil { - return fmt.Errorf("error finding VIP Interface: %v", err) - } - - err = netlink.LinkDel(macvlan) - if err != nil { - return fmt.Errorf("error deleting DHCP Link : %v", err) - } + } + if !shared { + serviceInstance.cluster.Stop() + if serviceInstance.isDHCP { + serviceInstance.dhcpClient.Stop() + macvlan, err := netlink.LinkByName(serviceInstance.dhcpInterface) + if err != nil { + return fmt.Errorf("error finding VIP Interface: %v", err) } - if serviceInstance.vipConfig.EnableBGP { - cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfig.VIP, serviceInstance.vipConfig.VIPCIDR) - err := sm.bgpServer.DelHost(cidrVip) - return err + + err = netlink.LinkDel(macvlan) + if err != nil { + return fmt.Errorf("error deleting DHCP Link : %v", err) } + } + if serviceInstance.vipConfig.EnableBGP { + cidrVip := fmt.Sprintf("%s/%s", serviceInstance.vipConfig.VIP, serviceInstance.vipConfig.VIPCIDR) + err := sm.bgpServer.DelHost(cidrVip) + return err + } - // We will need to tear down the egress - if serviceInstance.serviceSnapshot.Annotations[egress] == "true" { - if serviceInstance.serviceSnapshot.Annotations[endpoint] != "" { + // We will need to tear down the egress + if serviceInstance.serviceSnapshot.Annotations[egress] == "true" { + if serviceInstance.serviceSnapshot.Annotations[endpoint] != "" { - log.Infof("service [%s] has an egress re-write enabled", serviceInstance.serviceSnapshot.Name) - err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[endpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) - if err != nil { - log.Errorf("%v", err) - } + log.Infof("service [%s] has an egress re-write enabled", serviceInstance.serviceSnapshot.Name) + err := sm.TeardownEgress(serviceInstance.serviceSnapshot.Annotations[endpoint], serviceInstance.serviceSnapshot.Spec.LoadBalancerIP, serviceInstance.serviceSnapshot.Annotations[egressDestinationPorts], serviceInstance.serviceSnapshot.Namespace) + if err != nil { + log.Errorf("%v", err) } } } From f7666067a49f04922c469198924b200dc8405084 Mon Sep 17 00:00:00 2001 From: Daniel Finneran Date: Thu, 24 Aug 2023 09:01:16 +0100 Subject: [PATCH 416/542] Update Makefile for new release --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d983120e..33e4b544 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TARGET := kube-vip .DEFAULT_GOAL := $(TARGET) # These will be provided to the target -VERSION := v0.6.1 +VERSION := v0.6.2 BUILD := `git rev-parse HEAD` From 55398e6cfc424f218c9af92a3ae1e5386210eb17 Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Mon, 4 Sep 2023 16:35:09 +0200 Subject: [PATCH 417/542] add routing table type environment variable Signed-off-by: Timo Sluis --- pkg/cluster/cluster.go | 2 +- pkg/kubevip/config_environment.go | 10 ++++++++++ pkg/kubevip/config_envvar.go | 3 +++ pkg/kubevip/config_types.go | 3 +++ pkg/vip/address.go | 5 ++++- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 574f77ef..8dfea26f 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -46,7 +46,7 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { address = c.Address } - network, err := vip.NewConfig(address, c.Interface, c.VIPSubnet, c.DDNS, c.RoutingTableID) + network, err := vip.NewConfig(address, c.Interface, c.VIPSubnet, c.DDNS, c.RoutingTableID, c.RoutingTableType) if err != nil { return nil, err } diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 6b7498e4..8429e604 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -274,6 +274,16 @@ func ParseEnvironment(c *Config) error { c.EnableRoutingTable = b } + // Routing Table Type + env = os.Getenv(vipRoutingTableType) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.RoutingTableType = int(i) + } + // BGP Server options env = os.Getenv(bgpEnable) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 25b45649..0587d620 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -121,6 +121,9 @@ const ( // vipRoutingTable - defines if table mode will be used for vips vipRoutingTable = "vip_routingtable" //nolint + // vipRoutingTableType - defines which table type will be used for vip routes + vipRoutingTableType = "vip_routingtabletype" //nolint + // cpNamespace defines the namespace the control plane pods will run in cpNamespace = "cp_namespace" diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 5f61a0dc..9d00a1ba 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -23,6 +23,9 @@ type Config struct { // EnableRoutingTable, will use the routing table to advertise the VIP address EnableRoutingTable bool `yaml:"enableRoutingTable"` + // EnableRoutingTable, what sort of route should be added to the routing table + RoutingTableType int `yaml:"routingTableType"` + // EnableControlPlane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPlane bool `yaml:"enableControlPlane"` diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 98e27991..6aa69d3c 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -54,6 +54,7 @@ type network struct { isDDNS bool routeTable int + routingTableType int } func netlinkParse(addr string) (*netlink.Addr, error) { @@ -65,7 +66,7 @@ func netlinkParse(addr string) (*netlink.Addr, error) { } // NewConfig will attempt to provide an interface to the kernel network configuration -func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID int) (Network, error) { +func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID int, tableType int) (Network, error) { result := &network{} link, err := netlink.LinkByName(iface) @@ -75,6 +76,7 @@ func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID result.link = link result.routeTable = tableID + result.routingTableType = tableType if IsIP(address) { // Check if the subnet needs overriding @@ -127,6 +129,7 @@ func (configurator *network) AddRoute() error { Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, + Type: configurator.routingTableType, } return netlink.RouteAdd(route) } From 9fbe98c5d9de72637e1891f08be09b794e6be62d Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Mon, 4 Sep 2023 16:45:47 +0200 Subject: [PATCH 418/542] gofmt Signed-off-by: Timo Sluis --- pkg/vip/address.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 6aa69d3c..7ade3e0e 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -53,7 +53,7 @@ type network struct { dnsName string isDDNS bool - routeTable int + routeTable int routingTableType int } @@ -129,7 +129,7 @@ func (configurator *network) AddRoute() error { Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, - Type: configurator.routingTableType, + Type: configurator.routingTableType, } return netlink.RouteAdd(route) } From 6d47329f7cba358d5b1aa38074f26c7bfe981841 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Mon, 4 Sep 2023 20:47:56 +0200 Subject: [PATCH 419/542] added create rbac settings section for kind --- docs/usage/kind/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/usage/kind/index.md b/docs/usage/kind/index.md index f9f558fe..f8edd13e 100644 --- a/docs/usage/kind/index.md +++ b/docs/usage/kind/index.md @@ -4,6 +4,12 @@ The documentation for KIND is fantastic and its [quick start](https://kind.sigs.k8s.io/docs/user/quick-start/) guide will have you up and running in no time. +## Create RBAC settings + +``` +kubectl apply -f https://kube-vip.io/manifests/rbac.yaml +``` + ## Find Address Pool for Kube-Vip We will need to find addresses that can be used by Kube-Vip: From 8afe5ca155e428b56de0fd411e968a1ff580ada6 Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Thu, 7 Sep 2023 13:34:51 +0200 Subject: [PATCH 420/542] add comment about valid values Signed-off-by: Timo Sluis --- pkg/kubevip/config_envvar.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index 0587d620..e2ff6039 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -122,6 +122,11 @@ const ( vipRoutingTable = "vip_routingtable" //nolint // vipRoutingTableType - defines which table type will be used for vip routes + // valid values for this variable can be found in: + // https://pkg.go.dev/golang.org/x/sys/unix#RTN_UNSPEC + // Note that route type have the prefix `RTN_`, and you + // specify the integer value, not the name. For example: + // you should say `vip_routingtabletype=2` for RTN_LOCAL vipRoutingTableType = "vip_routingtabletype" //nolint // cpNamespace defines the namespace the control plane pods will run in From 724ec2ab10dbd5aa7408352eac615f52d546a283 Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Fri, 8 Sep 2023 15:28:45 +0200 Subject: [PATCH 421/542] specify different scope for local routes Signed-off-by: Timo Sluis --- cmd/kube-vip.go | 1 + pkg/kubevip/config_types.go | 6 +++--- pkg/manager/instance.go | 1 + pkg/vip/address.go | 15 ++++++++++++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1c2945bd..87aa5a78 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -123,6 +123,7 @@ func init() { // Routing Table flags kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableID, "tableID", 198, "The routing table used for all table entries") + kubeVipCmd.PersistentFlags().IntVar(&initConfig.RoutingTableType, "tableType", 0, "The type of route that will be added to the routing table") // Behaviour flags kubeVipCmd.PersistentFlags().BoolVar(&initConfig.EnableControlPlane, "controlplane", false, "Enable HA for control plane") diff --git a/pkg/kubevip/config_types.go b/pkg/kubevip/config_types.go index 9d00a1ba..9fa3876d 100644 --- a/pkg/kubevip/config_types.go +++ b/pkg/kubevip/config_types.go @@ -23,9 +23,6 @@ type Config struct { // EnableRoutingTable, will use the routing table to advertise the VIP address EnableRoutingTable bool `yaml:"enableRoutingTable"` - // EnableRoutingTable, what sort of route should be added to the routing table - RoutingTableType int `yaml:"routingTableType"` - // EnableControlPlane, will enable the control plane functionality (used for hybrid behaviour) EnableControlPlane bool `yaml:"enableControlPlane"` @@ -104,6 +101,9 @@ type Config struct { // Routing Table ID for when using routing table mode RoutingTableID int `yaml:"routingTableID"` + // Routing Table Type, what sort of route should be added to the routing table + RoutingTableType int `yaml:"routingTableType"` + // BGP Configuration BGPConfig bgp.Config BGPPeerConfig bgp.Peer diff --git a/pkg/manager/instance.go b/pkg/manager/instance.go index 1fa96e17..12858c04 100644 --- a/pkg/manager/instance.go +++ b/pkg/manager/instance.go @@ -60,6 +60,7 @@ func NewInstance(svc *v1.Service, config *kubevip.Config) (*Instance, error) { VIPSubnet: config.VIPSubnet, EnableRoutingTable: config.EnableRoutingTable, RoutingTableID: config.RoutingTableID, + RoutingTableType: config.RoutingTableType, ArpBroadcastRate: config.ArpBroadcastRate, EnableServiceSecurity: config.EnableServiceSecurity, } diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 7ade3e0e..8716cc72 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -124,8 +124,12 @@ func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID // AddRoute - Add an IP address to a route table func (configurator *network) AddRoute() error { + route_scope := netlink.SCOPE_UNIVERSE; + if configurator.routingTableType == unix.RTN_LOCAL { + route_scope = netlink.SCOPE_HOST + } route := &netlink.Route{ - Scope: netlink.SCOPE_UNIVERSE, + Scope: route_scope, Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, @@ -134,13 +138,18 @@ func (configurator *network) AddRoute() error { return netlink.RouteAdd(route) } -// AddRoute - Add an IP address to a route table +// DeleteRoute - Delete an IP address from a route table func (configurator *network) DeleteRoute() error { + route_scope := netlink.SCOPE_UNIVERSE; + if configurator.routingTableType == unix.RTN_LOCAL { + route_scope = netlink.SCOPE_HOST + } route := &netlink.Route{ - Scope: netlink.SCOPE_UNIVERSE, + Scope: route_scope, Dst: configurator.address.IPNet, LinkIndex: configurator.link.Attrs().Index, Table: configurator.routeTable, + Type: configurator.routingTableType, } return netlink.RouteDel(route) } From 89d883d0ec03dc9dbcf396edcbbd2274a3d73342 Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Fri, 8 Sep 2023 15:50:24 +0200 Subject: [PATCH 422/542] add routing table id as envvar Signed-off-by: Timo Sluis --- pkg/kubevip/config_environment.go | 10 ++++++++++ pkg/kubevip/config_envvar.go | 3 +++ 2 files changed, 13 insertions(+) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 8429e604..8640cfed 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -274,6 +274,16 @@ func ParseEnvironment(c *Config) error { c.EnableRoutingTable = b } + // Routing Table ID + env = os.Getenv(vipRoutingTableID) + if env != "" { + i, err := strconv.ParseInt(env, 10, 32) + if err != nil { + return err + } + c.RoutingTableID = int(i) + } + // Routing Table Type env = os.Getenv(vipRoutingTableType) if env != "" { diff --git a/pkg/kubevip/config_envvar.go b/pkg/kubevip/config_envvar.go index e2ff6039..c000af76 100644 --- a/pkg/kubevip/config_envvar.go +++ b/pkg/kubevip/config_envvar.go @@ -121,6 +121,9 @@ const ( // vipRoutingTable - defines if table mode will be used for vips vipRoutingTable = "vip_routingtable" //nolint + // vipRoutingTableID - defines which table mode will be used for vips + vipRoutingTableID = "vip_routingtableid" //nolint + // vipRoutingTableType - defines which table type will be used for vip routes // valid values for this variable can be found in: // https://pkg.go.dev/golang.org/x/sys/unix#RTN_UNSPEC From 991587c2944ae74512b5da429e5df4c21d0348cc Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Mon, 11 Sep 2023 11:06:48 +0200 Subject: [PATCH 423/542] fix formatting + add route to link + remove route on shutdown Signed-off-by: Timo Sluis --- go.mod | 70 -- go.sum | 1423 ++++++++++++++++++++++++++++++++++++++++ pkg/cluster/service.go | 7 + pkg/vip/address.go | 8 +- 4 files changed, 1434 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index 709d42a7..5e91cd1a 100644 --- a/go.mod +++ b/go.mod @@ -32,81 +32,11 @@ require ( ) require ( - github.com/BurntSushi/toml v1.2.1 // indirect - github.com/alessio/shellescape v1.4.1 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/eapache/channels v1.1.0 // indirect - github.com/eapache/queue v1.1.0 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/josharian/native v1.1.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/k-sone/critbitgo v1.4.0 // indirect - github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mdlayher/genetlink v1.3.2 // indirect - github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/packet v1.1.2 // indirect - github.com/mdlayher/socket v0.4.1 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect - github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.15.0 // indirect - github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect - github.com/vishvananda/netns v0.0.4 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - golang.org/x/time v0.1.0 // indirect - golang.org/x/tools v0.9.3 // indirect - golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 43e40d9b..563db15a 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -17,64 +18,643 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= +cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/bazelbuild/rules_go v0.30.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/ipvs v0.9.1 h1:4azDqbWqNAkcuD78yK9y9rxZoQfW2OnC9DFo+y7HPgk= github.com/cloudflare/ipvs v0.9.1/go.mod h1:5H4icNJZ8T4H7bg0/THRew5BbNOkDgl2RC1twjeSOHU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -82,38 +662,99 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -121,6 +762,9 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -136,11 +780,16 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -151,17 +800,24 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -172,35 +828,105 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= +github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= +github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -209,42 +935,87 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/ndp v1.0.1 h1:+yAD79/BWyFlvAoeG5ncPS0ItlHP/eVbH7bQ6/+LVA4= @@ -260,80 +1031,235 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= +github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/packet v1.1.1/go.mod h1:DRvYY5mH4M4lUqAnMg04E60U4fjUKMZ/4g2cHElZkKo= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= +github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= github.com/osrg/gobgp/v3 v3.17.0/go.mod h1:tSUXn/s9uggSRTKP3IBeT5zI4ayOUX3O7fG5+n+SHPc= github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -341,6 +1267,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -348,46 +1275,109 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= +go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -399,6 +1389,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -410,21 +1401,38 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -436,6 +1444,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -449,13 +1458,43 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -467,6 +1506,24 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -480,24 +1537,52 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -510,63 +1595,142 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.1-0.20230222185716-a3b23cc77e89/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -574,7 +1738,9 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -595,6 +1761,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -604,23 +1771,52 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -640,6 +1836,42 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -661,6 +1893,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -671,6 +1904,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -684,13 +1918,103 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA= google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -700,11 +2024,36 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0-dev/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -717,8 +2066,12 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -726,20 +2079,33 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -747,28 +2113,85 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs= k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= +k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= +k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.16.13/go.mod h1:UKvVT4cajC2iN7DCjLgT0KVY/cbY6DGdUCyRiIfws5M= k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/cluster/service.go b/pkg/cluster/service.go index 70463a7f..8afbe847 100644 --- a/pkg/cluster/service.go +++ b/pkg/cluster/service.go @@ -226,6 +226,13 @@ func (cluster *Cluster) StartLoadBalancerService(c *kubevip.Config, bgp *bgp.Ser log.Warnf("%v", err) } + if c.EnableRoutingTable { + err = cluster.Network.DeleteRoute() + if err != nil { + log.Warnf("%v", err) + } + } + close(cluster.completed) return } diff --git a/pkg/vip/address.go b/pkg/vip/address.go index 8716cc72..92792c3d 100644 --- a/pkg/vip/address.go +++ b/pkg/vip/address.go @@ -124,9 +124,9 @@ func NewConfig(address string, iface string, subnet string, isDDNS bool, tableID // AddRoute - Add an IP address to a route table func (configurator *network) AddRoute() error { - route_scope := netlink.SCOPE_UNIVERSE; + route_scope := netlink.SCOPE_UNIVERSE if configurator.routingTableType == unix.RTN_LOCAL { - route_scope = netlink.SCOPE_HOST + route_scope = netlink.SCOPE_LINK } route := &netlink.Route{ Scope: route_scope, @@ -140,9 +140,9 @@ func (configurator *network) AddRoute() error { // DeleteRoute - Delete an IP address from a route table func (configurator *network) DeleteRoute() error { - route_scope := netlink.SCOPE_UNIVERSE; + route_scope := netlink.SCOPE_UNIVERSE if configurator.routingTableType == unix.RTN_LOCAL { - route_scope = netlink.SCOPE_HOST + route_scope = netlink.SCOPE_LINK } route := &netlink.Route{ Scope: route_scope, From 31b7aad6c0f726c5a5639b2b18e13be6b5b3e112 Mon Sep 17 00:00:00 2001 From: Timo Sluis Date: Mon, 11 Sep 2023 13:14:04 +0200 Subject: [PATCH 424/542] revert go.mod and go.sum Signed-off-by: Timo Sluis --- go.mod | 70 +++ go.sum | 1423 -------------------------------------------------------- 2 files changed, 70 insertions(+), 1423 deletions(-) diff --git a/go.mod b/go.mod index 5e91cd1a..709d42a7 100644 --- a/go.mod +++ b/go.mod @@ -32,11 +32,81 @@ require ( ) require ( + github.com/BurntSushi/toml v1.2.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/eapache/channels v1.1.0 // indirect + github.com/eapache/queue v1.1.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect + github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/k-sone/critbitgo v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/packet v1.1.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.15.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.3.0 // indirect + golang.org/x/term v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + golang.org/x/time v0.1.0 // indirect + golang.org/x/tools v0.9.3 // indirect + golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect + google.golang.org/grpc v1.53.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 563db15a..43e40d9b 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -18,643 +17,64 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= -github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/bazelbuild/rules_go v0.30.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/ipvs v0.9.1 h1:4azDqbWqNAkcuD78yK9y9rxZoQfW2OnC9DFo+y7HPgk= github.com/cloudflare/ipvs v0.9.1/go.mod h1:5H4icNJZ8T4H7bg0/THRew5BbNOkDgl2RC1twjeSOHU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k= github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -662,99 +82,38 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/florianl/go-conntrack v0.4.0 h1:TlYkxytdwgVayfU0cKwkHurQA0Rd1ZSEBRckRYDUu18= github.com/florianl/go-conntrack v0.4.0/go.mod h1:iPDx4oIats2T7X7Jm3PFyRCJM1GfZhJaSHOWROYOrE8= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -762,9 +121,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -780,16 +136,11 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -800,24 +151,17 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -828,105 +172,35 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= -github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/hashicorp/consul/api v1.18.0/go.mod h1:owRRGJ9M5xReDC5nfT8FTJrNAPbT4NM6p/k+d03q2v4= -github.com/hashicorp/consul/sdk v0.13.0/go.mod h1:0hs/l5fOVhJy/VdcoaNqUSi2AUs95eF5WKtv+EYIQqE= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -935,87 +209,42 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08 h1:UQlM3K8NSN3cqIsICAQnSVOQe9B4LyFEu/xJUr+Scn4= github.com/kamhlos/upnp v0.0.0-20210324072331-5661950dff08/go.mod h1:0L/S1RSG4wA4M2Vhau3z7VsYMLxFnsX0bzzgwYRIdYU= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/ndp v1.0.1 h1:+yAD79/BWyFlvAoeG5ncPS0ItlHP/eVbH7bQ6/+LVA4= @@ -1031,235 +260,80 @@ github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuri github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= -github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/packet v1.1.1/go.mod h1:DRvYY5mH4M4lUqAnMg04E60U4fjUKMZ/4g2cHElZkKo= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws= -github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= -github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= -github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= -github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= -github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= -github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= -github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= -github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= -github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= -github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= -github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= -github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/osrg/gobgp/v3 v3.17.0 h1:Rh4hLzirQJnAz//57bxpiiDTkhPtsDuJ6oy0aeciJDA= github.com/osrg/gobgp/v3 v3.17.0/go.mod h1:tSUXn/s9uggSRTKP3IBeT5zI4ayOUX3O7fG5+n+SHPc= github.com/packethost/packngo v0.30.0 h1:JVeTwbXXETsLTDQncUbYwIFpkOp/xevXrffM2HrFECI= github.com/packethost/packngo v0.30.0/go.mod h1:BT/XcdwLVmeMtGPbovnxCpnI1s9ylSE1cs/7pq007NE= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.9.0/go.mod h1:RnH7sEhxfdnPm1z+XMgSLjWTEIjyK4z2dw6+4vHTMuo= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1267,7 +341,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -1275,109 +348,46 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= -github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 h1:YcojQL98T/OO+rybuzn2+5KrD5dBwXIvYBvQ2cD3Avg= github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= -github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1389,7 +399,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1401,38 +410,21 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1444,7 +436,6 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1458,43 +449,13 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1506,24 +467,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1537,52 +480,24 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1595,142 +510,63 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.1-0.20230222185716-a3b23cc77e89/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1738,9 +574,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1761,7 +595,6 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1771,52 +604,23 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1836,42 +640,6 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1893,7 +661,6 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1904,7 +671,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1918,103 +684,13 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA= google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -2024,36 +700,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0-dev/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2066,12 +717,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2079,33 +726,20 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2113,85 +747,28 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs= k8s.io/api v0.27.4 h1:0pCo/AN9hONazBKlNUdhQymmnfLRbSZjd5H5H3f0bSs= k8s.io/api v0.27.4/go.mod h1:O3smaaX15NfxjzILfiln1D8Z3+gEYpjEpiNA/1EVK1Y= -k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= -k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= k8s.io/apimachinery v0.27.4 h1:CdxflD4AF61yewuid0fLl6bM4a3q04jWel0IlP+aYjs= k8s.io/apimachinery v0.27.4/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/client-go v0.16.13/go.mod h1:UKvVT4cajC2iN7DCjLgT0KVY/cbY6DGdUCyRiIfws5M= k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk= k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 99e9579de57e50fc39376ae124c6e9f8161128b4 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 14 Sep 2023 11:07:47 +0200 Subject: [PATCH 425/542] Ignore kube-vip binary Signed-off-by: Mario Trangoni --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 723ef36f..bea64a87 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +kube-vip From 06e41bae50b9ce86af50c2a75a3b4be0e69002b0 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 14 Sep 2023 11:09:01 +0200 Subject: [PATCH 426/542] chore: Fix some misspellings found by codespell Signed-off-by: Mario Trangoni --- README.md | 2 +- cmd/kube-vip.go | 2 +- pkg/cluster/cluster.go | 2 +- pkg/cluster/clusterLeaderElection.go | 2 +- pkg/equinixmetal/eip.go | 2 +- pkg/kubevip/config_environment.go | 2 +- pkg/kubevip/config_generator.go | 2 +- pkg/manager/services.go | 2 +- pkg/manager/watch_services.go | 2 +- testing/kubeadm/create.sh | 2 +- testing/kubeadm/create_ctr.sh | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e80d016f..9aec8ed4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Kube-Vip was originally created to provide a HA solution for the Kubernetes cont - Service LoadBalancer address pools per namespace or global - Service LoadBalancer address via (existing network DHCP) - Service LoadBalancer address exposure to gateway via UPNP -- ... manifest generation, vendor API integrations and many nore... +- ... manifest generation, vendor API integrations and many more... ## Why? diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1c2945bd..9de2b405 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -38,7 +38,7 @@ var disableVIP bool // ConfigMap name within a Kubernetes cluster var configMap string -// Configure the level of loggin +// Configure the level of logging var logLevel uint32 // Provider Config diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 574f77ef..a146184b 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -56,7 +56,7 @@ func startNetworking(c *kubevip.Config) (vip.Network, error) { // Stop - Will stop the Cluster and release VIP if needed func (cluster *Cluster) Stop() { - // Close the stop chanel, which will shut down the VIP (if needed) + // Close the stop channel, which will shut down the VIP (if needed) if cluster.stop != nil { cluster.once.Do(func() { // Ensure that the close channel can only ever be called once close(cluster.stop) diff --git a/pkg/cluster/clusterLeaderElection.go b/pkg/cluster/clusterLeaderElection.go index aaabbd0e..c4f44bff 100644 --- a/pkg/cluster/clusterLeaderElection.go +++ b/pkg/cluster/clusterLeaderElection.go @@ -126,7 +126,7 @@ func (cluster *Cluster) StartCluster(c *kubevip.Config, sm *Manager, bgpServer * // Cancel the arp context, which will in turn stop any broadcasts }() - // (attempt to) Remove the virtual IP, incase it already exists + // (attempt to) Remove the virtual IP, in case it already exists err = cluster.Network.DeleteIP() if err != nil { log.Errorf("could not delete virtualIP: %v", err) diff --git a/pkg/equinixmetal/eip.go b/pkg/equinixmetal/eip.go index dcbe808d..1db4666a 100644 --- a/pkg/equinixmetal/eip.go +++ b/pkg/equinixmetal/eip.go @@ -35,7 +35,7 @@ func AttachEIP(c *packngo.Client, k *kubevip.Config, _ string) error { // Find the device id for our EIP if ip.Address == vip { log.Infof("Found EIP ->%s ID -> %s\n", ip.Address, ip.ID) - // If attachements already exist then remove them + // If attachments already exist then remove them if len(ip.Assignments) != 0 { hrefID := path.Base(ip.Assignments[0].Href) _, err := c.DeviceIPs.Unassign(hrefID) diff --git a/pkg/kubevip/config_environment.go b/pkg/kubevip/config_environment.go index 6b7498e4..c8a9bcd8 100644 --- a/pkg/kubevip/config_environment.go +++ b/pkg/kubevip/config_environment.go @@ -220,7 +220,7 @@ func ParseEnvironment(c *Config) error { } // Find Start As Leader - // TODO - does this need depricating? + // TODO - does this need deprecating? // Required when the host sets itself as leader before the state change env = os.Getenv(vipStartLeader) if env != "" { diff --git a/pkg/kubevip/config_generator.go b/pkg/kubevip/config_generator.go index 16610c86..706cb53d 100644 --- a/pkg/kubevip/config_generator.go +++ b/pkg/kubevip/config_generator.go @@ -398,7 +398,7 @@ func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod } if inCluster { - // If we're running this inCluster then the acccount name will be required + // If we're running this inCluster then the account name will be required newManifest.Spec.ServiceAccountName = "kube-vip" } else { // If this isn't inside a cluster then add the external path mount diff --git a/pkg/manager/services.go b/pkg/manager/services.go index 77a0dd3f..9a416d01 100644 --- a/pkg/manager/services.go +++ b/pkg/manager/services.go @@ -162,7 +162,7 @@ func (sm *Manager) addService(svc *v1.Service) error { } func (sm *Manager) deleteService(uid string) error { - // pretect multiple calls + // protect multiple calls sm.mutex.Lock() defer sm.mutex.Unlock() diff --git a/pkg/manager/watch_services.go b/pkg/manager/watch_services.go index 454a5b7a..0dbf4f4f 100644 --- a/pkg/manager/watch_services.go +++ b/pkg/manager/watch_services.go @@ -49,7 +49,7 @@ func (sm *Manager) servicesWatcher(ctx context.Context, serviceFunc func(context return err } if sm.config.ServiceNamespace == "" { - // v1.NamespaceAll is actually "", but we'll stay with the const incase things change upstream + // v1.NamespaceAll is actually "", but we'll stay with the const in case things change upstream sm.config.ServiceNamespace = v1.NamespaceAll log.Infof("starting services watcher for all namespaces") } else { diff --git a/testing/kubeadm/create.sh b/testing/kubeadm/create.sh index d1f31c30..6e346386 100755 --- a/testing/kubeadm/create.sh +++ b/testing/kubeadm/create.sh @@ -95,7 +95,7 @@ case "$3" in esac if [[ -z "$DEPS" ]]; then - logr "INFO" "Installing specific version of Kubernetes Dependancies" + logr "INFO" "Installing specific version of Kubernetes Dependencies" install_deps fi diff --git a/testing/kubeadm/create_ctr.sh b/testing/kubeadm/create_ctr.sh index aae51575..b366321a 100755 --- a/testing/kubeadm/create_ctr.sh +++ b/testing/kubeadm/create_ctr.sh @@ -97,7 +97,7 @@ case "$3" in esac if [[ -z "$DEPS" ]]; then - logr "INFO" "Installing specific version of Kubernetes Dependancies" + logr "INFO" "Installing specific version of Kubernetes Dependencies" install_deps fi From d8ed0e529689d7c81202a966111848516a9f39c6 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 14 Sep 2023 14:26:01 +0200 Subject: [PATCH 427/542] prometheus: Handle root path Signed-off-by: Mario Trangoni --- cmd/kube-vip.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/kube-vip.go b/cmd/kube-vip.go index 1c2945bd..590d0586 100644 --- a/cmd/kube-vip.go +++ b/cmd/kube-vip.go @@ -354,6 +354,15 @@ func servePrometheusHTTPServer(ctx context.Context, config PrometheusHTTPServerC var err error mux := http.NewServeMux() mux.Handle("/metrics", promhttp.Handler()) + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte(` + kube-vip + +

    AfS32AuIo#XWf^Kxh2_+kxpeJskd;mIDW!KTJ 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�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¥RxgqMI#7MYwvHT-meT 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