istio.io/istio@v0.0.0-20240520182934-d79c90f27776/istioctl/pkg/checkinject/checkinject_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 checkinject
    16  
    17  import (
    18  	"os"
    19  	"testing"
    20  
    21  	admitv1 "k8s.io/api/admissionregistration/v1"
    22  	corev1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"sigs.k8s.io/yaml"
    25  
    26  	"istio.io/api/annotation"
    27  	"istio.io/api/label"
    28  	"istio.io/istio/pkg/test/util/assert"
    29  )
    30  
    31  func Test_analyzeRunningWebhooks(t *testing.T) {
    32  	cases := []struct {
    33  		name             string
    34  		pod              *corev1.Pod
    35  		ns               *corev1.Namespace
    36  		expectedMessages []webhookAnalysis
    37  	}{
    38  		{
    39  			name: "no inj because of no match labels",
    40  			pod:  podTestObject("test1", "test1", "", ""),
    41  			ns:   nsTestObject("test1", "", ""),
    42  			expectedMessages: []webhookAnalysis{
    43  				{
    44  					Name:     "istio-sidecar-injector",
    45  					Revision: "default",
    46  					Reason: "No matching namespace labels (istio.io/rev=default, istio-injection=enabled) " +
    47  						"or pod labels (istio.io/rev=default, sidecar.istio.io/inject=true)",
    48  				},
    49  				{
    50  					Name:     "istio-sidecar-injector-1-16",
    51  					Revision: "1-16",
    52  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
    53  				},
    54  				{
    55  					Name:     "istio-sidecar-injector-deactivated",
    56  					Revision: "default",
    57  					Reason:   "The injection webhook is deactivated, and will never match labels.",
    58  				},
    59  			},
    60  		},
    61  		{
    62  			name: "default ns injection",
    63  			pod:  podTestObject("test1", "test1", "", ""),
    64  			ns:   nsTestObject("test1", "enabled", ""),
    65  			expectedMessages: []webhookAnalysis{
    66  				{
    67  					Name:     "istio-sidecar-injector",
    68  					Revision: "default",
    69  					Injected: true,
    70  					Reason:   "Namespace label istio-injection=enabled matches",
    71  				},
    72  				{
    73  					Name:     "istio-sidecar-injector-1-16",
    74  					Revision: "1-16",
    75  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
    76  				},
    77  				{
    78  					Name:     "istio-sidecar-injector-deactivated",
    79  					Revision: "default",
    80  					Reason:   "The injection webhook is deactivated, and will never match labels.",
    81  				},
    82  			},
    83  		},
    84  		{
    85  			name: "rev ns injection",
    86  			pod:  podTestObject("test1", "test1", "", ""),
    87  			ns:   nsTestObject("test1", "", "1-16"),
    88  			expectedMessages: []webhookAnalysis{
    89  				{
    90  					Name:     "istio-sidecar-injector",
    91  					Revision: "default",
    92  					Reason: "No matching namespace labels (istio.io/rev=default, istio-injection=enabled) " +
    93  						"or pod labels (istio.io/rev=default, sidecar.istio.io/inject=true)",
    94  				},
    95  				{
    96  					Name:     "istio-sidecar-injector-1-16",
    97  					Revision: "1-16",
    98  					Injected: true,
    99  					Reason:   "Namespace label istio.io/rev=1-16 matches",
   100  				},
   101  				{
   102  					Name:     "istio-sidecar-injector-deactivated",
   103  					Revision: "default",
   104  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   105  				},
   106  			},
   107  		},
   108  		{
   109  			name: "rev po label injection",
   110  			pod:  podTestObject("test1", "test1", "", "1-16"),
   111  			ns:   nsTestObject("test1", "", ""),
   112  			expectedMessages: []webhookAnalysis{
   113  				{
   114  					Name:     "istio-sidecar-injector",
   115  					Revision: "default",
   116  					Reason:   "Pod has istio.io/rev=1-16 label, preventing injection",
   117  				},
   118  				{
   119  					Name:     "istio-sidecar-injector-1-16",
   120  					Revision: "1-16",
   121  					Injected: true,
   122  					Reason:   "Pod label istio.io/rev=1-16 matches",
   123  				},
   124  				{
   125  					Name:     "istio-sidecar-injector-deactivated",
   126  					Revision: "default",
   127  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   128  				},
   129  			},
   130  		},
   131  		{
   132  			name: "default pod label injection",
   133  			pod:  podTestObject("test1", "test1", "true", ""),
   134  			ns:   nsTestObject("test1", "", ""),
   135  			expectedMessages: []webhookAnalysis{
   136  				{
   137  					Name:     "istio-sidecar-injector",
   138  					Revision: "default",
   139  					Injected: true,
   140  					Reason:   "Pod label sidecar.istio.io/inject=true matches",
   141  				},
   142  				{
   143  					Name:     "istio-sidecar-injector-1-16",
   144  					Revision: "1-16",
   145  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
   146  				},
   147  				{
   148  					Name:     "istio-sidecar-injector-deactivated",
   149  					Revision: "default",
   150  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   151  				},
   152  			},
   153  		},
   154  		{
   155  			name: "both default label injection",
   156  			pod:  podTestObject("test1", "test1", "true", ""),
   157  			ns:   nsTestObject("test1", "enabled", ""),
   158  			expectedMessages: []webhookAnalysis{
   159  				{
   160  					Name:     "istio-sidecar-injector",
   161  					Revision: "default",
   162  					Injected: true,
   163  					Reason:   "Namespace label istio-injection=enabled matches, and pod label sidecar.istio.io/inject=true matches",
   164  				},
   165  				{
   166  					Name:     "istio-sidecar-injector-1-16",
   167  					Revision: "1-16",
   168  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
   169  				},
   170  				{
   171  					Name:     "istio-sidecar-injector-deactivated",
   172  					Revision: "default",
   173  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   174  				},
   175  			},
   176  		},
   177  		{
   178  			name: "both rev label injection",
   179  			pod:  podTestObject("test1", "test1", "", "1-16"),
   180  			ns:   nsTestObject("test1", "", "1-16"),
   181  			expectedMessages: []webhookAnalysis{
   182  				{
   183  					Name:     "istio-sidecar-injector",
   184  					Revision: "default",
   185  					Reason: "No matching namespace labels (istio.io/rev=default, istio-injection=enabled) " +
   186  						"or pod labels (istio.io/rev=default, sidecar.istio.io/inject=true)",
   187  				},
   188  				{
   189  					Name:     "istio-sidecar-injector-1-16",
   190  					Revision: "1-16",
   191  					Injected: true,
   192  					Reason:   "Namespace label istio.io/rev=1-16 matches",
   193  				},
   194  				{
   195  					Name:     "istio-sidecar-injector-deactivated",
   196  					Revision: "default",
   197  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   198  				},
   199  			},
   200  		},
   201  		{
   202  			name: "disable ns label and rev po label",
   203  			pod:  podTestObject("test1", "test1", "", "1-16"),
   204  			ns:   nsTestObject("test1", "disabled", ""),
   205  			expectedMessages: []webhookAnalysis{
   206  				{
   207  					Name:     "istio-sidecar-injector",
   208  					Revision: "default",
   209  					Reason:   "Namespace has istio-injection=disabled label, preventing injection",
   210  				},
   211  				{
   212  					Name:     "istio-sidecar-injector-1-16",
   213  					Revision: "1-16",
   214  					Injected: false,
   215  					Reason:   "Namespace has istio-injection=disabled label, preventing injection",
   216  				},
   217  				{
   218  					Name:     "istio-sidecar-injector-deactivated",
   219  					Revision: "default",
   220  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   221  				},
   222  			},
   223  		},
   224  		{
   225  			name: "ns and rev pod label",
   226  			pod:  podTestObject("test1", "test1", "", "1-16"),
   227  			ns:   nsTestObject("test1", "enabled", ""),
   228  			expectedMessages: []webhookAnalysis{
   229  				{
   230  					Name:     "istio-sidecar-injector",
   231  					Revision: "default",
   232  					Injected: true,
   233  					Reason:   "Namespace label istio-injection=enabled matches",
   234  				},
   235  				{
   236  					Name:     "istio-sidecar-injector-1-16",
   237  					Revision: "1-16",
   238  					Injected: false,
   239  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
   240  				},
   241  				{
   242  					Name:     "istio-sidecar-injector-deactivated",
   243  					Revision: "default",
   244  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   245  				},
   246  			},
   247  		},
   248  		{
   249  			name: "pod label with not inject",
   250  			pod:  podTestObject("test1", "test1", "false", ""),
   251  			ns:   nsTestObject("test1", "enabled", ""),
   252  			expectedMessages: []webhookAnalysis{
   253  				{
   254  					Name:     "istio-sidecar-injector",
   255  					Revision: "default",
   256  					Injected: false,
   257  					Reason:   "Pod has sidecar.istio.io/inject=false label, preventing injection",
   258  				},
   259  				{
   260  					Name:     "istio-sidecar-injector-1-16",
   261  					Revision: "1-16",
   262  					Injected: false,
   263  					Reason:   "No matching namespace labels (istio.io/rev=1-16) or pod labels (istio.io/rev=1-16)",
   264  				},
   265  				{
   266  					Name:     "istio-sidecar-injector-deactivated",
   267  					Revision: "default",
   268  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   269  				},
   270  			},
   271  		},
   272  		{
   273  			name: "pod not injectable for ns rev",
   274  			pod:  podTestObject("test1", "test1", "false", ""),
   275  			ns:   nsTestObject("test1", "", "1-16"),
   276  			expectedMessages: []webhookAnalysis{
   277  				{
   278  					Name:     "istio-sidecar-injector",
   279  					Revision: "default",
   280  					Injected: false,
   281  					Reason: "No matching namespace labels (istio.io/rev=default, istio-injection=enabled) " +
   282  						"or pod labels (istio.io/rev=default, sidecar.istio.io/inject=true)",
   283  				},
   284  				{
   285  					Name:     "istio-sidecar-injector-1-16",
   286  					Revision: "1-16",
   287  					Injected: false,
   288  					Reason:   "Pod has sidecar.istio.io/inject=false label, preventing injection",
   289  				},
   290  				{
   291  					Name:     "istio-sidecar-injector-deactivated",
   292  					Revision: "default",
   293  					Reason:   "The injection webhook is deactivated, and will never match labels.",
   294  				},
   295  			},
   296  		},
   297  	}
   298  	whFiles := []string{
   299  		"testdata/check-inject/default-injector.yaml",
   300  		"testdata/check-inject/rev-16-injector.yaml",
   301  		"testdata/check-inject/never-match-injector.yaml",
   302  	}
   303  	var whs []admitv1.MutatingWebhookConfiguration
   304  	for _, whName := range whFiles {
   305  		file, err := os.ReadFile(whName)
   306  		if err != nil {
   307  			t.Fatal(err)
   308  		}
   309  		var wh *admitv1.MutatingWebhookConfiguration
   310  		if err := yaml.Unmarshal(file, &wh); err != nil {
   311  			t.Fatal(err)
   312  		}
   313  		whs = append(whs, *wh)
   314  	}
   315  	for _, c := range cases {
   316  		t.Run(c.name, func(t *testing.T) {
   317  			checkResults := analyzeRunningWebhooks(whs,
   318  				c.pod.Labels, c.ns.Labels)
   319  			assert.Equal(t, c.expectedMessages, checkResults)
   320  		})
   321  	}
   322  }
   323  
   324  var nsTestObject = func(namespace, injLabelValue, revLabelValue string) *corev1.Namespace {
   325  	labels := map[string]string{}
   326  	if injLabelValue != "" {
   327  		labels["istio-injection"] = injLabelValue
   328  	}
   329  	if revLabelValue != "" {
   330  		labels[label.IoIstioRev.Name] = revLabelValue
   331  	}
   332  	return &corev1.Namespace{
   333  		ObjectMeta: metav1.ObjectMeta{
   334  			Name:   namespace,
   335  			Labels: labels,
   336  		},
   337  	}
   338  }
   339  
   340  var podTestObject = func(name, namespace, injLabelValue, revLabelValue string) *corev1.Pod {
   341  	labels := map[string]string{}
   342  	if injLabelValue != "" {
   343  		labels[annotation.SidecarInject.Name] = injLabelValue
   344  	}
   345  	if revLabelValue != "" {
   346  		labels[label.IoIstioRev.Name] = revLabelValue
   347  	}
   348  	return &corev1.Pod{
   349  		ObjectMeta: metav1.ObjectMeta{
   350  			Name:      name,
   351  			Namespace: namespace,
   352  			Labels:    labels,
   353  		},
   354  	}
   355  }