sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/internal/util/objs_test.go (about)

     1  /*
     2  Copyright 2020 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 util
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	. "github.com/onsi/gomega"
    24  	appsv1 "k8s.io/api/apps/v1"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  )
    30  
    31  func Test_inspectImages(t *testing.T) {
    32  	type args struct {
    33  		objs []unstructured.Unstructured
    34  	}
    35  	tests := []struct {
    36  		name    string
    37  		args    args
    38  		want    []string
    39  		wantErr bool
    40  	}{
    41  		{
    42  			name: "controller without the RBAC proxy",
    43  			args: args{
    44  				objs: []unstructured.Unstructured{
    45  					{
    46  						Object: map[string]interface{}{
    47  							"apiVersion": "apps/v1",
    48  							"kind":       deploymentKind,
    49  							"spec": map[string]interface{}{
    50  								"template": map[string]interface{}{
    51  									"spec": map[string]interface{}{
    52  										"containers": []map[string]interface{}{
    53  											{
    54  												"name":  controllerContainerName,
    55  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:main",
    56  											},
    57  										},
    58  									},
    59  								},
    60  							},
    61  						},
    62  					},
    63  				},
    64  			},
    65  			want:    []string{"gcr.io/k8s-staging-cluster-api/cluster-api-controller:main"},
    66  			wantErr: false,
    67  		},
    68  		{
    69  			name: "controller with the RBAC proxy",
    70  			args: args{
    71  				objs: []unstructured.Unstructured{
    72  					{
    73  						Object: map[string]interface{}{
    74  							"apiVersion": "apps/v1",
    75  							"kind":       deploymentKind,
    76  							"spec": map[string]interface{}{
    77  								"template": map[string]interface{}{
    78  									"spec": map[string]interface{}{
    79  										"containers": []map[string]interface{}{
    80  											{
    81  												"name":  controllerContainerName,
    82  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:main",
    83  											},
    84  										},
    85  									},
    86  								},
    87  							},
    88  						},
    89  					},
    90  				},
    91  			},
    92  			want:    []string{"gcr.io/k8s-staging-cluster-api/cluster-api-controller:main"},
    93  			wantErr: false,
    94  		},
    95  		{
    96  			name: "controller with init container",
    97  			args: args{
    98  				objs: []unstructured.Unstructured{
    99  					{
   100  						Object: map[string]interface{}{
   101  							"apiVersion": "apps/v1",
   102  							"kind":       deploymentKind,
   103  							"spec": map[string]interface{}{
   104  								"template": map[string]interface{}{
   105  									"spec": map[string]interface{}{
   106  										"containers": []map[string]interface{}{
   107  											{
   108  												"name":  controllerContainerName,
   109  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:main",
   110  											},
   111  										},
   112  										"initContainers": []map[string]interface{}{
   113  											{
   114  												"name":  controllerContainerName,
   115  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:init",
   116  											},
   117  										},
   118  									},
   119  								},
   120  							},
   121  						},
   122  					},
   123  				},
   124  			},
   125  			want:    []string{"gcr.io/k8s-staging-cluster-api/cluster-api-controller:main", "gcr.io/k8s-staging-cluster-api/cluster-api-controller:init"},
   126  			wantErr: false,
   127  		},
   128  		{
   129  			name: "controller with deamonSet",
   130  			args: args{
   131  				objs: []unstructured.Unstructured{
   132  					{
   133  						Object: map[string]interface{}{
   134  							"apiVersion": "apps/v1",
   135  							"kind":       daemonSetKind,
   136  							"spec": map[string]interface{}{
   137  								"template": map[string]interface{}{
   138  									"spec": map[string]interface{}{
   139  										"containers": []map[string]interface{}{
   140  											{
   141  												"name":  controllerContainerName,
   142  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:main",
   143  											},
   144  										},
   145  										"initContainers": []map[string]interface{}{
   146  											{
   147  												"name":  controllerContainerName,
   148  												"image": "gcr.io/k8s-staging-cluster-api/cluster-api-controller:init",
   149  											},
   150  										},
   151  									},
   152  								},
   153  							},
   154  						},
   155  					},
   156  				},
   157  			},
   158  			want:    []string{"gcr.io/k8s-staging-cluster-api/cluster-api-controller:main", "gcr.io/k8s-staging-cluster-api/cluster-api-controller:init"},
   159  			wantErr: false,
   160  		},
   161  	}
   162  	for _, tt := range tests {
   163  		t.Run(tt.name, func(t *testing.T) {
   164  			g := NewWithT(t)
   165  
   166  			got, err := InspectImages(tt.args.objs)
   167  			if tt.wantErr {
   168  				g.Expect(err).To(HaveOccurred())
   169  				return
   170  			}
   171  
   172  			g.Expect(err).ToNot(HaveOccurred())
   173  			g.Expect(got).To(Equal(tt.want))
   174  		})
   175  	}
   176  }
   177  
   178  func TestFixImages(t *testing.T) {
   179  	type args struct {
   180  		objs           []unstructured.Unstructured
   181  		alterImageFunc func(image string) (string, error)
   182  	}
   183  	tests := []struct {
   184  		name    string
   185  		args    args
   186  		want    []string
   187  		wantErr bool
   188  	}{
   189  		{
   190  			name: "fix deployment containers images",
   191  			args: args{
   192  				objs: []unstructured.Unstructured{
   193  					{
   194  						Object: map[string]interface{}{
   195  							"apiVersion": "apps/v1",
   196  							"kind":       deploymentKind,
   197  							"spec": map[string]interface{}{
   198  								"template": map[string]interface{}{
   199  									"spec": map[string]interface{}{
   200  										"containers": []map[string]interface{}{
   201  											{
   202  												"image": "container-image",
   203  											},
   204  										},
   205  										"initContainers": []map[string]interface{}{
   206  											{
   207  												"image": "init-container-image",
   208  											},
   209  										},
   210  									},
   211  								},
   212  							},
   213  						},
   214  					},
   215  				},
   216  				alterImageFunc: func(image string) (string, error) {
   217  					return fmt.Sprintf("foo-%s", image), nil
   218  				},
   219  			},
   220  			want:    []string{"foo-container-image", "foo-init-container-image"},
   221  			wantErr: false,
   222  		},
   223  		{
   224  			name: "fix daemonSet containers images",
   225  			args: args{
   226  				objs: []unstructured.Unstructured{
   227  					{
   228  						Object: map[string]interface{}{
   229  							"apiVersion": "apps/v1",
   230  							"kind":       daemonSetKind,
   231  							"spec": map[string]interface{}{
   232  								"template": map[string]interface{}{
   233  									"spec": map[string]interface{}{
   234  										"containers": []map[string]interface{}{
   235  											{
   236  												"image": "container-image",
   237  											},
   238  										},
   239  										"initContainers": []map[string]interface{}{
   240  											{
   241  												"image": "init-container-image",
   242  											},
   243  										},
   244  									},
   245  								},
   246  							},
   247  						},
   248  					},
   249  				},
   250  				alterImageFunc: func(image string) (string, error) {
   251  					return fmt.Sprintf("foo-%s", image), nil
   252  				},
   253  			},
   254  			want:    []string{"foo-container-image", "foo-init-container-image"},
   255  			wantErr: false,
   256  		},
   257  	}
   258  	for _, tt := range tests {
   259  		t.Run(tt.name, func(t *testing.T) {
   260  			g := NewWithT(t)
   261  
   262  			got, err := FixImages(tt.args.objs, tt.args.alterImageFunc)
   263  			if tt.wantErr {
   264  				g.Expect(err).To(HaveOccurred())
   265  				return
   266  			}
   267  
   268  			g.Expect(err).ToNot(HaveOccurred())
   269  
   270  			gotImages, err := InspectImages(got)
   271  			g.Expect(err).ToNot(HaveOccurred())
   272  			g.Expect(gotImages).To(Equal(tt.want))
   273  		})
   274  	}
   275  }
   276  
   277  func TestIsDeploymentWithManager(t *testing.T) {
   278  	convertor := runtime.DefaultUnstructuredConverter
   279  
   280  	depManagerContainer := &appsv1.Deployment{
   281  		TypeMeta: metav1.TypeMeta{
   282  			Kind:       "Deployment",
   283  			APIVersion: "apps/v1",
   284  		},
   285  		ObjectMeta: metav1.ObjectMeta{
   286  			Name: "manager-deployment",
   287  		},
   288  		Spec: appsv1.DeploymentSpec{
   289  			Template: corev1.PodTemplateSpec{
   290  				Spec: corev1.PodSpec{
   291  					Containers: []corev1.Container{{Name: controllerContainerName}},
   292  				},
   293  			},
   294  		},
   295  	}
   296  	depManagerContainerObj, err := convertor.ToUnstructured(depManagerContainer)
   297  	if err != nil {
   298  		t.Fatalf("failed to construct unstructured object of %v: %v", depManagerContainer, err)
   299  	}
   300  
   301  	depNOManagerContainer := &appsv1.Deployment{
   302  		TypeMeta: metav1.TypeMeta{
   303  			Kind:       "Deployment",
   304  			APIVersion: "apps/v1",
   305  		},
   306  		ObjectMeta: metav1.ObjectMeta{
   307  			Name: "not-manager-deployment",
   308  		},
   309  		Spec: appsv1.DeploymentSpec{
   310  			Template: corev1.PodTemplateSpec{
   311  				Spec: corev1.PodSpec{
   312  					Containers: []corev1.Container{{Name: "not-manager"}},
   313  				},
   314  			},
   315  		},
   316  	}
   317  	depNOManagerContainerObj, err := convertor.ToUnstructured(depNOManagerContainer)
   318  	if err != nil {
   319  		t.Fatalf("failed to construct unstructured object of %v : %v", depNOManagerContainer, err)
   320  	}
   321  
   322  	svc := &corev1.Service{
   323  		TypeMeta: metav1.TypeMeta{
   324  			Kind:       "Service",
   325  			APIVersion: "v1",
   326  		},
   327  		ObjectMeta: metav1.ObjectMeta{
   328  			Name: "test-service",
   329  		},
   330  	}
   331  	svcObj, err := convertor.ToUnstructured(svc)
   332  	if err != nil {
   333  		t.Fatalf("failed to construct unstructured object of %v : %v", svc, err)
   334  	}
   335  
   336  	tests := []struct {
   337  		name     string
   338  		obj      unstructured.Unstructured
   339  		expected bool
   340  	}{
   341  		{
   342  			name:     "deployment with manager container",
   343  			obj:      unstructured.Unstructured{Object: depManagerContainerObj},
   344  			expected: true,
   345  		},
   346  		{
   347  			name:     "deployment without manager container",
   348  			obj:      unstructured.Unstructured{Object: depNOManagerContainerObj},
   349  			expected: false,
   350  		},
   351  		{
   352  			name:     "not a deployment",
   353  			obj:      unstructured.Unstructured{Object: svcObj},
   354  			expected: false,
   355  		},
   356  	}
   357  	for _, test := range tests {
   358  		t.Run(test.name, func(t *testing.T) {
   359  			g := NewWithT(t)
   360  			actual := IsDeploymentWithManager(test.obj)
   361  			g.Expect(actual).To(Equal(test.expected))
   362  		})
   363  	}
   364  }