...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane/markcontrolplane_test.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/phases/markcontrolplane

     1  /*
     2  Copyright 2017 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 markcontrolplane
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"testing"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	clientset "k8s.io/client-go/kubernetes"
    29  	restclient "k8s.io/client-go/rest"
    30  
    31  	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
    32  )
    33  
    34  func TestMarkControlPlane(t *testing.T) {
    35  	// Note: this test takes advantage of the deterministic marshalling of
    36  	// JSON provided by strategicpatch so that "expectedPatch" can use a
    37  	// string equality test instead of a logical JSON equality test. That
    38  	// will need to change if strategicpatch's behavior changes in the
    39  	// future.
    40  	tests := []struct {
    41  		name           string
    42  		existingLabels []string
    43  		existingTaints []v1.Taint
    44  		newTaints      []v1.Taint
    45  		expectedPatch  string
    46  	}{
    47  		{
    48  			name:           "apply default labels",
    49  			existingLabels: []string{""},
    50  			existingTaints: nil,
    51  			newTaints:      nil,
    52  			expectedPatch:  `{"metadata":{"labels":{"node-role.kubernetes.io/control-plane":"","node.kubernetes.io/exclude-from-external-load-balancers":""}}}`,
    53  		},
    54  		{
    55  			name: "control-plane taint missing",
    56  			existingLabels: []string{
    57  				kubeadmconstants.LabelNodeRoleControlPlane,
    58  				kubeadmconstants.LabelExcludeFromExternalLB,
    59  			},
    60  			existingTaints: nil,
    61  			newTaints:      []v1.Taint{kubeadmconstants.ControlPlaneTaint},
    62  			expectedPatch:  `{"spec":{"taints":[{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"}]}}`,
    63  		},
    64  		{
    65  			name: "nothing missing",
    66  			existingLabels: []string{
    67  				kubeadmconstants.LabelNodeRoleControlPlane,
    68  				kubeadmconstants.LabelExcludeFromExternalLB,
    69  			},
    70  			existingTaints: []v1.Taint{kubeadmconstants.ControlPlaneTaint},
    71  			newTaints:      []v1.Taint{kubeadmconstants.ControlPlaneTaint},
    72  			expectedPatch:  `{}`,
    73  		},
    74  		{
    75  			name: "has taint and no new taints wanted",
    76  			existingLabels: []string{
    77  				kubeadmconstants.LabelNodeRoleControlPlane,
    78  				kubeadmconstants.LabelExcludeFromExternalLB,
    79  			},
    80  			existingTaints: []v1.Taint{
    81  				{
    82  					Key:    "node.cloudprovider.kubernetes.io/uninitialized",
    83  					Effect: v1.TaintEffectNoSchedule,
    84  				},
    85  			},
    86  			newTaints:     nil,
    87  			expectedPatch: `{}`,
    88  		},
    89  		{
    90  			name: "has taint and should merge with wanted taint",
    91  			existingLabels: []string{
    92  				kubeadmconstants.LabelNodeRoleControlPlane,
    93  				kubeadmconstants.LabelExcludeFromExternalLB,
    94  			},
    95  			existingTaints: []v1.Taint{
    96  				{
    97  					Key:    "node.cloudprovider.kubernetes.io/uninitialized",
    98  					Effect: v1.TaintEffectNoSchedule,
    99  				},
   100  			},
   101  			newTaints:     []v1.Taint{kubeadmconstants.ControlPlaneTaint},
   102  			expectedPatch: `{"spec":{"taints":[{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"},{"effect":"NoSchedule","key":"node.cloudprovider.kubernetes.io/uninitialized"}]}}`,
   103  		},
   104  	}
   105  
   106  	for _, tc := range tests {
   107  		t.Run(tc.name, func(t *testing.T) {
   108  			nodename := "node01"
   109  			controlPlaneNode := &v1.Node{
   110  				ObjectMeta: metav1.ObjectMeta{
   111  					Name: nodename,
   112  					Labels: map[string]string{
   113  						v1.LabelHostname: nodename,
   114  					},
   115  				},
   116  			}
   117  
   118  			for _, label := range tc.existingLabels {
   119  				controlPlaneNode.ObjectMeta.Labels[label] = ""
   120  			}
   121  
   122  			if tc.existingTaints != nil {
   123  				controlPlaneNode.Spec.Taints = tc.existingTaints
   124  			}
   125  
   126  			jsonNode, err := json.Marshal(controlPlaneNode)
   127  			if err != nil {
   128  				t.Fatalf("unexpected encoding error: %v", err)
   129  			}
   130  
   131  			var patchRequest string
   132  			s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   133  				w.Header().Set("Content-Type", "application/json")
   134  
   135  				if req.URL.Path != "/api/v1/nodes/"+nodename {
   136  					t.Errorf("request for unexpected HTTP resource: %v", req.URL.Path)
   137  					http.Error(w, "", http.StatusNotFound)
   138  					return
   139  				}
   140  
   141  				switch req.Method {
   142  				case "GET":
   143  				case "PATCH":
   144  					buf := new(bytes.Buffer)
   145  					buf.ReadFrom(req.Body)
   146  					patchRequest = buf.String()
   147  				default:
   148  					t.Errorf("request for unexpected HTTP verb: %v", req.Method)
   149  					http.Error(w, "", http.StatusNotFound)
   150  					return
   151  				}
   152  
   153  				w.WriteHeader(http.StatusOK)
   154  				w.Write(jsonNode)
   155  			}))
   156  			defer s.Close()
   157  
   158  			cs, err := clientset.NewForConfig(&restclient.Config{Host: s.URL})
   159  			if err != nil {
   160  				t.Fatalf("unexpected error building clientset: %v", err)
   161  			}
   162  
   163  			if err := MarkControlPlane(cs, nodename, tc.newTaints); err != nil {
   164  				t.Errorf("unexpected error: %v", err)
   165  			}
   166  
   167  			if tc.expectedPatch != patchRequest {
   168  				t.Errorf("unexpected error: wanted patch %v, got %v", tc.expectedPatch, patchRequest)
   169  			}
   170  		})
   171  	}
   172  }
   173  

View as plain text