-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathconfig.go
297 lines (268 loc) · 8.91 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/yaml"
"github.com/meln5674/kink/pkg/docker"
"github.com/meln5674/kink/pkg/helm"
"github.com/meln5674/kink/pkg/kubectl"
)
const (
Kind = "Config"
DefaultClusterName = "kink"
)
var (
APIVersions = []string{"kink.meln5674.github.com/v0"}
)
// RawConfig is the configuration structure as provided by the user
type RawConfig struct {
metav1.TypeMeta
// Helm configures the `helm` commands used to manage the internal cluster
Helm helm.HelmFlags `json:"helm"`
// Kubectl configures the `kubectl` commands used to interact with the external cluster
Kubectl kubectl.KubectlFlags `json:"kubectl"`
// Kubernetes configures the connection to the external cluster
Kubernetes kubectl.RawKubeFlags `json:"kubernetes"`
// Docker configures the `docker` commands used to move images from a local daemon into the internal cluster
Docker docker.DockerFlags `json:"docker"`
// Chart configures the Helm Chart used to deploy the cluster
Chart helm.ChartFlags `json:"chart"`
// Release configures the Helm Release of the Chart that is used to deploy the cluster
Release helm.ClusterReleaseFlags `json:"release"`
}
// Config is the formatted configuration as usable by the module
func (r *RawConfig) Format() Config {
return Config{
Helm: r.Helm,
Kubectl: r.Kubectl,
Kubernetes: r.Kubernetes.Format(),
Docker: r.Docker,
Chart: r.Chart,
Release: r.Release,
}
}
// Config contains all of the necessary configuration to run the KinK CLI
type Config struct {
Helm helm.HelmFlags
// Kubectl configures the `kubectl` commands used to interact with the external cluster
Kubectl kubectl.KubectlFlags
// Kubernetes configures the connection to the external cluster
Kubernetes kubectl.KubeFlags
// Docker configures the `docker` commands used to move images from a local daemon into the internal cluster
Docker docker.DockerFlags
// Chart configures the Helm Chart used to deploy the cluster
Chart helm.ChartFlags
// Release configures the Helm Release of the Chart that is used to deploy the cluster
Release helm.ClusterReleaseFlags
}
// Overrides sets any non-zero fields from another config in this one
func (c *Config) Override(c2 *Config) {
c.Helm.Override(&c2.Helm)
c.Kubectl.Override(&c2.Kubectl)
c.Kubernetes.Override(&c2.Kubernetes)
c.Docker.Override(&c2.Docker)
c.Chart.Override(&c2.Chart)
c.Release.Override(&c2.Release)
}
func (c *RawConfig) LoadFromFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
bytes, err := ioutil.ReadAll(f)
if err != nil {
return err
}
err = yaml.Unmarshal(bytes, c)
if err != nil {
return err
}
validAPIVersion := false
for _, version := range APIVersions {
if c.APIVersion == version {
validAPIVersion = true
break
}
}
if !validAPIVersion {
return fmt.Errorf("Unsupported APIVersion %s, supported: %v", c.APIVersion, APIVersions)
}
if c.Kind != Kind {
return fmt.Errorf("Unsupported Kind %s, must be %s", c.Kind, Kind)
}
return nil
}
// A StringMap is a map of strings to strings, but unmarshals from JSON by parsing a string, then re-parsing that string as JSON
type StringMap map[string]string
// UnmarshalJSON implements json.Unmarshaler
func (s *StringMap) UnmarshalJSON(bytes []byte) (err error) {
var sJSON string
err = json.Unmarshal(bytes, &sJSON)
if err != nil {
return
}
x := map[string]string{}
err = json.Unmarshal([]byte(sJSON), &x)
if err != nil {
return err
}
*s = StringMap(x)
return nil
}
type Int int
// An Int is a int that unmarshals from a JSON string
func (i *Int) UnmarshalJSON(bytes []byte) (err error) {
var sJSON string
err = json.Unmarshal(bytes, &sJSON)
if err != nil {
return
}
x := 0
err = json.Unmarshal([]byte(sJSON), &x)
if err != nil {
return err
}
*i = Int(x)
return nil
}
type Bool bool
// An Int is a int that unmarshals from a JSON string
func (b *Bool) UnmarshalJSON(bytes []byte) (err error) {
var sJSON string
err = json.Unmarshal(bytes, &sJSON)
if err != nil {
return
}
x := false
err = json.Unmarshal([]byte(sJSON), &x)
if err != nil {
return err
}
*b = Bool(x)
return nil
}
type LoadBalancerIngressNodePortClassMapping struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
HttpPort *string `json:"httpPort,omitempty"`
HttpsPort *string `json:"httpsPort,omitempty"`
}
type LoadBalancerIngressHostPortClassMapping struct {
HttpPort *string `json:"httpPort,omitempty"`
HttpsPort *string `json:"httpsPort,omitempty"`
}
type LoadBalancerIngressClassMapping struct {
ClassName string `json:"className"`
Annotations map[string]string `json:"annotations"`
NodePort *LoadBalancerIngressNodePortClassMapping `json:"nodePort,omitempty"`
HostPort *LoadBalancerIngressHostPortClassMapping `json:"hostPort,omitempty"`
}
func (l *LoadBalancerIngressClassMapping) Ports() (*string, *string) {
if l.NodePort != nil {
return l.NodePort.HttpPort, l.NodePort.HttpsPort
}
if l.HostPort != nil {
return l.HostPort.HttpPort, l.HostPort.HttpsPort
}
return nil, nil
}
func (l *LoadBalancerIngressClassMapping) Port() (port string, isHttps bool) {
httpPort, httpsPort := l.Ports()
if httpsPort != nil {
return *httpsPort, true
}
if httpPort != nil {
return *httpPort, false
}
return "", false
}
type LoadBalancerIngressInner struct {
Enabled bool `json:"enabled"`
HostPortTargetFullname string `json:"hostPortTargetFullname"`
ClassMappings map[string]LoadBalancerIngressClassMapping `json:"classMappings"`
}
type LoadBalancerIngress struct {
LoadBalancerIngressInner
}
// UnmarshalJSON implements json.Unmarshaler
func (l *LoadBalancerIngress) UnmarshalJSON(bytes []byte) (err error) {
var sJSON string
err = json.Unmarshal(bytes, &sJSON)
if err != nil {
return
}
x := LoadBalancerIngressInner{}
err = json.Unmarshal([]byte(sJSON), &x)
if err != nil {
return err
}
*l = LoadBalancerIngress{x}
return nil
}
// ReleaseConfig are the values kept in the helm ConfigMap
type ReleaseConfig struct {
Fullname string `json:"fullname"`
Labels StringMap `json:"labels"`
ControlplaneFullname string `json:"controlplane.fullname"`
ControlplanePort Int `json:"controlplane.port"`
ControlplaneHostname string `json:"controlplane.hostname"`
ControlplaneIsNodePort Bool `json:"controlplane.isNodePort"`
ControlplaneLabels StringMap `json:"controlplane.labels"`
ControlplaneSelectorLabels StringMap `json:"controlplane.selectorLabels"`
SelectorLabels StringMap `json:"selectorLabels"`
WorkerFullname string `json:"worker.fullname"`
WorkerLabels StringMap `json:"worker.labels"`
WorkerSelectorLabels StringMap `json:"worker.selectorLabels"`
LoadBalancerFullname string `json:"load-balancer.fullname"`
LoadBalancerLabels StringMap `json:"load-balancer.labels"`
LoadBalancerSelectorLabels StringMap `json:"load-balancer.selectorLabels"`
LoadBalancerServiceType string `json:"load-balancer.service.type"`
LoadBalancerServiceAnnotations StringMap `json:"load-balancer.service.annotations"`
LoadBalancerIngress LoadBalancerIngress `json:"load-balancer.ingress"`
LBManagerFullname string `json:"lb-manager.fullname"`
FileGatewayEnabled Bool `json:"file-gateway.enabled"`
FileGatewayHostname string `json:"file-gateway.hostname"`
FileGatewayContainerPort Int `json:"file-gateway.containerPort"`
RKE2Enabled Bool `json:"rke2.enabled"`
}
func loadMap(path string) (map[string]string, error) {
valueJSON, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
value := make(map[string]string)
err = json.Unmarshal(valueJSON, &value)
if err != nil {
return nil, err
}
return value, nil
}
func (r *ReleaseConfig) LoadFromMount(mount string) error {
f, err := os.Open(filepath.Join(mount, "config.json"))
if err != nil {
return err
}
defer f.Close()
return json.NewDecoder(f).Decode(r)
}
func (r *ReleaseConfig) LoadFromMap(data map[string]interface{}) (err error) {
bytes, err := json.Marshal(data)
if err != nil {
return
}
return json.Unmarshal(bytes, r)
}
func (r *ReleaseConfig) LoadFromConfigMap(cm *corev1.ConfigMap) (ok bool, err error) {
configJSON, ok := cm.Data["config.json"]
if !ok {
return
}
err = json.Unmarshal([]byte(configJSON), r)
return
}