k8s.io/client-go@v0.22.2/tools/auth/exec/exec_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 exec
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
    28  	clientauthenticationv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
    29  	clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
    30  	"k8s.io/client-go/rest"
    31  )
    32  
    33  // restInfo holds the rest.Client fields that we care about for test assertions.
    34  type restInfo struct {
    35  	host            string
    36  	tlsClientConfig rest.TLSClientConfig
    37  	proxyURL        string
    38  }
    39  
    40  func TestLoadExecCredential(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	tests := []struct {
    44  		name               string
    45  		data               []byte
    46  		wantExecCredential runtime.Object
    47  		wantRESTInfo       restInfo
    48  		wantErrorPrefix    string
    49  	}{
    50  		{
    51  			name: "v1 happy path",
    52  			data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{
    53  				Spec: clientauthenticationv1.ExecCredentialSpec{
    54  					Cluster: &clientauthenticationv1.Cluster{
    55  						Server:                   "https://some-server/some/path",
    56  						TLSServerName:            "some-server-name",
    57  						InsecureSkipTLSVerify:    true,
    58  						CertificateAuthorityData: []byte("some-ca-data"),
    59  						ProxyURL:                 "https://some-proxy-url:12345",
    60  						Config: runtime.RawExtension{
    61  							Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`),
    62  						},
    63  					},
    64  				},
    65  			}),
    66  			wantExecCredential: &clientauthenticationv1.ExecCredential{
    67  				TypeMeta: metav1.TypeMeta{
    68  					Kind:       "ExecCredential",
    69  					APIVersion: clientauthenticationv1.SchemeGroupVersion.String(),
    70  				},
    71  				Spec: clientauthenticationv1.ExecCredentialSpec{
    72  					Cluster: &clientauthenticationv1.Cluster{
    73  						Server:                   "https://some-server/some/path",
    74  						TLSServerName:            "some-server-name",
    75  						InsecureSkipTLSVerify:    true,
    76  						CertificateAuthorityData: []byte("some-ca-data"),
    77  						ProxyURL:                 "https://some-proxy-url:12345",
    78  						Config: runtime.RawExtension{
    79  							Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`),
    80  						},
    81  					},
    82  				},
    83  			},
    84  			wantRESTInfo: restInfo{
    85  				host: "https://some-server/some/path",
    86  				tlsClientConfig: rest.TLSClientConfig{
    87  					Insecure:   true,
    88  					ServerName: "some-server-name",
    89  					CAData:     []byte("some-ca-data"),
    90  				},
    91  				proxyURL: "https://some-proxy-url:12345",
    92  			},
    93  		},
    94  		{
    95  			name: "v1beta1 happy path",
    96  			data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{
    97  				Spec: clientauthenticationv1beta1.ExecCredentialSpec{
    98  					Cluster: &clientauthenticationv1beta1.Cluster{
    99  						Server:                   "https://some-server/some/path",
   100  						TLSServerName:            "some-server-name",
   101  						InsecureSkipTLSVerify:    true,
   102  						CertificateAuthorityData: []byte("some-ca-data"),
   103  						ProxyURL:                 "https://some-proxy-url:12345",
   104  						Config: runtime.RawExtension{
   105  							Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`),
   106  						},
   107  					},
   108  				},
   109  			}),
   110  			wantExecCredential: &clientauthenticationv1beta1.ExecCredential{
   111  				TypeMeta: metav1.TypeMeta{
   112  					Kind:       "ExecCredential",
   113  					APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
   114  				},
   115  				Spec: clientauthenticationv1beta1.ExecCredentialSpec{
   116  					Cluster: &clientauthenticationv1beta1.Cluster{
   117  						Server:                   "https://some-server/some/path",
   118  						TLSServerName:            "some-server-name",
   119  						InsecureSkipTLSVerify:    true,
   120  						CertificateAuthorityData: []byte("some-ca-data"),
   121  						ProxyURL:                 "https://some-proxy-url:12345",
   122  						Config: runtime.RawExtension{
   123  							Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`),
   124  						},
   125  					},
   126  				},
   127  			},
   128  			wantRESTInfo: restInfo{
   129  				host: "https://some-server/some/path",
   130  				tlsClientConfig: rest.TLSClientConfig{
   131  					Insecure:   true,
   132  					ServerName: "some-server-name",
   133  					CAData:     []byte("some-ca-data"),
   134  				},
   135  				proxyURL: "https://some-proxy-url:12345",
   136  			},
   137  		},
   138  		{
   139  			name: "v1 nil config",
   140  			data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{
   141  				Spec: clientauthenticationv1.ExecCredentialSpec{
   142  					Cluster: &clientauthenticationv1.Cluster{
   143  						Server:                   "https://some-server/some/path",
   144  						TLSServerName:            "some-server-name",
   145  						InsecureSkipTLSVerify:    true,
   146  						CertificateAuthorityData: []byte("some-ca-data"),
   147  						ProxyURL:                 "https://some-proxy-url:12345",
   148  					},
   149  				},
   150  			}),
   151  			wantExecCredential: &clientauthenticationv1.ExecCredential{
   152  				TypeMeta: metav1.TypeMeta{
   153  					Kind:       "ExecCredential",
   154  					APIVersion: clientauthenticationv1.SchemeGroupVersion.String(),
   155  				},
   156  				Spec: clientauthenticationv1.ExecCredentialSpec{
   157  					Cluster: &clientauthenticationv1.Cluster{
   158  						Server:                   "https://some-server/some/path",
   159  						TLSServerName:            "some-server-name",
   160  						InsecureSkipTLSVerify:    true,
   161  						CertificateAuthorityData: []byte("some-ca-data"),
   162  						ProxyURL:                 "https://some-proxy-url:12345",
   163  					},
   164  				},
   165  			},
   166  			wantRESTInfo: restInfo{
   167  				host: "https://some-server/some/path",
   168  				tlsClientConfig: rest.TLSClientConfig{
   169  					Insecure:   true,
   170  					ServerName: "some-server-name",
   171  					CAData:     []byte("some-ca-data"),
   172  				},
   173  				proxyURL: "https://some-proxy-url:12345",
   174  			},
   175  		},
   176  		{
   177  			name: "v1beta1 nil config",
   178  			data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{
   179  				Spec: clientauthenticationv1beta1.ExecCredentialSpec{
   180  					Cluster: &clientauthenticationv1beta1.Cluster{
   181  						Server:                   "https://some-server/some/path",
   182  						TLSServerName:            "some-server-name",
   183  						InsecureSkipTLSVerify:    true,
   184  						CertificateAuthorityData: []byte("some-ca-data"),
   185  						ProxyURL:                 "https://some-proxy-url:12345",
   186  					},
   187  				},
   188  			}),
   189  			wantExecCredential: &clientauthenticationv1beta1.ExecCredential{
   190  				TypeMeta: metav1.TypeMeta{
   191  					Kind:       "ExecCredential",
   192  					APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
   193  				},
   194  				Spec: clientauthenticationv1beta1.ExecCredentialSpec{
   195  					Cluster: &clientauthenticationv1beta1.Cluster{
   196  						Server:                   "https://some-server/some/path",
   197  						TLSServerName:            "some-server-name",
   198  						InsecureSkipTLSVerify:    true,
   199  						CertificateAuthorityData: []byte("some-ca-data"),
   200  						ProxyURL:                 "https://some-proxy-url:12345",
   201  					},
   202  				},
   203  			},
   204  			wantRESTInfo: restInfo{
   205  				host: "https://some-server/some/path",
   206  				tlsClientConfig: rest.TLSClientConfig{
   207  					Insecure:   true,
   208  					ServerName: "some-server-name",
   209  					CAData:     []byte("some-ca-data"),
   210  				},
   211  				proxyURL: "https://some-proxy-url:12345",
   212  			},
   213  		},
   214  		{
   215  			name: "v1 invalid cluster",
   216  			data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{
   217  				Spec: clientauthenticationv1.ExecCredentialSpec{
   218  					Cluster: &clientauthenticationv1.Cluster{
   219  						ProxyURL: "invalid- url\n",
   220  					},
   221  				},
   222  			}),
   223  			wantErrorPrefix: "cannot create rest.Config",
   224  		},
   225  		{
   226  			name: "v1beta1 invalid cluster",
   227  			data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{
   228  				Spec: clientauthenticationv1beta1.ExecCredentialSpec{
   229  					Cluster: &clientauthenticationv1beta1.Cluster{
   230  						ProxyURL: "invalid- url\n",
   231  					},
   232  				},
   233  			}),
   234  			wantErrorPrefix: "cannot create rest.Config",
   235  		},
   236  		{
   237  			name:            "v1 nil cluster",
   238  			data:            marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{}),
   239  			wantErrorPrefix: "ExecCredential does not contain cluster information",
   240  		},
   241  		{
   242  			name:            "v1beta1 nil cluster",
   243  			data:            marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{}),
   244  			wantErrorPrefix: "ExecCredential does not contain cluster information",
   245  		},
   246  		{
   247  			name:            "v1alpha1",
   248  			data:            marshal(t, clientauthenticationv1alpha1.SchemeGroupVersion, &clientauthenticationv1alpha1.ExecCredential{}),
   249  			wantErrorPrefix: "ExecCredential does not contain cluster information",
   250  		},
   251  		{
   252  			name:            "invalid object kind",
   253  			data:            marshal(t, metav1.SchemeGroupVersion, &metav1.Status{}),
   254  			wantErrorPrefix: "invalid group/kind: wanted ExecCredential.client.authentication.k8s.io, got Status",
   255  		},
   256  		{
   257  			name:            "bad data",
   258  			data:            []byte("bad data"),
   259  			wantErrorPrefix: "decode: ",
   260  		},
   261  	}
   262  	for _, test := range tests {
   263  		test := test
   264  		t.Run(test.name, func(t *testing.T) {
   265  			t.Parallel()
   266  
   267  			execCredential, restConfig, err := LoadExecCredential(test.data)
   268  			if test.wantErrorPrefix != "" {
   269  				if err == nil {
   270  					t.Error("wanted error, got success")
   271  				} else if !strings.HasPrefix(err.Error(), test.wantErrorPrefix) {
   272  					t.Errorf("wanted '%s', got '%s'", test.wantErrorPrefix, err.Error())
   273  				}
   274  			} else if err != nil {
   275  				t.Error(err)
   276  			} else {
   277  				if diff := cmp.Diff(test.wantExecCredential, execCredential); diff != "" {
   278  					t.Error(diff)
   279  				}
   280  
   281  				if diff := cmp.Diff(test.wantRESTInfo.host, restConfig.Host); diff != "" {
   282  					t.Error(diff)
   283  				}
   284  				if diff := cmp.Diff(test.wantRESTInfo.tlsClientConfig, restConfig.TLSClientConfig); diff != "" {
   285  					t.Error(diff)
   286  				}
   287  
   288  				proxyURL, err := restConfig.Proxy(nil)
   289  				if err != nil {
   290  					t.Fatal(err)
   291  				}
   292  				if diff := cmp.Diff(test.wantRESTInfo.proxyURL, proxyURL.String()); diff != "" {
   293  					t.Error(diff)
   294  				}
   295  			}
   296  		})
   297  	}
   298  }
   299  
   300  func marshal(t *testing.T, gv schema.GroupVersion, obj runtime.Object) []byte {
   301  	t.Helper()
   302  
   303  	data, err := runtime.Encode(codecs.LegacyCodec(gv), obj)
   304  	if err != nil {
   305  		t.Fatal(err)
   306  	}
   307  
   308  	return data
   309  }