Skip to content

Commit d48025d

Browse files
vinceprik8s-ci-robot
authored andcommitted
Add remote/util.go helpers to work with KubeConfig Secrets (kubernetes-sigs#1004)
Signed-off-by: Vince Prignano <[email protected]>
1 parent f88835a commit d48025d

File tree

5 files changed

+196
-1
lines changed

5 files changed

+196
-1
lines changed

pkg/controller/BUILD.bazel

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ go_library(
66
"add_machinedeployment.go",
77
"add_machineset.go",
88
"add_node.go",
9-
"noderef_controller.go",
9+
"controller.go",
1010
],
1111
importpath = "sigs.k8s.io/cluster-api/pkg/controller",
1212
visibility = ["//visibility:public"],

pkg/controller/cluster/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ go_library(
1414
"//pkg/controller/error:go_default_library",
1515
"//pkg/util:go_default_library",
1616
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
17+
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
1718
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
1819
"//vendor/k8s.io/klog:go_default_library",
1920
"//vendor/sigs.k8s.io/controller-runtime/pkg/client:go_default_library",

pkg/controller/remote/BUILD.bazel

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["util.go"],
6+
importpath = "sigs.k8s.io/cluster-api/pkg/controller/remote",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//vendor/github.com/pkg/errors:go_default_library",
10+
"//vendor/k8s.io/api/core/v1:go_default_library",
11+
"//vendor/sigs.k8s.io/controller-runtime/pkg/client:go_default_library",
12+
],
13+
)
14+
15+
go_test(
16+
name = "go_default_test",
17+
srcs = ["util_test.go"],
18+
embed = [":go_default_library"],
19+
deps = [
20+
"//vendor/k8s.io/api/core/v1:go_default_library",
21+
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
22+
"//vendor/sigs.k8s.io/controller-runtime/pkg/client/fake:go_default_library",
23+
],
24+
)

pkg/controller/remote/util.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2019 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 remote
18+
19+
import (
20+
"context"
21+
"encoding/base64"
22+
"fmt"
23+
24+
"github.com/pkg/errors"
25+
corev1 "k8s.io/api/core/v1"
26+
"sigs.k8s.io/controller-runtime/pkg/client"
27+
)
28+
29+
const (
30+
kubeconfigSecretKey = "value"
31+
)
32+
33+
// KubeConfigSecretName generates the expected name for the Kubeconfig secret
34+
// to access a remote cluster given the cluster's name.
35+
func KubeConfigSecretName(cluster string) string {
36+
return fmt.Sprintf("%s-kubeconfig", cluster)
37+
}
38+
39+
// GetKubeConfigSecret retrieves the KubeConfig Secret (if any)
40+
// from the given cluster name and namespace.
41+
func GetKubeConfigSecret(c client.Client, cluster, namespace string) (*corev1.Secret, error) {
42+
secret := &corev1.Secret{}
43+
secretKey := client.ObjectKey{
44+
Namespace: namespace,
45+
Name: KubeConfigSecretName(cluster),
46+
}
47+
48+
if err := c.Get(context.TODO(), secretKey, secret); err != nil {
49+
return nil, err
50+
}
51+
52+
return secret, nil
53+
}
54+
55+
// DecodeKubeConfigSecret uses the Secret to retrieve and decode the data.
56+
func DecodeKubeConfigSecret(secret *corev1.Secret) ([]byte, error) {
57+
encodedKubeconfig, ok := secret.Data[kubeconfigSecretKey]
58+
if !ok {
59+
return nil, errors.Errorf("missing value in secret %s/%s", secret.Namespace, secret.Name)
60+
}
61+
62+
kubeconfig, err := base64.StdEncoding.DecodeString(string(encodedKubeconfig))
63+
if err != nil {
64+
return nil, errors.Wrapf(err, "cannot decode kubeconfig secret %s/%s", secret.Namespace, secret.Name)
65+
}
66+
67+
return kubeconfig, nil
68+
}

