-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
190 lines (151 loc) · 5.19 KB
/
main.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
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
)
type KubectlConfig struct {
Kind string `yaml:"kind"`
ApiVersion string `yaml:"apiVersion"`
CurrentContext string `yaml:"current-context"`
Clusters []*KubectlClusterWithName `yaml:"clusters"`
Contexts []*KubectlContextWithName `yaml:"contexts"`
Users []*KubectlUserWithName `yaml:"users"`
}
type KubectlUser struct {
ClientCertificateData string `yaml:"client-certificate-data,omitempty"`
ClientKeyData string `yaml:"client-key-data,omitempty"`
Password string `yaml:"password,omitempty"`
Username string `yaml:"username,omitempty"`
Token string `yaml:"token,omitempty"`
}
type KubectlUserWithName struct {
Name string `yaml:"name"`
User KubectlUser `yaml:"user"`
}
type KubectlContext struct {
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
}
type KubectlContextWithName struct {
Name string `yaml:"name"`
Context KubectlContext `yaml:"context"`
}
type KubectlCluster struct {
Server string `yaml:"server"`
CertificateAuthorityData string `yaml:"certificate-authority-data,omitempty"`
}
type KubectlClusterWithName struct {
Name string `yaml:"name"`
Cluster KubectlCluster `yaml:"cluster"`
}
const KUBECONFIG_ENV = "KUBECONFIG"
const KUBECONFIG_ENV_KEY = "$KUBECONFIG"
const KUBECONFIG_DEFAULT_PATH = "~/.kube/config"
func ParseKubeConfig(path string) (*KubectlConfig, error) {
file, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var kubeConfig KubectlConfig
err = yaml.Unmarshal(file, &kubeConfig)
if err != nil {
return nil, err
}
return &kubeConfig, nil
}
func validate(toBeAppend KubectlConfig, kubectlConfig KubectlConfig, name string) error {
if len(toBeAppend.Clusters) != 1 {
return errors.New("only one cluster can be merged into original kubeconfig")
}
if len(toBeAppend.Users) != 1 {
return errors.New("only one user can be merged into original kubeconfig")
}
if len(toBeAppend.Contexts) != 1 {
return errors.New("only one context can be merged into original kubeconfig")
}
for _, v := range kubectlConfig.Clusters {
if strings.EqualFold(v.Name, name) {
return fmt.Errorf("a cluster entry with %s already exists in kubeconfig, merge failed", name)
}
}
for _, v := range kubectlConfig.Contexts {
if strings.EqualFold(v.Name, name) {
return fmt.Errorf("a context entry with %s already exists in kubeconfig, merge failed", name)
}
}
for _, v := range kubectlConfig.Users {
if strings.EqualFold(v.Name, name) {
return fmt.Errorf("a user entry with %s already exists in kubeconfig, merge failed", name)
}
}
return nil
}
func Merge(kubeConfig KubectlConfig, toBeAppend KubectlConfig, name, toBeAppendFileName string) (*KubectlConfig, error) {
var newName = toBeAppendFileName
if len(name) > 0 {
newName = name
}
var err = validate(toBeAppend, kubeConfig, toBeAppendFileName)
if err != nil {
return nil, err
}
toBeAppend.Clusters[0].Name = newName
toBeAppend.Users[0].Name = newName
toBeAppend.Contexts[0].Name = newName
toBeAppend.Contexts[0].Context.Cluster = newName
toBeAppend.Contexts[0].Context.User = newName
kubeConfig.Clusters = append(kubeConfig.Clusters, toBeAppend.Clusters[0])
kubeConfig.Users = append(kubeConfig.Users, toBeAppend.Users[0])
kubeConfig.Contexts = append(kubeConfig.Contexts, toBeAppend.Contexts[0])
fmt.Printf("Cluster, context and user will be added with '%s' name\n", newName)
return &kubeConfig, nil
}
func getKubeConfigPath(passedValue string) string {
//--kubeconfig is not passed
kubeConfigPath := strings.ReplaceAll(passedValue, " ", "")
if len(kubeConfigPath) == 0 {
log.Printf("--kubeconfig was not passed. Looking the %s environment variable\n", KUBECONFIG_ENV)
// case1: env variable exists
kubeConfigPath = os.Getenv(KUBECONFIG_ENV)
// case2: fallback to default path
if len(kubeConfigPath) == 0 {
log.Printf("%s env variable does not exist. Default %s path will be used\n", KUBECONFIG_ENV, KUBECONFIG_DEFAULT_PATH)
}
}
return kubeConfigPath
}
func main() {
kubeConfigPtr := flag.String("kubeconfig", "", fmt.Sprintf("path to the kubeconfig file (defaults '%s' or '%s')", KUBECONFIG_ENV_KEY, KUBECONFIG_DEFAULT_PATH))
filePtr := flag.String("file", "", "path to the yaml file that to be append into kubeconfig")
namePtr := flag.String("name", "", "Replaces the name of context, user and cluster (default file name of --file argument)")
flag.Parse()
var kubeConfigPath = getKubeConfigPath(*kubeConfigPtr)
kubeConfig, err := ParseKubeConfig(kubeConfigPath)
if err != nil {
log.Panic(err)
}
toBeAppend, err := ParseKubeConfig(*filePtr)
if err != nil {
log.Panic(err)
}
var fileName = filepath.Base(*filePtr)
result, err := Merge(*kubeConfig, *toBeAppend, *namePtr, fileName[:len(fileName)-len(filepath.Ext(fileName))])
if err != nil {
log.Panic(err)
}
data, err := yaml.Marshal(result)
if err != nil {
log.Panic(err)
}
err = os.WriteFile(kubeConfigPath, data, 0644)
if err != nil {
log.Panic(err)
}
fmt.Printf("%s was modified successfully\n", kubeConfigPath)
}