4
4
"fmt"
5
5
"os"
6
6
"path"
7
+ "path/filepath"
7
8
"strings"
8
9
9
10
"os/exec"
@@ -17,18 +18,25 @@ import (
17
18
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
18
19
)
19
20
20
- // DefaultPath defines the default path
21
- var DefaultPath = clientcmd .RecommendedHomeFile
22
-
23
21
const (
24
22
// AWSIAMAuthenticator defines the name of the AWS IAM authenticator
25
23
AWSIAMAuthenticator = "aws-iam-authenticator"
26
24
// HeptioAuthenticatorAWS defines the old name of AWS IAM authenticator
27
25
HeptioAuthenticatorAWS = "heptio-authenticator-aws"
28
26
// AWSEKSAuthenticator defines the recently added `aws eks get-token` command
29
27
AWSEKSAuthenticator = "aws"
28
+ // Shadowing the default kubeconfig path environment variable
29
+ RecommendedConfigPathEnvVar = clientcmd .RecommendedConfigPathEnvVar
30
30
)
31
31
32
+ // DefaultPath defines the default path
33
+ func DefaultPath () string {
34
+ if env := os .Getenv (RecommendedConfigPathEnvVar ); len (env ) > 0 {
35
+ return env
36
+ }
37
+ return clientcmd .RecommendedHomeFile
38
+ }
39
+
32
40
// AuthenticatorCommands returns all of authenticator commands
33
41
func AuthenticatorCommands () []string {
34
42
return []string {
@@ -38,22 +46,23 @@ func AuthenticatorCommands() []string {
38
46
}
39
47
}
40
48
41
- // New creates Kubernetes client configuration for a given username
42
- // if certificateAuthorityPath is not empty, it is used instead of
43
- // embedded certificate-authority-data
44
- func New ( spec * api. ClusterConfig , username , certificateAuthorityPath string ) ( * clientcmdapi. Config , string , string ) {
45
- clusterName := spec . Metadata . String ()
46
- contextName := fmt . Sprintf ( "%s@%s" , username , clusterName )
49
+ // ConfigBuilder can create a client-go clientcmd Config
50
+ type ConfigBuilder struct {
51
+ cluster clientcmdapi. Cluster
52
+ clusterName string
53
+ username string
54
+ }
47
55
48
- c := & clientcmdapi.Config {
56
+ // Build creates the Config with the ConfigBuilder settings
57
+ func (cb * ConfigBuilder ) Build () * clientcmdapi.Config {
58
+ contextName := fmt .Sprintf ("%s@%s" , cb .username , cb .clusterName )
59
+ return & clientcmdapi.Config {
49
60
Clusters : map [string ]* clientcmdapi.Cluster {
50
- clusterName : {
51
- Server : spec .Status .Endpoint ,
52
- },
61
+ cb .clusterName : & cb .cluster ,
53
62
},
54
63
Contexts : map [string ]* clientcmdapi.Context {
55
64
contextName : {
56
- Cluster : clusterName ,
65
+ Cluster : cb . clusterName ,
57
66
AuthInfo : contextName ,
58
67
},
59
68
},
@@ -62,19 +71,32 @@ func New(spec *api.ClusterConfig, username, certificateAuthorityPath string) (*c
62
71
},
63
72
CurrentContext : contextName ,
64
73
}
74
+ }
65
75
66
- if certificateAuthorityPath == "" {
67
- c .Clusters [clusterName ].CertificateAuthorityData = spec .Status .CertificateAuthorityData
68
- } else {
69
- c .Clusters [clusterName ].CertificateAuthority = certificateAuthorityPath
76
+ // NewBuilder returns a minimal ConfigBuilder
77
+ func NewBuilder (metadata * api.ClusterMeta , status * api.ClusterStatus , username string ) * ConfigBuilder {
78
+ cluster := clientcmdapi.Cluster {
79
+ Server : status .Endpoint ,
80
+ CertificateAuthorityData : status .CertificateAuthorityData ,
70
81
}
82
+ return & ConfigBuilder {
83
+ cluster : cluster ,
84
+ clusterName : metadata .String (),
85
+ username : username ,
86
+ }
87
+ }
71
88
72
- return c , clusterName , contextName
89
+ // UseCertificateAuthorityFile sets the config to use CA from file instead
90
+ // of the CA as retrieved from EKS
91
+ func (cb * ConfigBuilder ) UseCertificateAuthorityFile (path string ) * ConfigBuilder {
92
+ cb .cluster .CertificateAuthority = path
93
+ cb .cluster .CertificateAuthorityData = []byte {}
94
+ return cb
73
95
}
74
96
75
97
// NewForKubectl creates configuration for kubectl using a suitable authenticator
76
98
func NewForKubectl (spec * api.ClusterConfig , username , roleARN , profile string ) * clientcmdapi.Config {
77
- config , _ , _ := New (spec , username , "" )
99
+ config := NewBuilder (spec . Metadata , spec . Status , username ). Build ( )
78
100
authenticator , found := LookupAuthenticator ()
79
101
if ! found {
80
102
// fall back to aws-iam-authenticator
@@ -139,21 +161,40 @@ func AppendAuthenticator(config *clientcmdapi.Config, spec *api.ClusterConfig, a
139
161
}
140
162
}
141
163
164
+ // ensureDirectory should probably be handled in flock
165
+ func ensureDirectory (filePath string ) error {
166
+ dir := filepath .Dir (filePath )
167
+ if _ , err := os .Stat (dir ); os .IsNotExist (err ) {
168
+ if err = os .MkdirAll (dir , 0755 ); err != nil {
169
+ return err
170
+ }
171
+ }
172
+ return nil
173
+ }
174
+
142
175
func lockConfigFile (filePath string ) error {
176
+ // Make sure the directory exists, otherwise flock fails
177
+ if err := ensureDirectory (filePath ); err != nil {
178
+ return err
179
+ }
143
180
flock := flock .New (filePath )
144
181
err := flock .Lock ()
145
182
if err != nil {
146
- return errors .Wrap (err , "flock: failed to obtain exclusive lock existing kubeconfig file" )
183
+ return errors .Wrap (err , "flock: failed to obtain exclusive lock on kubeconfig file" )
147
184
}
148
185
149
186
return nil
150
187
}
151
188
152
189
func unlockConfigFile (filePath string ) error {
190
+ // Make sure the directory exists, otherwise flock fails
191
+ if err := ensureDirectory (filePath ); err != nil {
192
+ return err
193
+ }
153
194
flock := flock .New (filePath )
154
195
err := flock .Unlock ()
155
196
if err != nil {
156
- return errors .Wrap (err , "flock: failed to release exclusive lock on existing kubeconfig file" )
197
+ return errors .Wrap (err , "flock: failed to release exclusive lock on kubeconfig file" )
157
198
}
158
199
159
200
return nil
@@ -199,7 +240,7 @@ func Write(path string, newConfig clientcmdapi.Config, setContext bool) (string,
199
240
200
241
func getConfigAccess (explicitPath string ) clientcmd.ConfigAccess {
201
242
pathOptions := clientcmd .NewDefaultPathOptions ()
202
- if explicitPath != "" && explicitPath != DefaultPath {
243
+ if explicitPath != "" && explicitPath != DefaultPath () {
203
244
pathOptions .LoadingRules .ExplicitPath = explicitPath
204
245
}
205
246
@@ -275,7 +316,7 @@ func MaybeDeleteConfig(meta *api.ClusterMeta) {
275
316
return
276
317
}
277
318
278
- configAccess := getConfigAccess (DefaultPath )
319
+ configAccess := getConfigAccess (DefaultPath () )
279
320
defaultFilename := configAccess .GetDefaultFilename ()
280
321
err := lockConfigFile (defaultFilename )
281
322
if err != nil {
@@ -290,7 +331,7 @@ func MaybeDeleteConfig(meta *api.ClusterMeta) {
290
331
291
332
config , err := configAccess .GetStartingConfig ()
292
333
if err != nil {
293
- logger .Debug ("error reading kubeconfig file %q: %s" , DefaultPath , err .Error ())
334
+ logger .Debug ("error reading kubeconfig file %q: %s" , DefaultPath () , err .Error ())
294
335
return
295
336
}
296
337
@@ -299,7 +340,7 @@ func MaybeDeleteConfig(meta *api.ClusterMeta) {
299
340
}
300
341
301
342
if err := clientcmd .ModifyConfig (configAccess , * config , true ); err != nil {
302
- logger .Debug ("ignoring error while failing to update config file %q: %s" , DefaultPath , err .Error ())
343
+ logger .Debug ("ignoring error while failing to update config file %q: %s" , DefaultPath () , err .Error ())
303
344
} else {
304
345
logger .Success ("kubeconfig has been updated" )
305
346
}
0 commit comments