pkg/controller/remote/util_test.go

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
Copyright 2019 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 remote
18+
19+
import (
20+
"encoding/base64"
21+
"reflect"
22+
"testing"
23+
24+
corev1 "k8s.io/api/core/v1"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
27+
)
28+
29+
var (
30+
validKubeConfig = `
31+
clusters:
32+
- cluster:
33+
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1ERXhNREU0TURBME1Gb1hEVEk1TURFd056RTRNREEwTUZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBT1EvCmVndmViNk1qMHkzM3hSbGFjczd6OXE4QTNDajcrdnRrZ0pUSjRUSVB4TldRTEd0Q0dmL0xadzlHMW9zNmRKUHgKZFhDNmkwaHA5czJuT0Y2VjQvREUrYUNTTU45VDYzckdWb2s0TkcwSlJPYmlRWEtNY1VQakpiYm9PTXF2R2lLaAoyMGlFY0h5K3B4WkZOb3FzdnlaRGM5L2dRSHJVR1FPNXp6TDNHZGhFL0k1Nkczek9JaWhhbFRHSTNaakRRS05CCmVFV3FONTVDcHZzT3I1b0ZnTmZZTXk2YzZ4WXlUTlhWSUkwNFN0Z2xBbUk4bzZWaTNUVEJhZ1BWaldIVnRha1EKU2w3VGZtVUlIdndKZUo3b2hxbXArVThvaGVTQUIraHZSbDIrVHE5NURTemtKcmRjNmphcyswd2FWaEJydEh1agpWMU15NlNvV2VVUlkrdW5VVFgwQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIT2thSXNsd0pCOE5PaENUZkF4UWlnaUc1bEMKQlo0LytGeHZ3Y1pnWGhlL0IyUWo1UURMNWlRUU1VL2NqQ0tyYUxkTFFqM1o1aHA1dzY0K2NWRUg3Vm9PSTFCaQowMm13YTc4eWo4aDNzQ2lLQXJiU21kKzNld1QrdlNpWFMzWk9EYWRHVVRRa1BnUHB0THlaMlRGakF0SW43WjcyCmpnYlVnT2FXaklKbnlwRVJ5UmlSKzBvWlk4SUlmWWFsTHUwVXlXcmkwaVhNRmZqQUQ1UVNURy8zRGN5djhEN1UKZHBxU2l5ekJkZVRjSExyenpEbktBeXhQWWgvcWpKZ0tRdEdIakhjY0FCSE1URlFtRy9Ea1pNTnZWL2FZSnMrKwp0aVJCbHExSFhlQ0d4aExFcGdQcGxVb3IrWmVYTGF2WUo0Z2dMVmIweGl2QTF2RUtyaUUwak1Wd2lQaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
34+
server: https://test-cluster-api:6443
35+
name: test-cluster-api
36+
contexts:
37+
- context:
38+
cluster: test-cluster-api
39+
user: kubernetes-admin
40+
name: kubernetes-admin@test-cluster-api
41+
current-context: kubernetes-admin@test-cluster-api
42+
kind: Config
43+
preferences: {}
44+
users:
45+
- name: kubernetes-admin
46+
user:
47+
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJUTJFS3c0cU0wbFV3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBeE1UQXhPREF3TkRCYUZ3MHlNREF4TVRBeE9EQXdOREphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXUxeWNHcVdLMlZBUGpmWlYKeUdHWmhvQWdxZ1oreVFqU0pYQlVwNkR4VkZyYStENHJDVkNpRDNhWTVmTWNXaVpYVy9uanJsNFRudWJydndhWgpTN0hhMUxELzFZdmhFUFhLcnlBMzVNMStsN0JkUjA3T3NlRnFqNXNJQk9xWDNoNEJmckQ0SFQ5VGxSS082TXgxClMycSt5NzVaYjI5eXN0UTk3SGk4ZXVBS0sxN0JuSmJ5Zk80NlMvOFVxc2tlb0JXT3VnRkJHMlQrTFd6RXluK1oKVjdUUHZxdDE0MG1lQU40TStZUy91dFp2VmE0WFFmKy80czB4TjVwMGw4M0RrYnVWbnErcjR5dzBiSHM4cHdWdwo0Z3RuTVhrbjFhcGUwOGN4YUtBMGpodnZ4cFgyVnhHbEsxUTR0aDk1S2JNQWlpMlVINFcyNE1GSnlxOHloOUljCk54UldZd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCbDUwSmNVblhGRHB4TWtkL2JOdlRHMkxVTnVWTVNnQmlCNQpmbFlpWTJibUQ3NVMreEE0eEwrZEYxanlJZHRDTGVtZURoS2MwRWtyVUpyYk5XSTZnVDB0OFAwWVNuYmxiY09ICmxBRHdmMjhoVW5TYTdIR1NOaWNBdDdKOGpnd296ZzFDVnNWbE9YM2cvcWdmSkdYeld0QzJMRFVvdjR3MFVNMVgKQ2pLNFdtMk8xTDFybEpzaHE1VysxalZzTEllYnZIcjlYb0cxRlcyY0ovcHJTK0dFS2dtNWc4YjZ1MWdJQXVFNAozOHNVQTltU3ZBYlgwR1RWdXI3Um9taWhSR2QwTktZK0k1S3A2bWtIRnpLVEVRbks2YXcrQWMvVFJObmFwUEh6Ci9IMXA0eGkyWlFHYi84MURhQjVTZDRwTURzK09FK1BNNitudkN4amN2eFdFbEdTdjE2Yz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
48+
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdTF5Y0dxV0syVkFQamZaVnlHR1pob0FncWdaK3lRalNKWEJVcDZEeFZGcmErRDRyCkNWQ2lEM2FZNWZNY1dpWlhXL25qcmw0VG51YnJ2d2FaUzdIYTFMRC8xWXZoRVBYS3J5QTM1TTErbDdCZFIwN08Kc2VGcWo1c0lCT3FYM2g0QmZyRDRIVDlUbFJLTzZNeDFTMnEreTc1WmIyOXlzdFE5N0hpOGV1QUtLMTdCbkpieQpmTzQ2Uy84VXFza2VvQldPdWdGQkcyVCtMV3pFeW4rWlY3VFB2cXQxNDBtZUFONE0rWVMvdXRadlZhNFhRZisvCjRzMHhONXAwbDgzRGtidVZucStyNHl3MGJIczhwd1Z3NGd0bk1Ya24xYXBlMDhjeGFLQTBqaHZ2eHBYMlZ4R2wKSzFRNHRoOTVLYk1BaWkyVUg0VzI0TUZKeXE4eWg5SWNOeFJXWXdJREFRQUJBb0lCQVFDc0JLamw1aHNHemZTWgorQkptT1FXRmNWbU1BUTZpY0ZEUVFzUFdhM05tYVV3bElwN01uSlZOOFNzTDVCcWh3aFh1d2cwQjZDbkhlR2YxCktJL1I2V2JxWTk5ZkpsL3EvRitzVGI1RGVVL0M0UStqQ24zRzN4akE1Q3VHcUFQcTBFMjdEYXVlM3FkVWRJZDAKd1ZMbmZRZlRjOTRVNjVPNUVCZ1NaZjlXS1IvdEZDNHpGSlVselhHTlYxT2hOTWVyeXovbllmSVRZZGppUWNiRwplcDJucHk1cHZ5dEFPY1RiV0xXUEw4T2RKTDMvTER3b0h2aHlSa3huZXhWRTc0K3ZGd2lYbkRkNEp6ODVJVzBvCkFyeGEyRlJzOGZyWXFreHNSQ1VGYmRXNUpMTzhRVFBWYnl3S1c3Z0Z4S0c1U1c4Y004cmJLTHEzT01JOXBXVkoKTzNscVQxc1JBb0dCQU50QUxzR2VodzZsZWN3Zi9VU0RFN0FWNFQrdDJsWit6a3J1d3dodloyWXJYZHpXbGVqTAprNGpZWjhkQUNUUVdDRkJlaWtmYi9XdzZtMFF3ZUZudzExdVd1WndWRVJPS3BnRDFTa0krcVRtdGd0V2J2Y2lBClg4U0t4SU5qTGNzTzRLZUoxdEdkaVVDVEg3MW8zV0pBOXYzR3NaTlkrdW1WTVhnaGQ2d2YrTnB0QW9HQkFOckUKR3djOWNLVGVtZWZWSTcraFVtS2YvNm9SQ2NYdWxIK3gwSEZwNVBIQzl3NEhTMVp0Zk9NS3F6QzlJMWt6a200RwpjYW11WHovRy9iQXg4WGdaa3lURnRxTk5hdjE3Y0UzV25GRlMxejRHeGRQNDMvSkdLVWJrUzhkM1dZc0pkZnRYCkt5Vm45anl3Yjc0VG5hSnFIVlBSWFJRSkNFR3E2VlR4RVVGNlIzSVBBb0dBSmFTYlluckpUV1p6eHV3bkc4QTEKZlNJRWpsNVhBa3E3T0hwTjJnRG1pOUFlU1hBK1JMM1BFc3UwNWF6RTU4QndwUHZXV2dnWE5xSEpUcWZUd2Yxcgp2RG5nbkQreHN0MDNLeXJ5R1BXUk1HbnQ4S2JRcXIvL3NVcngrbXpveTlnK0VnWEVjRERRQTlvK3ROSndVQkkvClZjcnJhaFQ0MzJuU0dJSUdmZkx2VXZFQ2dZQmtNRGVvb3l5NWRQRExTY09yZVhnL2pzTUo0ZSsxNUVQQ0QyOUUKNFpobVdFSEkvUEkxek1MTFFCR1NxcXhMcCtEQjN0V2pQaWFGRU44U0dHMWI4V3FBQnNSVUdacU1LRUlRZzk3bgpKNmRIMHRZNjg5bXNIUkcrVThPWXdFSVQrT3M5aG5oT0UwU2tHckd5UFUyT0drY0FJZndjdHQ0L0pNVGpqOXUxClB3a0ZaUUtCZ1FDTWppdkpGL3crQXlUZUo0K1piWWpvZ091QkJFRE9oeXdiRnN5NC9ubVduTm4rQXRYQklDaGkKR2J6LzFuWkZTOGc2Nlh2cGFTWEQ5blVpS1BOUW5ORzUralJmclluTlI4WERCL3ZiNk9TMVFHbXBvWWxJZ2Q3UgpjTVpSRm1sbTUvbkJMWkdoVVpjOXZVN1pRVis4RXdLK2lHaGNrTFduVGhHNURZTkRWaksxcFE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
49+
`
50+
51+
validSecret = &corev1.Secret{
52+
ObjectMeta: metav1.ObjectMeta{
53+
Name: "test1-kubeconfig",
54+
Namespace: "test",
55+
},
56+
Data: map[string][]byte{
57+
kubeconfigSecretKey: []byte(base64.StdEncoding.EncodeToString([]byte(validKubeConfig))),
58+
},
59+
}
60+
61+
invalidSecret = &corev1.Secret{
62+
ObjectMeta: metav1.ObjectMeta{
63+
Name: "test2-kubeconfig",
64+
Namespace: "test",
65+
},
66+
Data: map[string][]byte{
67+
kubeconfigSecretKey: []byte("Not valid!!1"),
68+
},
69+
}
70+
)
71+
72+
func TestGetKubeConfigSecret(t *testing.T) {
73+
client := fake.NewFakeClient(validSecret)
74+
found, err := GetKubeConfigSecret(client, "test1", "test")
75+
if err != nil {
76+
t.Fatalf("Expected no error, got %v", err)
77+
}
78+
79+
if !reflect.DeepEqual(validSecret, found) {
80+
t.Fatalf("Expected found secret to be equal to input")
81+
}
82+
}
83+
84+
func TestDecodeKubeConfigSecret(t *testing.T) {
85+
t.Run("with valid secret", func(t *testing.T) {
86+
out, err := DecodeKubeConfigSecret(validSecret)
87+
if err != nil {
88+
t.Fatalf("Expected no error, got %v", err)
89+
}
90+
91+
if string(out) != validKubeConfig {
92+
t.Fatalf("Expected decoded KubeConfig to match input")
93+
}
94+
})
95+
96+
t.Run("with invalid secret", func(t *testing.T) {
97+
_, err := DecodeKubeConfigSecret(invalidSecret)
98+
if err == nil {
99+
t.Fatalf("Expected error, got nil")
100+
}
101+
})
102+
}

0 commit comments

Comments
 (0)