blob: 43e26487cbe7c5f8c06db3e7520e2bd9b0a78943 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package api
18
19import (
20 "encoding/base64"
21 "errors"
22 "fmt"
23 "io/ioutil"
24 "os"
25 "path"
26 "path/filepath"
27)
28
29func init() {
30 sDec, _ := base64.StdEncoding.DecodeString("REDACTED+")
31 redactedBytes = []byte(string(sDec))
32}
33
34// IsConfigEmpty returns true if the config is empty.
35func IsConfigEmpty(config *Config) bool {
36 return len(config.AuthInfos) == 0 && len(config.Clusters) == 0 && len(config.Contexts) == 0 &&
37 len(config.CurrentContext) == 0 &&
38 len(config.Preferences.Extensions) == 0 && !config.Preferences.Colors &&
39 len(config.Extensions) == 0
40}
41
42// MinifyConfig read the current context and uses that to keep only the relevant pieces of config
43// This is useful for making secrets based on kubeconfig files
44func MinifyConfig(config *Config) error {
45 if len(config.CurrentContext) == 0 {
46 return errors.New("current-context must exist in order to minify")
47 }
48
49 currContext, exists := config.Contexts[config.CurrentContext]
50 if !exists {
51 return fmt.Errorf("cannot locate context %v", config.CurrentContext)
52 }
53
54 newContexts := map[string]*Context{}
55 newContexts[config.CurrentContext] = currContext
56
57 newClusters := map[string]*Cluster{}
58 if len(currContext.Cluster) > 0 {
59 if _, exists := config.Clusters[currContext.Cluster]; !exists {
60 return fmt.Errorf("cannot locate cluster %v", currContext.Cluster)
61 }
62
63 newClusters[currContext.Cluster] = config.Clusters[currContext.Cluster]
64 }
65
66 newAuthInfos := map[string]*AuthInfo{}
67 if len(currContext.AuthInfo) > 0 {
68 if _, exists := config.AuthInfos[currContext.AuthInfo]; !exists {
69 return fmt.Errorf("cannot locate user %v", currContext.AuthInfo)
70 }
71
72 newAuthInfos[currContext.AuthInfo] = config.AuthInfos[currContext.AuthInfo]
73 }
74
75 config.AuthInfos = newAuthInfos
76 config.Clusters = newClusters
77 config.Contexts = newContexts
78
79 return nil
80}
81
82var redactedBytes []byte
83
84// Flatten redacts raw data entries from the config object for a human-readable view.
85func ShortenConfig(config *Config) {
86 // trick json encoder into printing a human readable string in the raw data
87 // by base64 decoding what we want to print. Relies on implementation of
88 // http://golang.org/pkg/encoding/json/#Marshal using base64 to encode []byte
89 for key, authInfo := range config.AuthInfos {
90 if len(authInfo.ClientKeyData) > 0 {
91 authInfo.ClientKeyData = redactedBytes
92 }
93 if len(authInfo.ClientCertificateData) > 0 {
94 authInfo.ClientCertificateData = redactedBytes
95 }
96 config.AuthInfos[key] = authInfo
97 }
98 for key, cluster := range config.Clusters {
99 if len(cluster.CertificateAuthorityData) > 0 {
100 cluster.CertificateAuthorityData = redactedBytes
101 }
102 config.Clusters[key] = cluster
103 }
104}
105
106// Flatten changes the config object into a self contained config (useful for making secrets)
107func FlattenConfig(config *Config) error {
108 for key, authInfo := range config.AuthInfos {
109 baseDir, err := MakeAbs(path.Dir(authInfo.LocationOfOrigin), "")
110 if err != nil {
111 return err
112 }
113
114 if err := FlattenContent(&authInfo.ClientCertificate, &authInfo.ClientCertificateData, baseDir); err != nil {
115 return err
116 }
117 if err := FlattenContent(&authInfo.ClientKey, &authInfo.ClientKeyData, baseDir); err != nil {
118 return err
119 }
120
121 config.AuthInfos[key] = authInfo
122 }
123 for key, cluster := range config.Clusters {
124 baseDir, err := MakeAbs(path.Dir(cluster.LocationOfOrigin), "")
125 if err != nil {
126 return err
127 }
128
129 if err := FlattenContent(&cluster.CertificateAuthority, &cluster.CertificateAuthorityData, baseDir); err != nil {
130 return err
131 }
132
133 config.Clusters[key] = cluster
134 }
135
136 return nil
137}
138
139func FlattenContent(path *string, contents *[]byte, baseDir string) error {
140 if len(*path) != 0 {
141 if len(*contents) > 0 {
142 return errors.New("cannot have values for both path and contents")
143 }
144
145 var err error
146 absPath := ResolvePath(*path, baseDir)
147 *contents, err = ioutil.ReadFile(absPath)
148 if err != nil {
149 return err
150 }
151
152 *path = ""
153 }
154
155 return nil
156}
157
158// ResolvePath returns the path as an absolute paths, relative to the given base directory
159func ResolvePath(path string, base string) string {
160 // Don't resolve empty paths
161 if len(path) > 0 {
162 // Don't resolve absolute paths
163 if !filepath.IsAbs(path) {
164 return filepath.Join(base, path)
165 }
166 }
167
168 return path
169}
170
171func MakeAbs(path, base string) (string, error) {
172 if filepath.IsAbs(path) {
173 return path, nil
174 }
175 if len(base) == 0 {
176 cwd, err := os.Getwd()
177 if err != nil {
178 return "", err
179 }
180 base = cwd
181 }
182 return filepath.Join(base, path), nil
183}