mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			378 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			378 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 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 config
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"net/http"
 | 
						|
	"net/http/httptest"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"k8s.io/api/core/v1"
 | 
						|
	apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
						|
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/runtime"
 | 
						|
	"k8s.io/apimachinery/pkg/types"
 | 
						|
	utiltesting "k8s.io/client-go/util/testing"
 | 
						|
	"k8s.io/kubernetes/pkg/api/legacyscheme"
 | 
						|
	"k8s.io/kubernetes/pkg/api/testapi"
 | 
						|
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
						|
	k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
 | 
						|
	"k8s.io/kubernetes/pkg/apis/core/validation"
 | 
						|
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
 | 
						|
)
 | 
						|
 | 
						|
func TestURLErrorNotExistNoUpdate(t *testing.T) {
 | 
						|
	ch := make(chan interface{})
 | 
						|
	NewSourceURL("http://localhost:49575/_not_found_", http.Header{}, "localhost", time.Millisecond, ch)
 | 
						|
	select {
 | 
						|
	case got := <-ch:
 | 
						|
		t.Errorf("Expected no update, Got %#v", got)
 | 
						|
	case <-time.After(2 * time.Millisecond):
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestExtractFromHttpBadness(t *testing.T) {
 | 
						|
	ch := make(chan interface{}, 1)
 | 
						|
	c := sourceURL{"http://localhost:49575/_not_found_", http.Header{}, "other", ch, nil, 0, http.DefaultClient}
 | 
						|
	if err := c.extractFromURL(); err == nil {
 | 
						|
		t.Errorf("Expected error")
 | 
						|
	}
 | 
						|
	expectEmptyChannel(t, ch)
 | 
						|
}
 | 
						|
 | 
						|
func TestExtractInvalidPods(t *testing.T) {
 | 
						|
	var testCases = []struct {
 | 
						|
		desc string
 | 
						|
		pod  *v1.Pod
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			desc: "No version",
 | 
						|
			pod:  &v1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: ""}},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Invalid version",
 | 
						|
			pod:  &v1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "v1betta2"}},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Invalid volume name",
 | 
						|
			pod: &v1.Pod{
 | 
						|
				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
 | 
						|
				Spec: v1.PodSpec{
 | 
						|
					Volumes: []v1.Volume{{Name: "_INVALID_"}},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Duplicate volume names",
 | 
						|
			pod: &v1.Pod{
 | 
						|
				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
 | 
						|
				Spec: v1.PodSpec{
 | 
						|
					Volumes: []v1.Volume{{Name: "repeated"}, {Name: "repeated"}},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Unspecified container name",
 | 
						|
			pod: &v1.Pod{
 | 
						|
				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
 | 
						|
				Spec: v1.PodSpec{
 | 
						|
					Containers: []v1.Container{{Name: ""}},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Invalid container name",
 | 
						|
			pod: &v1.Pod{
 | 
						|
				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
 | 
						|
				Spec: v1.PodSpec{
 | 
						|
					Containers: []v1.Container{{Name: "_INVALID_"}},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	for _, testCase := range testCases {
 | 
						|
		data, err := json.Marshal(testCase.pod)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
 | 
						|
		}
 | 
						|
		fakeHandler := utiltesting.FakeHandler{
 | 
						|
			StatusCode:   200,
 | 
						|
			ResponseBody: string(data),
 | 
						|
		}
 | 
						|
		testServer := httptest.NewServer(&fakeHandler)
 | 
						|
		defer testServer.Close()
 | 
						|
		ch := make(chan interface{}, 1)
 | 
						|
		c := sourceURL{testServer.URL, http.Header{}, "localhost", ch, nil, 0, http.DefaultClient}
 | 
						|
		if err := c.extractFromURL(); err == nil {
 | 
						|
			t.Errorf("%s: Expected error", testCase.desc)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestExtractPodsFromHTTP(t *testing.T) {
 | 
						|
	nodeName := "different-value"
 | 
						|
 | 
						|
	grace := int64(30)
 | 
						|
	enableServiceLinks := api.DefaultEnableServiceLinks
 | 
						|
	var testCases = []struct {
 | 
						|
		desc     string
 | 
						|
		pods     runtime.Object
 | 
						|
		expected kubetypes.PodUpdate
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			desc: "Single pod",
 | 
						|
			pods: &v1.Pod{
 | 
						|
				TypeMeta: metav1.TypeMeta{
 | 
						|
					Kind:       "Pod",
 | 
						|
					APIVersion: "",
 | 
						|
				},
 | 
						|
				ObjectMeta: metav1.ObjectMeta{
 | 
						|
					Name:      "foo",
 | 
						|
					UID:       "111",
 | 
						|
					Namespace: "mynamespace",
 | 
						|
				},
 | 
						|
				Spec: v1.PodSpec{
 | 
						|
					NodeName:        string(nodeName),
 | 
						|
					Containers:      []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
 | 
						|
					SecurityContext: &v1.PodSecurityContext{},
 | 
						|
					SchedulerName:   api.DefaultSchedulerName,
 | 
						|
				},
 | 
						|
				Status: v1.PodStatus{
 | 
						|
					Phase: v1.PodPending,
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expected: CreatePodUpdate(kubetypes.SET,
 | 
						|
				kubetypes.HTTPSource,
 | 
						|
				&v1.Pod{
 | 
						|
					ObjectMeta: metav1.ObjectMeta{
 | 
						|
						UID:         "111",
 | 
						|
						Name:        "foo" + "-" + nodeName,
 | 
						|
						Namespace:   "mynamespace",
 | 
						|
						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"},
 | 
						|
						SelfLink:    getSelfLink("foo-"+nodeName, "mynamespace"),
 | 
						|
					},
 | 
						|
					Spec: v1.PodSpec{
 | 
						|
						NodeName:                      nodeName,
 | 
						|
						RestartPolicy:                 v1.RestartPolicyAlways,
 | 
						|
						DNSPolicy:                     v1.DNSClusterFirst,
 | 
						|
						SecurityContext:               &v1.PodSecurityContext{},
 | 
						|
						TerminationGracePeriodSeconds: &grace,
 | 
						|
						SchedulerName:                 api.DefaultSchedulerName,
 | 
						|
						EnableServiceLinks:            &enableServiceLinks,
 | 
						|
 | 
						|
						Containers: []v1.Container{{
 | 
						|
							Name:  "1",
 | 
						|
							Image: "foo",
 | 
						|
							TerminationMessagePath:   "/dev/termination-log",
 | 
						|
							ImagePullPolicy:          "Always",
 | 
						|
							TerminationMessagePolicy: v1.TerminationMessageReadFile,
 | 
						|
						}},
 | 
						|
					},
 | 
						|
					Status: v1.PodStatus{
 | 
						|
						Phase: v1.PodPending,
 | 
						|
					},
 | 
						|
				}),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			desc: "Multiple pods",
 | 
						|
			pods: &v1.PodList{
 | 
						|
				TypeMeta: metav1.TypeMeta{
 | 
						|
					Kind:       "PodList",
 | 
						|
					APIVersion: "",
 | 
						|
				},
 | 
						|
				Items: []v1.Pod{
 | 
						|
					{
 | 
						|
						ObjectMeta: metav1.ObjectMeta{
 | 
						|
							Name: "foo",
 | 
						|
							UID:  "111",
 | 
						|
						},
 | 
						|
						Spec: v1.PodSpec{
 | 
						|
							NodeName:        nodeName,
 | 
						|
							Containers:      []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
 | 
						|
							SecurityContext: &v1.PodSecurityContext{},
 | 
						|
							SchedulerName:   api.DefaultSchedulerName,
 | 
						|
						},
 | 
						|
						Status: v1.PodStatus{
 | 
						|
							Phase: v1.PodPending,
 | 
						|
						},
 | 
						|
					},
 | 
						|
					{
 | 
						|
						ObjectMeta: metav1.ObjectMeta{
 | 
						|
							Name: "bar",
 | 
						|
							UID:  "222",
 | 
						|
						},
 | 
						|
						Spec: v1.PodSpec{
 | 
						|
							NodeName:        nodeName,
 | 
						|
							Containers:      []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: "", TerminationMessagePolicy: v1.TerminationMessageReadFile}},
 | 
						|
							SecurityContext: &v1.PodSecurityContext{},
 | 
						|
							SchedulerName:   api.DefaultSchedulerName,
 | 
						|
						},
 | 
						|
						Status: v1.PodStatus{
 | 
						|
							Phase: v1.PodPending,
 | 
						|
						},
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
			expected: CreatePodUpdate(kubetypes.SET,
 | 
						|
				kubetypes.HTTPSource,
 | 
						|
				&v1.Pod{
 | 
						|
					ObjectMeta: metav1.ObjectMeta{
 | 
						|
						UID:         "111",
 | 
						|
						Name:        "foo" + "-" + nodeName,
 | 
						|
						Namespace:   "default",
 | 
						|
						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"},
 | 
						|
						SelfLink:    getSelfLink("foo-"+nodeName, metav1.NamespaceDefault),
 | 
						|
					},
 | 
						|
					Spec: v1.PodSpec{
 | 
						|
						NodeName:                      nodeName,
 | 
						|
						RestartPolicy:                 v1.RestartPolicyAlways,
 | 
						|
						DNSPolicy:                     v1.DNSClusterFirst,
 | 
						|
						TerminationGracePeriodSeconds: &grace,
 | 
						|
						SecurityContext:               &v1.PodSecurityContext{},
 | 
						|
						SchedulerName:                 api.DefaultSchedulerName,
 | 
						|
						EnableServiceLinks:            &enableServiceLinks,
 | 
						|
 | 
						|
						Containers: []v1.Container{{
 | 
						|
							Name:  "1",
 | 
						|
							Image: "foo",
 | 
						|
							TerminationMessagePath:   "/dev/termination-log",
 | 
						|
							ImagePullPolicy:          "Always",
 | 
						|
							TerminationMessagePolicy: v1.TerminationMessageReadFile,
 | 
						|
						}},
 | 
						|
					},
 | 
						|
					Status: v1.PodStatus{
 | 
						|
						Phase: v1.PodPending,
 | 
						|
					},
 | 
						|
				},
 | 
						|
				&v1.Pod{
 | 
						|
					ObjectMeta: metav1.ObjectMeta{
 | 
						|
						UID:         "222",
 | 
						|
						Name:        "bar" + "-" + nodeName,
 | 
						|
						Namespace:   "default",
 | 
						|
						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "222"},
 | 
						|
						SelfLink:    getSelfLink("bar-"+nodeName, metav1.NamespaceDefault),
 | 
						|
					},
 | 
						|
					Spec: v1.PodSpec{
 | 
						|
						NodeName:                      nodeName,
 | 
						|
						RestartPolicy:                 v1.RestartPolicyAlways,
 | 
						|
						DNSPolicy:                     v1.DNSClusterFirst,
 | 
						|
						TerminationGracePeriodSeconds: &grace,
 | 
						|
						SecurityContext:               &v1.PodSecurityContext{},
 | 
						|
						SchedulerName:                 api.DefaultSchedulerName,
 | 
						|
						EnableServiceLinks:            &enableServiceLinks,
 | 
						|
 | 
						|
						Containers: []v1.Container{{
 | 
						|
							Name:  "2",
 | 
						|
							Image: "bar:bartag",
 | 
						|
							TerminationMessagePath:   "/dev/termination-log",
 | 
						|
							ImagePullPolicy:          "IfNotPresent",
 | 
						|
							TerminationMessagePolicy: v1.TerminationMessageReadFile,
 | 
						|
						}},
 | 
						|
					},
 | 
						|
					Status: v1.PodStatus{
 | 
						|
						Phase: v1.PodPending,
 | 
						|
					},
 | 
						|
				}),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, testCase := range testCases {
 | 
						|
		var versionedPods runtime.Object
 | 
						|
		err := legacyscheme.Scheme.Convert(&testCase.pods, &versionedPods, nil)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("%s: error in versioning the pods: %s", testCase.desc, err)
 | 
						|
		}
 | 
						|
		data, err := runtime.Encode(testapi.Default.Codec(), versionedPods)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err)
 | 
						|
		}
 | 
						|
		fakeHandler := utiltesting.FakeHandler{
 | 
						|
			StatusCode:   200,
 | 
						|
			ResponseBody: string(data),
 | 
						|
		}
 | 
						|
		testServer := httptest.NewServer(&fakeHandler)
 | 
						|
		defer testServer.Close()
 | 
						|
		ch := make(chan interface{}, 1)
 | 
						|
		c := sourceURL{testServer.URL, http.Header{}, types.NodeName(nodeName), ch, nil, 0, http.DefaultClient}
 | 
						|
		if err := c.extractFromURL(); err != nil {
 | 
						|
			t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		update := (<-ch).(kubetypes.PodUpdate)
 | 
						|
 | 
						|
		if !apiequality.Semantic.DeepEqual(testCase.expected, update) {
 | 
						|
			t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
 | 
						|
		}
 | 
						|
		for _, pod := range update.Pods {
 | 
						|
			// TODO: remove the conversion when validation is performed on versioned objects.
 | 
						|
			internalPod := &api.Pod{}
 | 
						|
			if err := k8s_api_v1.Convert_v1_Pod_To_core_Pod(pod, internalPod, nil); err != nil {
 | 
						|
				t.Fatalf("%s: Cannot convert pod %#v, %#v", testCase.desc, pod, err)
 | 
						|
			}
 | 
						|
			if errs := validation.ValidatePod(internalPod); len(errs) != 0 {
 | 
						|
				t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errs.ToAggregate())
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestURLWithHeader(t *testing.T) {
 | 
						|
	pod := &v1.Pod{
 | 
						|
		TypeMeta: metav1.TypeMeta{
 | 
						|
			APIVersion: "v1",
 | 
						|
			Kind:       "Pod",
 | 
						|
		},
 | 
						|
		ObjectMeta: metav1.ObjectMeta{
 | 
						|
			Name:      "foo",
 | 
						|
			UID:       "111",
 | 
						|
			Namespace: "mynamespace",
 | 
						|
		},
 | 
						|
		Spec: v1.PodSpec{
 | 
						|
			NodeName:   "localhost",
 | 
						|
			Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	data, err := json.Marshal(pod)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unexpected json marshalling error: %v", err)
 | 
						|
	}
 | 
						|
	fakeHandler := utiltesting.FakeHandler{
 | 
						|
		StatusCode:   200,
 | 
						|
		ResponseBody: string(data),
 | 
						|
	}
 | 
						|
	testServer := httptest.NewServer(&fakeHandler)
 | 
						|
	defer testServer.Close()
 | 
						|
	ch := make(chan interface{}, 1)
 | 
						|
	header := make(http.Header)
 | 
						|
	header.Set("Metadata-Flavor", "Google")
 | 
						|
	c := sourceURL{testServer.URL, header, "localhost", ch, nil, 0, http.DefaultClient}
 | 
						|
	if err := c.extractFromURL(); err != nil {
 | 
						|
		t.Fatalf("Unexpected error extracting from URL: %v", err)
 | 
						|
	}
 | 
						|
	update := (<-ch).(kubetypes.PodUpdate)
 | 
						|
 | 
						|
	headerVal := fakeHandler.RequestReceived.Header["Metadata-Flavor"]
 | 
						|
	if len(headerVal) != 1 || headerVal[0] != "Google" {
 | 
						|
		t.Errorf("Header missing expected entry %v. Got %v", header, fakeHandler.RequestReceived.Header)
 | 
						|
	}
 | 
						|
	if len(update.Pods) != 1 {
 | 
						|
		t.Errorf("Received wrong number of pods, expected one: %v", update.Pods)
 | 
						|
	}
 | 
						|
}
 |