|
4 | 4 | package ctx |
5 | 5 |
|
6 | 6 | import ( |
7 | | - golangContext "context" |
8 | | - "encoding/csv" |
9 | | - "flag" |
10 | | - "fmt" |
11 | | - "io/ioutil" |
12 | | - "os" |
13 | | - "os/exec" |
14 | | - "path/filepath" |
15 | | - "strings" |
16 | | - "sync" |
17 | | - "time" |
18 | | - |
19 | | - corev1 "k8s.io/api/core/v1" |
20 | | - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
21 | | - "k8s.io/apimachinery/pkg/util/rand" |
22 | | - "k8s.io/client-go/tools/clientcmd" |
23 | | - "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" |
24 | | - "sigs.k8s.io/kind/pkg/cluster" |
25 | | - "sigs.k8s.io/kind/pkg/cluster/nodeutils" |
26 | | - "sigs.k8s.io/kind/pkg/log" |
| 7 | + golangContext "context" |
| 8 | + "encoding/csv" |
| 9 | + "flag" |
| 10 | + "fmt" |
| 11 | + "io/ioutil" |
| 12 | + "os" |
| 13 | + "os/exec" |
| 14 | + "path/filepath" |
| 15 | + "strings" |
| 16 | + "sync" |
| 17 | + "time" |
| 18 | + |
| 19 | + corev1 "k8s.io/api/core/v1" |
| 20 | + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 21 | + "k8s.io/apimachinery/pkg/util/rand" |
| 22 | + "k8s.io/client-go/tools/clientcmd" |
| 23 | + "sigs.k8s.io/kind/pkg/cluster" |
| 24 | + "sigs.k8s.io/kind/pkg/cluster/nodeutils" |
| 25 | + "sigs.k8s.io/kind/pkg/log" |
27 | 26 | ) |
28 | 27 |
|
29 | 28 | var ( |
30 | | - images = flag.String("kind.images", "", "comma-separated list of image archives to load on cluster nodes, relative to the test binary or test package path") |
| 29 | + images = flag.String("kind.images", "", "comma-separated list of image archives to load on cluster nodes, relative to the test binary or test package path") |
31 | 30 | ) |
32 | 31 |
|
33 | 32 | type kindLogAdapter struct { |
34 | | - *TestContext |
| 33 | + *TestContext |
35 | 34 | } |
36 | 35 |
|
37 | 36 | var _ log.Logger = kindLogAdapter{} |
38 | 37 |
|
39 | 38 | func (kl kindLogAdapter) Enabled() bool { |
40 | | - return true |
| 39 | + return true |
41 | 40 | } |
42 | 41 |
|
43 | 42 | func (kl kindLogAdapter) Info(message string) { |
44 | | - kl.Infof(message) |
| 43 | + kl.Infof(message) |
45 | 44 | } |
46 | 45 |
|
47 | 46 | func (kl kindLogAdapter) Infof(format string, args ...interface{}) { |
48 | | - kl.Logf(format, args) |
| 47 | + kl.Logf(format, args) |
49 | 48 | } |
50 | 49 |
|
51 | 50 | func (kl kindLogAdapter) Warn(message string) { |
52 | | - kl.Warnf(message) |
| 51 | + kl.Warnf(message) |
53 | 52 | } |
54 | 53 |
|
55 | 54 | func (kl kindLogAdapter) Warnf(format string, args ...interface{}) { |
56 | | - kl.Logf(format, args) |
| 55 | + kl.Logf(format, args) |
57 | 56 | } |
58 | 57 |
|
59 | 58 | func (kl kindLogAdapter) Error(message string) { |
60 | | - kl.Errorf(message) |
| 59 | + kl.Errorf(message) |
61 | 60 | } |
62 | 61 |
|
63 | 62 | func (kl kindLogAdapter) Errorf(format string, args ...interface{}) { |
64 | | - kl.Logf(format, args) |
| 63 | + kl.Logf(format, args) |
65 | 64 | } |
66 | 65 |
|
67 | 66 | func (kl kindLogAdapter) V(log.Level) log.InfoLogger { |
68 | | - return kl |
| 67 | + return kl |
69 | 68 | } |
70 | 69 |
|
71 | 70 | func Provision(ctx *TestContext) (func(), error) { |
72 | | - dir, err := ioutil.TempDir("", "kind.") |
73 | | - if err != nil { |
74 | | - return nil, fmt.Errorf("failed to create temporary directory: %s", err.Error()) |
75 | | - } |
76 | | - defer os.RemoveAll(dir) |
77 | | - kubeconfigPath := filepath.Join(dir, "kubeconfig") |
78 | | - |
79 | | - provider := cluster.NewProvider( |
80 | | - cluster.ProviderWithLogger(kindLogAdapter{ctx}), |
81 | | - ) |
82 | | - name := fmt.Sprintf("kind-%s", rand.String(16)) |
83 | | - |
84 | | - // create cluster with configuration: |
85 | | - // 1. use local docker registry |
86 | | - // 2. wait for 5 minutes for control plane |
87 | | - // 3. use explicit kube config path |
88 | | - registry := "kind-registry" |
89 | | - // registry := "localhost" |
90 | | - registryPort := 5000 |
91 | | - if err := provider.Create( |
92 | | - name, |
93 | | - cluster.CreateWithV1Alpha4Config(&v1alpha4.Cluster{ |
94 | | - ContainerdConfigPatches: []string{ |
95 | | - fmt.Sprintf(`[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:%[2]d"] |
96 | | - endpoint = ["http://%[1]s:%[2]d"]`, registry, registryPort), |
97 | | - }, |
98 | | - }), |
99 | | - cluster.CreateWithWaitForReady(5*time.Minute), |
100 | | - cluster.CreateWithKubeconfigPath(kubeconfigPath), |
101 | | - ); err != nil { |
102 | | - return nil, fmt.Errorf("failed to create kind cluster: %s", err.Error()) |
103 | | - } |
104 | | - |
105 | | - nodes, err := provider.ListNodes(name) |
106 | | - if err != nil { |
107 | | - return nil, fmt.Errorf("failed to list kind nodes: %s", err.Error()) |
108 | | - } |
109 | | - |
110 | | - var archives []string |
111 | | - if images != nil { |
112 | | - records, err := csv.NewReader(strings.NewReader(*images)).ReadAll() |
113 | | - if err != nil { |
114 | | - return nil, fmt.Errorf("error parsing image flag: %s", err.Error()) |
115 | | - } |
116 | | - for _, row := range records { |
117 | | - archives = append(archives, row...) |
118 | | - } |
119 | | - } |
120 | | - |
121 | | - for _, archive := range archives { |
122 | | - for _, node := range nodes { |
123 | | - fd, err := os.Open(archive) |
124 | | - if err != nil { |
125 | | - return nil, fmt.Errorf("error opening archive %q: %s", archive, err.Error()) |
126 | | - } |
127 | | - err = nodeutils.LoadImageArchive(node, fd) |
128 | | - fd.Close() |
129 | | - if err != nil { |
130 | | - return nil, fmt.Errorf("error loading image archive %q to node %q: %s", archive, node, err.Error()) |
131 | | - } |
132 | | - } |
133 | | - } |
134 | | - |
135 | | - kubeconfig, err := provider.KubeConfig(name, false) |
136 | | - if err != nil { |
137 | | - return nil, fmt.Errorf("failed to read kubeconfig: %s", err.Error()) |
138 | | - } |
139 | | - restConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeconfig)) |
140 | | - if err != nil { |
141 | | - return nil, fmt.Errorf("error loading kubeconfig: %s", err.Error()) |
142 | | - } |
143 | | - |
144 | | - ctx.restConfig = restConfig |
145 | | - |
146 | | - var once sync.Once |
147 | | - deprovision := func() { |
148 | | - once.Do(func() { |
149 | | - provider.Delete(name, kubeconfigPath) |
150 | | - }) |
151 | | - } |
152 | | - derivedFieldsErr := setDerivedFields(ctx) |
153 | | - // make best attempt before we return to: |
154 | | - // 1) add local registry ConfigMap |
155 | | - // 2) connect "kind" network to the registry |
156 | | - if derivedFieldsErr == nil { |
157 | | - // add config map |
158 | | - configMap := &corev1.ConfigMap{ |
159 | | - ObjectMeta: metav1.ObjectMeta{ |
160 | | - Name: "local-registry-hosting", |
161 | | - Namespace: "kube-public", |
162 | | - }, |
163 | | - Data: map[string]string{"localRegistryHosting.v1": fmt.Sprintf(`host: "localhost:%d"\nhelp: "https://kind.sigs.k8s.io/docs/user/local-registry/"`, registryPort)}, |
164 | | - } |
165 | | - err := ctx.Client().Create(golangContext.TODO(), configMap) |
166 | | - if err != nil { |
167 | | - ctx.Logf("failed to create local-registry-hosting ConfigMap: %s", err.Error()) |
168 | | - } |
169 | | - // connect the docker "kind" network to the registry so the local registry is resolvable |
170 | | - // we don't care about errors here since the connection might already exist |
171 | | - cmd := exec.Command("docker", "network", "connect", "kind", registry) |
172 | | - err = cmd.Start() |
173 | | - if err != nil { |
174 | | - ctx.Logf("failed to exec %#v: %v", cmd.Args, err) |
175 | | - } |
176 | | - } |
177 | | - return deprovision, derivedFieldsErr |
| 71 | + dir, err := ioutil.TempDir("", "kind.") |
| 72 | + if err != nil { |
| 73 | + return nil, fmt.Errorf("failed to create temporary directory: %s", err.Error()) |
| 74 | + } |
| 75 | + defer os.RemoveAll(dir) |
| 76 | + kubeconfigPath := filepath.Join(dir, "kubeconfig") |
| 77 | + |
| 78 | + provider := cluster.NewProvider( |
| 79 | + cluster.ProviderWithLogger(kindLogAdapter{ctx}), |
| 80 | + ) |
| 81 | + name := fmt.Sprintf("kind-%s", rand.String(16)) |
| 82 | + |
| 83 | + // create cluster with configuration: |
| 84 | + // 1. use local docker registry |
| 85 | + // 2. wait for 5 minutes for control plane |
| 86 | + // 3. use explicit kube config path |
| 87 | + registry := "kind-registry" |
| 88 | + // registry := "localhost" |
| 89 | + registryPort := 5000 |
| 90 | + if err := provider.Create( |
| 91 | + name, |
| 92 | + // cluster.CreateWithV1Alpha4Config(&v1alpha4.Cluster{ |
| 93 | + // ContainerdConfigPatches: []string{ |
| 94 | + // fmt.Sprintf(`[plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:%[2]d"] |
| 95 | + //endpoint = ["http://%[1]s:%[2]d"]`, registry, registryPort), |
| 96 | + // }, |
| 97 | + // }), |
| 98 | + cluster.CreateWithWaitForReady(5*time.Minute), |
| 99 | + cluster.CreateWithKubeconfigPath(kubeconfigPath), |
| 100 | + ); err != nil { |
| 101 | + return nil, fmt.Errorf("failed to create kind cluster: %s", err.Error()) |
| 102 | + } |
| 103 | + |
| 104 | + nodes, err := provider.ListNodes(name) |
| 105 | + if err != nil { |
| 106 | + return nil, fmt.Errorf("failed to list kind nodes: %s", err.Error()) |
| 107 | + } |
| 108 | + |
| 109 | + var archives []string |
| 110 | + if images != nil { |
| 111 | + records, err := csv.NewReader(strings.NewReader(*images)).ReadAll() |
| 112 | + if err != nil { |
| 113 | + return nil, fmt.Errorf("error parsing image flag: %s", err.Error()) |
| 114 | + } |
| 115 | + for _, row := range records { |
| 116 | + archives = append(archives, row...) |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + for _, archive := range archives { |
| 121 | + for _, node := range nodes { |
| 122 | + fd, err := os.Open(archive) |
| 123 | + if err != nil { |
| 124 | + return nil, fmt.Errorf("error opening archive %q: %s", archive, err.Error()) |
| 125 | + } |
| 126 | + err = nodeutils.LoadImageArchive(node, fd) |
| 127 | + fd.Close() |
| 128 | + if err != nil { |
| 129 | + return nil, fmt.Errorf("error loading image archive %q to node %q: %s", archive, node, err.Error()) |
| 130 | + } |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + kubeconfig, err := provider.KubeConfig(name, false) |
| 135 | + if err != nil { |
| 136 | + return nil, fmt.Errorf("failed to read kubeconfig: %s", err.Error()) |
| 137 | + } |
| 138 | + restConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeconfig)) |
| 139 | + if err != nil { |
| 140 | + return nil, fmt.Errorf("error loading kubeconfig: %s", err.Error()) |
| 141 | + } |
| 142 | + |
| 143 | + ctx.restConfig = restConfig |
| 144 | + |
| 145 | + var once sync.Once |
| 146 | + deprovision := func() { |
| 147 | + once.Do(func() { |
| 148 | + provider.Delete(name, kubeconfigPath) |
| 149 | + }) |
| 150 | + } |
| 151 | + derivedFieldsErr := setDerivedFields(ctx) |
| 152 | + // make best attempt before we return to: |
| 153 | + // 1) add local registry ConfigMap |
| 154 | + // 2) connect "kind" network to the registry |
| 155 | + if derivedFieldsErr == nil { |
| 156 | + // add config map |
| 157 | + configMap := &corev1.ConfigMap{ |
| 158 | + ObjectMeta: metav1.ObjectMeta{ |
| 159 | + Name: "local-registry-hosting", |
| 160 | + Namespace: "kube-public", |
| 161 | + }, |
| 162 | + Data: map[string]string{"localRegistryHosting.v1": fmt.Sprintf(`host: "localhost:%d"\nhelp: "https://kind.sigs.k8s.io/docs/user/local-registry/"`, registryPort)}, |
| 163 | + } |
| 164 | + err := ctx.Client().Create(golangContext.TODO(), configMap) |
| 165 | + if err != nil { |
| 166 | + ctx.Logf("failed to create local-registry-hosting ConfigMap: %s", err.Error()) |
| 167 | + } |
| 168 | + // connect the docker "kind" network to the registry so the local registry is resolvable |
| 169 | + // we don't care about errors here since the connection might already exist |
| 170 | + cmd := exec.Command("docker", "network", "connect", "kind", registry) |
| 171 | + err = cmd.Start() |
| 172 | + if err != nil { |
| 173 | + ctx.Logf("failed to exec %#v: %v", cmd.Args, err) |
| 174 | + } |
| 175 | + } |
| 176 | + return deprovision, derivedFieldsErr |
178 | 177 | } |
0 commit comments