Refactor extraction of ingress pod details
This commit is contained in:
parent
b482b5dd32
commit
1389cc0e80
9 changed files with 99 additions and 68 deletions
|
@ -26,7 +26,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
@ -58,7 +57,7 @@ func TestHandleSigterm(t *testing.T) {
|
||||||
namespace = "test"
|
namespace = "test"
|
||||||
)
|
)
|
||||||
|
|
||||||
k8s.IngressNGINXPod = &v1.Pod{
|
k8s.IngressPodDetails = &k8s.PodInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
|
|
@ -154,7 +154,7 @@ func (n *NGINXController) syncIngress(interface{}) error {
|
||||||
n.metricCollector.IncReloadErrorCount()
|
n.metricCollector.IncReloadErrorCount()
|
||||||
n.metricCollector.ConfigSuccess(hash, false)
|
n.metricCollector.ConfigSuccess(hash, false)
|
||||||
klog.Errorf("Unexpected failure reloading the backend:\n%v", err)
|
klog.Errorf("Unexpected failure reloading the backend:\n%v", err)
|
||||||
n.recorder.Eventf(k8s.IngressNGINXPod, apiv1.EventTypeWarning, "RELOAD", fmt.Sprintf("Error reloading NGINX: %v", err))
|
n.recorder.Eventf(k8s.IngressPodDetails, apiv1.EventTypeWarning, "RELOAD", fmt.Sprintf("Error reloading NGINX: %v", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ func (n *NGINXController) syncIngress(interface{}) error {
|
||||||
n.metricCollector.ConfigSuccess(hash, true)
|
n.metricCollector.ConfigSuccess(hash, true)
|
||||||
n.metricCollector.IncReloadCount()
|
n.metricCollector.IncReloadCount()
|
||||||
|
|
||||||
n.recorder.Eventf(k8s.IngressNGINXPod, apiv1.EventTypeNormal, "RELOAD", "NGINX reload triggered due to a change in configuration")
|
n.recorder.Eventf(k8s.IngressPodDetails, apiv1.EventTypeNormal, "RELOAD", "NGINX reload triggered due to a change in configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
isFirstSync := n.runningConfig.Equal(&ingress.Configuration{})
|
isFirstSync := n.runningConfig.Equal(&ingress.Configuration{})
|
||||||
|
|
|
@ -1671,7 +1671,7 @@ func newNGINXController(t *testing.T) *NGINXController {
|
||||||
t.Fatalf("error creating the configuration map: %v", err)
|
t.Fatalf("error creating the configuration map: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
k8s.IngressNGINXPod = &v1.Pod{
|
k8s.IngressPodDetails = &k8s.PodInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "testpod",
|
Name: "testpod",
|
||||||
Namespace: ns,
|
Namespace: ns,
|
||||||
|
@ -1729,7 +1729,7 @@ func newDynamicNginxController(t *testing.T, setConfigMap func(string) *v1.Confi
|
||||||
t.Fatalf("error creating the configuration map: %v", err)
|
t.Fatalf("error creating the configuration map: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
k8s.IngressNGINXPod = &v1.Pod{
|
k8s.IngressPodDetails = &k8s.PodInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "testpod",
|
Name: "testpod",
|
||||||
Namespace: ns,
|
Namespace: ns,
|
||||||
|
|
|
@ -93,23 +93,18 @@ func setupLeaderElection(config *leaderElectionConfig) {
|
||||||
Host: hostname,
|
Host: hostname,
|
||||||
})
|
})
|
||||||
|
|
||||||
ingressPod, err := k8s.GetPodDetails()
|
|
||||||
if err != nil {
|
|
||||||
klog.Fatalf("unexpected error starting leader election: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
lock := resourcelock.ConfigMapLock{
|
lock := resourcelock.ConfigMapLock{
|
||||||
ConfigMapMeta: metav1.ObjectMeta{Namespace: ingressPod.Namespace, Name: config.ElectionID},
|
ConfigMapMeta: metav1.ObjectMeta{Namespace: k8s.IngressPodDetails.Namespace, Name: config.ElectionID},
|
||||||
Client: config.Client.CoreV1(),
|
Client: config.Client.CoreV1(),
|
||||||
LockConfig: resourcelock.ResourceLockConfig{
|
LockConfig: resourcelock.ResourceLockConfig{
|
||||||
Identity: ingressPod.Name,
|
Identity: k8s.IngressPodDetails.Name,
|
||||||
EventRecorder: recorder,
|
EventRecorder: recorder,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ttl := 30 * time.Second
|
ttl := 30 * time.Second
|
||||||
|
|
||||||
elector, err = leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
|
elector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
|
||||||
Lock: &lock,
|
Lock: &lock,
|
||||||
LeaseDuration: ttl,
|
LeaseDuration: ttl,
|
||||||
RenewDeadline: ttl / 2,
|
RenewDeadline: ttl / 2,
|
||||||
|
|
|
@ -172,14 +172,9 @@ func (s *statusSync) runningAddresses() ([]string, error) {
|
||||||
return statusAddressFromService(s.PublishService, s.Client)
|
return statusAddressFromService(s.PublishService, s.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
ingressPod, err := k8s.GetPodDetails()
|
|
||||||
if err != nil {
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get information about all the pods running the ingress controller
|
// get information about all the pods running the ingress controller
|
||||||
pods, err := s.Client.CoreV1().Pods(ingressPod.Namespace).List(context.TODO(), metav1.ListOptions{
|
pods, err := s.Client.CoreV1().Pods(k8s.IngressPodDetails.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||||
LabelSelector: labels.SelectorFromSet(ingressPod.Labels).String(),
|
LabelSelector: labels.SelectorFromSet(k8s.IngressPodDetails.Labels).String(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -216,13 +211,8 @@ func (s *statusSync) runningAddresses() ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *statusSync) isRunningMultiplePods() bool {
|
func (s *statusSync) isRunningMultiplePods() bool {
|
||||||
ingressPod, err := k8s.GetPodDetails()
|
pods, err := s.Client.CoreV1().Pods(k8s.IngressPodDetails.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||||
if err != nil {
|
LabelSelector: labels.SelectorFromSet(k8s.IngressPodDetails.Labels).String(),
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pods, err := s.Client.CoreV1().Pods(ingressPod.Namespace).List(context.TODO(), metav1.ListOptions{
|
|
||||||
LabelSelector: labels.SelectorFromSet(ingressPod.Labels).String(),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
networking "k8s.io/api/networking/v1beta1"
|
networking "k8s.io/api/networking/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
testclient "k8s.io/client-go/kubernetes/fake"
|
testclient "k8s.io/client-go/kubernetes/fake"
|
||||||
|
@ -297,7 +296,7 @@ func TestStatusActions(t *testing.T) {
|
||||||
UpdateStatusOnShutdown: true,
|
UpdateStatusOnShutdown: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
k8s.IngressNGINXPod = &v1.Pod{
|
k8s.IngressPodDetails = &k8s.PodInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo_base_pod",
|
Name: "foo_base_pod",
|
||||||
Namespace: apiv1.NamespaceDefault,
|
Namespace: apiv1.NamespaceDefault,
|
||||||
|
|
|
@ -75,16 +75,22 @@ func GetNodeIPOrName(kubeClient clientset.Interface, name string, useInternalIP
|
||||||
return defaultOrInternalIP
|
return defaultOrInternalIP
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressNGINXPod hold information about the ingress-nginx pod
|
var (
|
||||||
var IngressNGINXPod *apiv1.Pod
|
// IngressPodDetails hold information about the ingress-nginx pod
|
||||||
|
IngressPodDetails *PodInfo
|
||||||
|
|
||||||
|
selectorLabelKeys = []string{
|
||||||
|
"app.kubernetes.io/component",
|
||||||
|
"app.kubernetes.io/instance",
|
||||||
|
"app.kubernetes.io/name",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// PodInfo contains runtime information about the pod running the Ingres controller
|
// PodInfo contains runtime information about the pod running the Ingres controller
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type PodInfo struct {
|
type PodInfo struct {
|
||||||
Name string
|
metav1.TypeMeta
|
||||||
Namespace string
|
metav1.ObjectMeta
|
||||||
// Labels selectors of the running pod
|
|
||||||
// This is used to search for other Ingress controller pods
|
|
||||||
Labels map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIngressPod load the ingress-nginx pod
|
// GetIngressPod load the ingress-nginx pod
|
||||||
|
@ -96,28 +102,31 @@ func GetIngressPod(kubeClient clientset.Interface) error {
|
||||||
return fmt.Errorf("unable to get POD information (missing POD_NAME or POD_NAMESPACE environment variable")
|
return fmt.Errorf("unable to get POD information (missing POD_NAME or POD_NAMESPACE environment variable")
|
||||||
}
|
}
|
||||||
|
|
||||||
IngressNGINXPod, _ = kubeClient.CoreV1().Pods(podNs).Get(context.TODO(), podName, metav1.GetOptions{})
|
pod, err := kubeClient.CoreV1().Pods(podNs).Get(context.TODO(), podName, metav1.GetOptions{})
|
||||||
if IngressNGINXPod == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to get POD information")
|
return fmt.Errorf("unable to get POD information: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labels := map[string]string{}
|
||||||
|
for _, key := range selectorLabelKeys {
|
||||||
|
value, ok := pod.GetLabels()[key]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("label %v is missing. Please do not remove", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
labels[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
IngressPodDetails = &PodInfo{
|
||||||
|
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
|
||||||
|
}
|
||||||
|
|
||||||
|
pod.ObjectMeta.DeepCopyInto(&IngressPodDetails.ObjectMeta)
|
||||||
|
IngressPodDetails.SetLabels(labels)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPodDetails returns runtime information about the pod:
|
|
||||||
// name, namespace and IP of the node where it is running
|
|
||||||
func GetPodDetails() (*PodInfo, error) {
|
|
||||||
if IngressNGINXPod == nil {
|
|
||||||
return nil, fmt.Errorf("no ingress-nginx pod details available")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &PodInfo{
|
|
||||||
Name: IngressNGINXPod.Name,
|
|
||||||
Namespace: IngressNGINXPod.Namespace,
|
|
||||||
Labels: IngressNGINXPod.GetLabels(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MetaNamespaceKey knows how to make keys for API objects which implement meta.Interface.
|
// MetaNamespaceKey knows how to make keys for API objects which implement meta.Interface.
|
||||||
func MetaNamespaceKey(obj interface{}) string {
|
func MetaNamespaceKey(obj interface{}) string {
|
||||||
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
||||||
|
|
|
@ -214,36 +214,36 @@ func TestGetNodeIP(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetPodDetails(t *testing.T) {
|
func TestGetIngressPod(t *testing.T) {
|
||||||
// POD_NAME & POD_NAMESPACE not exist
|
// POD_NAME & POD_NAMESPACE not exist
|
||||||
os.Setenv("POD_NAME", "")
|
os.Setenv("POD_NAME", "")
|
||||||
os.Setenv("POD_NAMESPACE", "")
|
os.Setenv("POD_NAMESPACE", "")
|
||||||
err1 := GetIngressPod(testclient.NewSimpleClientset())
|
err := GetIngressPod(testclient.NewSimpleClientset())
|
||||||
if err1 == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error but returned nil")
|
t.Errorf("expected an error but returned nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// POD_NAME not exist
|
// POD_NAME not exist
|
||||||
os.Setenv("POD_NAME", "")
|
os.Setenv("POD_NAME", "")
|
||||||
os.Setenv("POD_NAMESPACE", apiv1.NamespaceDefault)
|
os.Setenv("POD_NAMESPACE", apiv1.NamespaceDefault)
|
||||||
err2 := GetIngressPod(testclient.NewSimpleClientset())
|
err = GetIngressPod(testclient.NewSimpleClientset())
|
||||||
if err2 == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error but returned nil")
|
t.Errorf("expected an error but returned nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// POD_NAMESPACE not exist
|
// POD_NAMESPACE not exist
|
||||||
os.Setenv("POD_NAME", "testpod")
|
os.Setenv("POD_NAME", "testpod")
|
||||||
os.Setenv("POD_NAMESPACE", "")
|
os.Setenv("POD_NAMESPACE", "")
|
||||||
err3 := GetIngressPod(testclient.NewSimpleClientset())
|
err = GetIngressPod(testclient.NewSimpleClientset())
|
||||||
if err3 == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error but returned nil")
|
t.Errorf("expected an error but returned nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// POD not exist
|
// POD not exist
|
||||||
os.Setenv("POD_NAME", "testpod")
|
os.Setenv("POD_NAME", "testpod")
|
||||||
os.Setenv("POD_NAMESPACE", apiv1.NamespaceDefault)
|
os.Setenv("POD_NAMESPACE", apiv1.NamespaceDefault)
|
||||||
err4 := GetIngressPod(testclient.NewSimpleClientset())
|
err = GetIngressPod(testclient.NewSimpleClientset())
|
||||||
if err4 == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error but returned nil")
|
t.Errorf("expected an error but returned nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +256,9 @@ func TestGetPodDetails(t *testing.T) {
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"first": "first_label",
|
"first": "first_label",
|
||||||
"second": "second_label",
|
"second": "second_label",
|
||||||
|
"app.kubernetes.io/component": "controller",
|
||||||
|
"app.kubernetes.io/instance": "ingress-nginx",
|
||||||
|
"app.kubernetes.io/name": "ingress-nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}},
|
}}},
|
||||||
|
@ -273,9 +276,9 @@ func TestGetPodDetails(t *testing.T) {
|
||||||
},
|
},
|
||||||
}}})
|
}}})
|
||||||
|
|
||||||
err5 := GetIngressPod(fkClient)
|
err = GetIngressPod(fkClient)
|
||||||
if err5 != nil {
|
if err != nil {
|
||||||
t.Errorf("expected a PodInfo but returned error")
|
t.Errorf("expected a PodInfo but returned error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
36
internal/k8s/zz_generated.deepcopy.go
Normal file
36
internal/k8s/zz_generated.deepcopy.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package k8s
|
||||||
|
|
||||||
|
import "k8s.io/apimachinery/pkg/runtime"
|
||||||
|
|
||||||
|
func (in *PodInfo) DeepCopyInto(out *PodInfo) {
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
out.ObjectMeta = in.ObjectMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject returns a generically typed copy of an object
|
||||||
|
func (in *PodInfo) DeepCopyObject() runtime.Object {
|
||||||
|
out := PodInfo{}
|
||||||
|
in.DeepCopyInto(&out)
|
||||||
|
|
||||||
|
return &out
|
||||||
|
}
|
Loading…
Reference in a new issue