...

Source file src/k8s.io/kubernetes/pkg/kubelet/config/http_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/config

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package config
    18  
    19  import (
    20  	"encoding/json"
    21  	"net/http"
    22  	"net/http/httptest"
    23  	"testing"
    24  	"time"
    25  
    26  	"k8s.io/api/core/v1"
    27  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/apimachinery/pkg/types"
    31  	clientscheme "k8s.io/client-go/kubernetes/scheme"
    32  	utiltesting "k8s.io/client-go/util/testing"
    33  	api "k8s.io/kubernetes/pkg/apis/core"
    34  	k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
    35  	"k8s.io/kubernetes/pkg/apis/core/validation"
    36  	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
    37  )
    38  
    39  func TestURLErrorNotExistNoUpdate(t *testing.T) {
    40  	ch := make(chan interface{})
    41  	NewSourceURL("http://localhost:49575/_not_found_", http.Header{}, "localhost", time.Millisecond, ch)
    42  	select {
    43  	case got := <-ch:
    44  		t.Errorf("Expected no update, Got %#v", got)
    45  	case <-time.After(2 * time.Millisecond):
    46  	}
    47  }
    48  
    49  func TestExtractFromHttpBadness(t *testing.T) {
    50  	ch := make(chan interface{}, 1)
    51  	c := sourceURL{"http://localhost:49575/_not_found_", http.Header{}, "other", ch, nil, 0, http.DefaultClient}
    52  	if err := c.extractFromURL(); err == nil {
    53  		t.Errorf("Expected error")
    54  	}
    55  	expectEmptyChannel(t, ch)
    56  }
    57  
    58  func TestExtractInvalidPods(t *testing.T) {
    59  	var testCases = []struct {
    60  		desc string
    61  		pod  *v1.Pod
    62  	}{
    63  		{
    64  			desc: "No version",
    65  			pod:  &v1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: ""}},
    66  		},
    67  		{
    68  			desc: "Invalid version",
    69  			pod:  &v1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: "v1betta2"}},
    70  		},
    71  		{
    72  			desc: "Invalid volume name",
    73  			pod: &v1.Pod{
    74  				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
    75  				Spec: v1.PodSpec{
    76  					Volumes: []v1.Volume{{Name: "_INVALID_"}},
    77  				},
    78  			},
    79  		},
    80  		{
    81  			desc: "Duplicate volume names",
    82  			pod: &v1.Pod{
    83  				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
    84  				Spec: v1.PodSpec{
    85  					Volumes: []v1.Volume{{Name: "repeated"}, {Name: "repeated"}},
    86  				},
    87  			},
    88  		},
    89  		{
    90  			desc: "Unspecified container name",
    91  			pod: &v1.Pod{
    92  				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
    93  				Spec: v1.PodSpec{
    94  					Containers: []v1.Container{{Name: ""}},
    95  				},
    96  			},
    97  		},
    98  		{
    99  			desc: "Invalid container name",
   100  			pod: &v1.Pod{
   101  				TypeMeta: metav1.TypeMeta{APIVersion: "v1"},
   102  				Spec: v1.PodSpec{
   103  					Containers: []v1.Container{{Name: "_INVALID_"}},
   104  				},
   105  			},
   106  		},
   107  	}
   108  	for _, testCase := range testCases {
   109  		data, err := json.Marshal(testCase.pod)
   110  		if err != nil {
   111  			t.Fatalf("%s: Some weird json problem: %v", testCase.desc, err)
   112  		}
   113  		fakeHandler := utiltesting.FakeHandler{
   114  			StatusCode:   http.StatusOK,
   115  			ResponseBody: string(data),
   116  		}
   117  		testServer := httptest.NewServer(&fakeHandler)
   118  		defer testServer.Close()
   119  		ch := make(chan interface{}, 1)
   120  		c := sourceURL{testServer.URL, http.Header{}, "localhost", ch, nil, 0, http.DefaultClient}
   121  		if err := c.extractFromURL(); err == nil {
   122  			t.Errorf("%s: Expected error", testCase.desc)
   123  		}
   124  	}
   125  }
   126  
   127  func TestExtractPodsFromHTTP(t *testing.T) {
   128  	nodeName := "different-value"
   129  
   130  	grace := int64(30)
   131  	enableServiceLinks := v1.DefaultEnableServiceLinks
   132  	var testCases = []struct {
   133  		desc     string
   134  		pods     runtime.Object
   135  		expected kubetypes.PodUpdate
   136  	}{
   137  		{
   138  			desc: "Single pod",
   139  			pods: &v1.Pod{
   140  				TypeMeta: metav1.TypeMeta{
   141  					Kind:       "Pod",
   142  					APIVersion: "",
   143  				},
   144  				ObjectMeta: metav1.ObjectMeta{
   145  					Name:      "foo",
   146  					UID:       "111",
   147  					Namespace: "mynamespace",
   148  				},
   149  				Spec: v1.PodSpec{
   150  					NodeName:        string(nodeName),
   151  					Containers:      []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
   152  					SecurityContext: &v1.PodSecurityContext{},
   153  					SchedulerName:   v1.DefaultSchedulerName,
   154  				},
   155  				Status: v1.PodStatus{
   156  					Phase: v1.PodPending,
   157  				},
   158  			},
   159  			expected: CreatePodUpdate(kubetypes.SET,
   160  				kubetypes.HTTPSource,
   161  				&v1.Pod{
   162  					ObjectMeta: metav1.ObjectMeta{
   163  						UID:         "111",
   164  						Name:        "foo" + "-" + nodeName,
   165  						Namespace:   "mynamespace",
   166  						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"},
   167  					},
   168  					Spec: v1.PodSpec{
   169  						NodeName:                      nodeName,
   170  						RestartPolicy:                 v1.RestartPolicyAlways,
   171  						DNSPolicy:                     v1.DNSClusterFirst,
   172  						SecurityContext:               &v1.PodSecurityContext{},
   173  						TerminationGracePeriodSeconds: &grace,
   174  						SchedulerName:                 v1.DefaultSchedulerName,
   175  						EnableServiceLinks:            &enableServiceLinks,
   176  
   177  						Containers: []v1.Container{{
   178  							Name:                     "1",
   179  							Image:                    "foo",
   180  							TerminationMessagePath:   "/dev/termination-log",
   181  							ImagePullPolicy:          "Always",
   182  							TerminationMessagePolicy: v1.TerminationMessageReadFile,
   183  						}},
   184  					},
   185  					Status: v1.PodStatus{
   186  						Phase: v1.PodPending,
   187  					},
   188  				}),
   189  		},
   190  		{
   191  			desc: "Multiple pods",
   192  			pods: &v1.PodList{
   193  				TypeMeta: metav1.TypeMeta{
   194  					Kind:       "PodList",
   195  					APIVersion: "",
   196  				},
   197  				Items: []v1.Pod{
   198  					{
   199  						ObjectMeta: metav1.ObjectMeta{
   200  							Name: "foo",
   201  							UID:  "111",
   202  						},
   203  						Spec: v1.PodSpec{
   204  							NodeName:        nodeName,
   205  							Containers:      []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways, TerminationMessagePolicy: v1.TerminationMessageReadFile}},
   206  							SecurityContext: &v1.PodSecurityContext{},
   207  							SchedulerName:   v1.DefaultSchedulerName,
   208  						},
   209  						Status: v1.PodStatus{
   210  							Phase: v1.PodPending,
   211  						},
   212  					},
   213  					{
   214  						ObjectMeta: metav1.ObjectMeta{
   215  							Name: "bar",
   216  							UID:  "222",
   217  						},
   218  						Spec: v1.PodSpec{
   219  							NodeName:        nodeName,
   220  							Containers:      []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: "", TerminationMessagePolicy: v1.TerminationMessageReadFile}},
   221  							SecurityContext: &v1.PodSecurityContext{},
   222  							SchedulerName:   v1.DefaultSchedulerName,
   223  						},
   224  						Status: v1.PodStatus{
   225  							Phase: v1.PodPending,
   226  						},
   227  					},
   228  				},
   229  			},
   230  			expected: CreatePodUpdate(kubetypes.SET,
   231  				kubetypes.HTTPSource,
   232  				&v1.Pod{
   233  					ObjectMeta: metav1.ObjectMeta{
   234  						UID:         "111",
   235  						Name:        "foo" + "-" + nodeName,
   236  						Namespace:   "default",
   237  						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "111"},
   238  					},
   239  					Spec: v1.PodSpec{
   240  						NodeName:                      nodeName,
   241  						RestartPolicy:                 v1.RestartPolicyAlways,
   242  						DNSPolicy:                     v1.DNSClusterFirst,
   243  						TerminationGracePeriodSeconds: &grace,
   244  						SecurityContext:               &v1.PodSecurityContext{},
   245  						SchedulerName:                 v1.DefaultSchedulerName,
   246  						EnableServiceLinks:            &enableServiceLinks,
   247  
   248  						Containers: []v1.Container{{
   249  							Name:                     "1",
   250  							Image:                    "foo",
   251  							TerminationMessagePath:   "/dev/termination-log",
   252  							ImagePullPolicy:          "Always",
   253  							TerminationMessagePolicy: v1.TerminationMessageReadFile,
   254  						}},
   255  					},
   256  					Status: v1.PodStatus{
   257  						Phase: v1.PodPending,
   258  					},
   259  				},
   260  				&v1.Pod{
   261  					ObjectMeta: metav1.ObjectMeta{
   262  						UID:         "222",
   263  						Name:        "bar" + "-" + nodeName,
   264  						Namespace:   "default",
   265  						Annotations: map[string]string{kubetypes.ConfigHashAnnotationKey: "222"},
   266  					},
   267  					Spec: v1.PodSpec{
   268  						NodeName:                      nodeName,
   269  						RestartPolicy:                 v1.RestartPolicyAlways,
   270  						DNSPolicy:                     v1.DNSClusterFirst,
   271  						TerminationGracePeriodSeconds: &grace,
   272  						SecurityContext:               &v1.PodSecurityContext{},
   273  						SchedulerName:                 v1.DefaultSchedulerName,
   274  						EnableServiceLinks:            &enableServiceLinks,
   275  
   276  						Containers: []v1.Container{{
   277  							Name:                     "2",
   278  							Image:                    "bar:bartag",
   279  							TerminationMessagePath:   "/dev/termination-log",
   280  							ImagePullPolicy:          "IfNotPresent",
   281  							TerminationMessagePolicy: v1.TerminationMessageReadFile,
   282  						}},
   283  					},
   284  					Status: v1.PodStatus{
   285  						Phase: v1.PodPending,
   286  					},
   287  				}),
   288  		},
   289  	}
   290  
   291  	for _, testCase := range testCases {
   292  		data, err := runtime.Encode(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), testCase.pods)
   293  		if err != nil {
   294  			t.Fatalf("%s: error in encoding the pod: %v", testCase.desc, err)
   295  		}
   296  		fakeHandler := utiltesting.FakeHandler{
   297  			StatusCode:   http.StatusOK,
   298  			ResponseBody: string(data),
   299  		}
   300  		testServer := httptest.NewServer(&fakeHandler)
   301  		defer testServer.Close()
   302  		ch := make(chan interface{}, 1)
   303  		c := sourceURL{testServer.URL, http.Header{}, types.NodeName(nodeName), ch, nil, 0, http.DefaultClient}
   304  		if err := c.extractFromURL(); err != nil {
   305  			t.Errorf("%s: Unexpected error: %v", testCase.desc, err)
   306  			continue
   307  		}
   308  		update := (<-ch).(kubetypes.PodUpdate)
   309  
   310  		if !apiequality.Semantic.DeepEqual(testCase.expected, update) {
   311  			t.Errorf("%s: Expected: %#v, Got: %#v", testCase.desc, testCase.expected, update)
   312  		}
   313  		for _, pod := range update.Pods {
   314  			// TODO: remove the conversion when validation is performed on versioned objects.
   315  			internalPod := &api.Pod{}
   316  			if err := k8s_api_v1.Convert_v1_Pod_To_core_Pod(pod, internalPod, nil); err != nil {
   317  				t.Fatalf("%s: Cannot convert pod %#v, %#v", testCase.desc, pod, err)
   318  			}
   319  			if errs := validation.ValidatePodCreate(internalPod, validation.PodValidationOptions{}); len(errs) != 0 {
   320  				t.Errorf("%s: Expected no validation errors on %#v, Got %v", testCase.desc, pod, errs.ToAggregate())
   321  			}
   322  		}
   323  	}
   324  }
   325  
   326  func TestURLWithHeader(t *testing.T) {
   327  	pod := &v1.Pod{
   328  		TypeMeta: metav1.TypeMeta{
   329  			APIVersion: "v1",
   330  			Kind:       "Pod",
   331  		},
   332  		ObjectMeta: metav1.ObjectMeta{
   333  			Name:      "foo",
   334  			UID:       "111",
   335  			Namespace: "mynamespace",
   336  		},
   337  		Spec: v1.PodSpec{
   338  			NodeName:   "localhost",
   339  			Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}},
   340  		},
   341  	}
   342  	data, err := json.Marshal(pod)
   343  	if err != nil {
   344  		t.Fatalf("Unexpected json marshalling error: %v", err)
   345  	}
   346  	fakeHandler := utiltesting.FakeHandler{
   347  		StatusCode:   http.StatusOK,
   348  		ResponseBody: string(data),
   349  	}
   350  	testServer := httptest.NewServer(&fakeHandler)
   351  	defer testServer.Close()
   352  	ch := make(chan interface{}, 1)
   353  	header := make(http.Header)
   354  	header.Set("Metadata-Flavor", "Google")
   355  	c := sourceURL{testServer.URL, header, "localhost", ch, nil, 0, http.DefaultClient}
   356  	if err := c.extractFromURL(); err != nil {
   357  		t.Fatalf("Unexpected error extracting from URL: %v", err)
   358  	}
   359  	update := (<-ch).(kubetypes.PodUpdate)
   360  
   361  	headerVal := fakeHandler.RequestReceived.Header["Metadata-Flavor"]
   362  	if len(headerVal) != 1 || headerVal[0] != "Google" {
   363  		t.Errorf("Header missing expected entry %v. Got %v", header, fakeHandler.RequestReceived.Header)
   364  	}
   365  	if len(update.Pods) != 1 {
   366  		t.Errorf("Received wrong number of pods, expected one: %v", update.Pods)
   367  	}
   368  }
   369  

View as plain text