istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/util/handlers/handlers_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package handlers 16 17 import ( 18 "fmt" 19 "net/http" 20 "sort" 21 "strings" 22 "testing" 23 "time" 24 25 appsv1 "k8s.io/api/apps/v1" 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 corev1client "k8s.io/client-go/kubernetes/typed/core/v1" 30 "k8s.io/client-go/rest/fake" 31 cmdtesting "k8s.io/kubectl/pkg/cmd/testing" 32 "k8s.io/kubectl/pkg/scheme" 33 34 "istio.io/istio/pkg/test/util/assert" 35 ) 36 37 func TestInferPodInfo(t *testing.T) { 38 tests := []struct { 39 proxyName string 40 namespace string 41 wantPodName string 42 wantNamespace string 43 }{ 44 { 45 proxyName: "istio-ingressgateway-8d9697654-qdzgh.istio-system", 46 namespace: "kube-system", 47 wantPodName: "istio-ingressgateway-8d9697654-qdzgh", 48 wantNamespace: "istio-system", 49 }, 50 { 51 proxyName: "istio-ingressgateway-8d9697654-qdzgh.istio-system", 52 namespace: "", 53 wantPodName: "istio-ingressgateway-8d9697654-qdzgh", 54 wantNamespace: "istio-system", 55 }, 56 { 57 proxyName: "istio-ingressgateway-8d9697654-qdzgh", 58 namespace: "kube-system", 59 wantPodName: "istio-ingressgateway-8d9697654-qdzgh", 60 wantNamespace: "kube-system", 61 }, 62 { 63 proxyName: "istio-security-post-install-1.2.2-bm9w2.istio-system", 64 namespace: "istio-system", 65 wantPodName: "istio-security-post-install-1.2.2-bm9w2", 66 wantNamespace: "istio-system", 67 }, 68 { 69 proxyName: "istio-security-post-install-1.2.2-bm9w2.istio-system", 70 namespace: "", 71 wantPodName: "istio-security-post-install-1.2.2-bm9w2", 72 wantNamespace: "istio-system", 73 }, 74 { 75 proxyName: "service/istiod", 76 namespace: "", 77 wantPodName: "service/istiod", 78 wantNamespace: "", 79 }, 80 { 81 proxyName: "service/istiod", 82 namespace: "namespace", 83 wantPodName: "service/istiod", 84 wantNamespace: "namespace", 85 }, 86 { 87 proxyName: "service/istiod.istio-system", 88 namespace: "namespace", 89 wantPodName: "service/istiod", 90 wantNamespace: "istio-system", 91 }, 92 { 93 proxyName: "gateway.gateway.networking.k8s.io/istiod", 94 namespace: "", 95 wantPodName: "gateway.gateway.networking.k8s.io/istiod", 96 wantNamespace: "", 97 }, 98 { 99 proxyName: "gateway.gateway.networking.k8s.io/istiod", 100 namespace: "namespace", 101 wantPodName: "gateway.gateway.networking.k8s.io/istiod", 102 wantNamespace: "namespace", 103 }, 104 { 105 proxyName: "gateway.gateway.networking.k8s.io/istiod.istio-system", 106 namespace: "namespace", 107 wantPodName: "gateway.gateway.networking.k8s.io/istiod", 108 wantNamespace: "istio-system", 109 }, 110 } 111 for _, tt := range tests { 112 t.Run(strings.Split(tt.proxyName, ".")[0], func(t *testing.T) { 113 gotPodName, gotNamespace := InferPodInfo(tt.proxyName, tt.namespace) 114 if gotPodName != tt.wantPodName || gotNamespace != tt.wantNamespace { 115 t.Errorf("unexpected podName and namespace: wanted %v %v got %v %v", tt.wantPodName, tt.wantNamespace, gotPodName, gotNamespace) 116 } 117 }) 118 } 119 } 120 121 func TestInferPodInfoFromTypedResource(t *testing.T) { 122 tests := []struct { 123 name string 124 wantPodName string 125 wantNamespace string 126 }{ 127 { 128 name: "foo-abc.istio-system", 129 wantPodName: "foo-abc", 130 wantNamespace: "istio-system", 131 }, 132 { 133 name: "foo-abc", 134 wantPodName: "foo-abc", 135 wantNamespace: "test", 136 }, 137 { 138 name: "Deployment/foo.istio-system", 139 wantPodName: "foo-abc", 140 wantNamespace: "istio-system", 141 }, 142 { 143 name: "Deployment/foo", 144 wantPodName: "foo-abc", 145 wantNamespace: "test", 146 }, 147 } 148 factory := cmdtesting.NewTestFactory().WithNamespace("test") 149 ns := scheme.Codecs.WithoutConversion() 150 codec := scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) 151 factory.Client = &fake.RESTClient{ 152 GroupVersion: schema.GroupVersion{Group: "", Version: "v1"}, 153 NegotiatedSerializer: ns, 154 Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { 155 switch p, m := req.URL.Path, req.Method; { 156 case p == "/namespaces/istio-system/deployments/foo" && m == "GET": 157 body := cmdtesting.ObjBody(codec, attachDeploy("istio-system")) 158 return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil 159 case p == "/namespaces/test/deployments/foo" && m == "GET": 160 body := cmdtesting.ObjBody(codec, attachDeploy("test")) 161 return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil 162 default: 163 t.Errorf("%s: unexpected request: %s %#v\n%#v", p, req.Method, req.URL, req) 164 return nil, fmt.Errorf("unexpected request") 165 } 166 }), 167 } 168 getFirstPodFunc = func(client corev1client.PodsGetter, namespace string, selector string, timeout time.Duration, sortBy func([]*corev1.Pod) sort.Interface) ( 169 *corev1.Pod, int, error, 170 ) { 171 return attachPod(namespace), 1, nil 172 } 173 for _, tt := range tests { 174 t.Run(strings.Split(tt.name, ".")[0], func(t *testing.T) { 175 gotPodName, gotNamespace, err := InferPodInfoFromTypedResource(tt.name, "test", factory) 176 assert.NoError(t, err) 177 if gotPodName != tt.wantPodName || gotNamespace != tt.wantNamespace { 178 t.Errorf("unexpected podName and namespace: wanted %v %v got %v %v", tt.wantPodName, tt.wantNamespace, gotPodName, gotNamespace) 179 } 180 }) 181 } 182 } 183 184 func attachPod(ns string) *corev1.Pod { 185 return &corev1.Pod{ 186 ObjectMeta: metav1.ObjectMeta{Name: "foo-abc", Namespace: ns, ResourceVersion: "10"}, 187 Spec: corev1.PodSpec{ 188 RestartPolicy: corev1.RestartPolicyAlways, 189 DNSPolicy: corev1.DNSClusterFirst, 190 Containers: []corev1.Container{ 191 { 192 Name: "bar", 193 }, 194 }, 195 InitContainers: []corev1.Container{ 196 { 197 Name: "initfoo", 198 }, 199 }, 200 EphemeralContainers: []corev1.EphemeralContainer{ 201 { 202 EphemeralContainerCommon: corev1.EphemeralContainerCommon{ 203 Name: "debugger", 204 }, 205 }, 206 }, 207 }, 208 Status: corev1.PodStatus{ 209 Phase: corev1.PodRunning, 210 }, 211 } 212 } 213 214 func attachDeploy(ns string) *appsv1.Deployment { 215 return &appsv1.Deployment{ 216 ObjectMeta: metav1.ObjectMeta{ 217 Name: "foo", 218 Namespace: ns, 219 }, 220 Spec: appsv1.DeploymentSpec{}, 221 } 222 }