1/* 2Copyright 2014 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 clientcmd 18 19import ( 20 "strconv" 21 "strings" 22 23 "github.com/spf13/pflag" 24 25 clientcmdapi "k8s.io/client-go/tools/clientcmd/api" 26) 27 28// ConfigOverrides holds values that should override whatever information is pulled from the actual Config object. You can't 29// simply use an actual Config object, because Configs hold maps, but overrides are restricted to "at most one" 30type ConfigOverrides struct { 31 AuthInfo clientcmdapi.AuthInfo 32 // ClusterDefaults are applied before the configured cluster info is loaded. 33 ClusterDefaults clientcmdapi.Cluster 34 ClusterInfo clientcmdapi.Cluster 35 Context clientcmdapi.Context 36 CurrentContext string 37 Timeout string 38} 39 40// ConfigOverrideFlags holds the flag names to be used for binding command line flags. Notice that this structure tightly 41// corresponds to ConfigOverrides 42type ConfigOverrideFlags struct { 43 AuthOverrideFlags AuthOverrideFlags 44 ClusterOverrideFlags ClusterOverrideFlags 45 ContextOverrideFlags ContextOverrideFlags 46 CurrentContext FlagInfo 47 Timeout FlagInfo 48} 49 50// AuthOverrideFlags holds the flag names to be used for binding command line flags for AuthInfo objects 51type AuthOverrideFlags struct { 52 ClientCertificate FlagInfo 53 ClientKey FlagInfo 54 Token FlagInfo 55 Impersonate FlagInfo 56 ImpersonateGroups FlagInfo 57 Username FlagInfo 58 Password FlagInfo 59} 60 61// ContextOverrideFlags holds the flag names to be used for binding command line flags for Cluster objects 62type ContextOverrideFlags struct { 63 ClusterName FlagInfo 64 AuthInfoName FlagInfo 65 Namespace FlagInfo 66} 67 68// ClusterOverride holds the flag names to be used for binding command line flags for Cluster objects 69type ClusterOverrideFlags struct { 70 APIServer FlagInfo 71 APIVersion FlagInfo 72 CertificateAuthority FlagInfo 73 InsecureSkipTLSVerify FlagInfo 74 TLSServerName FlagInfo 75} 76 77// FlagInfo contains information about how to register a flag. This struct is useful if you want to provide a way for an extender to 78// get back a set of recommended flag names, descriptions, and defaults, but allow for customization by an extender. This makes for 79// coherent extension, without full prescription 80type FlagInfo struct { 81 // LongName is the long string for a flag. If this is empty, then the flag will not be bound 82 LongName string 83 // ShortName is the single character for a flag. If this is empty, then there will be no short flag 84 ShortName string 85 // Default is the default value for the flag 86 Default string 87 // Description is the description for the flag 88 Description string 89} 90 91// AddSecretAnnotation add secret flag to Annotation. 92func (f FlagInfo) AddSecretAnnotation(flags *pflag.FlagSet) FlagInfo { 93 flags.SetAnnotation(f.LongName, "classified", []string{"true"}) 94 return f 95} 96 97// BindStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered 98func (f FlagInfo) BindStringFlag(flags *pflag.FlagSet, target *string) FlagInfo { 99 // you can't register a flag without a long name 100 if len(f.LongName) > 0 { 101 flags.StringVarP(target, f.LongName, f.ShortName, f.Default, f.Description) 102 } 103 return f 104} 105 106// BindTransformingStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered 107func (f FlagInfo) BindTransformingStringFlag(flags *pflag.FlagSet, target *string, transformer func(string) (string, error)) FlagInfo { 108 // you can't register a flag without a long name 109 if len(f.LongName) > 0 { 110 flags.VarP(newTransformingStringValue(f.Default, target, transformer), f.LongName, f.ShortName, f.Description) 111 } 112 return f 113} 114 115// BindStringSliceFlag binds the flag based on the provided info. If LongName == "", nothing is registered 116func (f FlagInfo) BindStringArrayFlag(flags *pflag.FlagSet, target *[]string) FlagInfo { 117 // you can't register a flag without a long name 118 if len(f.LongName) > 0 { 119 sliceVal := []string{} 120 if len(f.Default) > 0 { 121 sliceVal = []string{f.Default} 122 } 123 flags.StringArrayVarP(target, f.LongName, f.ShortName, sliceVal, f.Description) 124 } 125 return f 126} 127 128// BindBoolFlag binds the flag based on the provided info. If LongName == "", nothing is registered 129func (f FlagInfo) BindBoolFlag(flags *pflag.FlagSet, target *bool) FlagInfo { 130 // you can't register a flag without a long name 131 if len(f.LongName) > 0 { 132 // try to parse Default as a bool. If it fails, assume false 133 boolVal, err := strconv.ParseBool(f.Default) 134 if err != nil { 135 boolVal = false 136 } 137 138 flags.BoolVarP(target, f.LongName, f.ShortName, boolVal, f.Description) 139 } 140 return f 141} 142 143const ( 144 FlagClusterName = "cluster" 145 FlagAuthInfoName = "user" 146 FlagContext = "context" 147 FlagNamespace = "namespace" 148 FlagAPIServer = "server" 149 FlagTLSServerName = "tls-server-name" 150 FlagInsecure = "insecure-skip-tls-verify" 151 FlagCertFile = "client-certificate" 152 FlagKeyFile = "client-key" 153 FlagCAFile = "certificate-authority" 154 FlagEmbedCerts = "embed-certs" 155 FlagBearerToken = "token" 156 FlagImpersonate = "as" 157 FlagImpersonateGroup = "as-group" 158 FlagUsername = "username" 159 FlagPassword = "password" 160 FlagTimeout = "request-timeout" 161) 162 163// RecommendedConfigOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 164func RecommendedConfigOverrideFlags(prefix string) ConfigOverrideFlags { 165 return ConfigOverrideFlags{ 166 AuthOverrideFlags: RecommendedAuthOverrideFlags(prefix), 167 ClusterOverrideFlags: RecommendedClusterOverrideFlags(prefix), 168 ContextOverrideFlags: RecommendedContextOverrideFlags(prefix), 169 170 CurrentContext: FlagInfo{prefix + FlagContext, "", "", "The name of the kubeconfig context to use"}, 171 Timeout: FlagInfo{prefix + FlagTimeout, "", "0", "The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests."}, 172 } 173} 174 175// RecommendedAuthOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 176func RecommendedAuthOverrideFlags(prefix string) AuthOverrideFlags { 177 return AuthOverrideFlags{ 178 ClientCertificate: FlagInfo{prefix + FlagCertFile, "", "", "Path to a client certificate file for TLS"}, 179 ClientKey: FlagInfo{prefix + FlagKeyFile, "", "", "Path to a client key file for TLS"}, 180 Token: FlagInfo{prefix + FlagBearerToken, "", "", "Bearer token for authentication to the API server"}, 181 Impersonate: FlagInfo{prefix + FlagImpersonate, "", "", "Username to impersonate for the operation"}, 182 ImpersonateGroups: FlagInfo{prefix + FlagImpersonateGroup, "", "", "Group to impersonate for the operation, this flag can be repeated to specify multiple groups."}, 183 Username: FlagInfo{prefix + FlagUsername, "", "", "Username for basic authentication to the API server"}, 184 Password: FlagInfo{prefix + FlagPassword, "", "", "Password for basic authentication to the API server"}, 185 } 186} 187 188// RecommendedClusterOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 189func RecommendedClusterOverrideFlags(prefix string) ClusterOverrideFlags { 190 return ClusterOverrideFlags{ 191 APIServer: FlagInfo{prefix + FlagAPIServer, "", "", "The address and port of the Kubernetes API server"}, 192 CertificateAuthority: FlagInfo{prefix + FlagCAFile, "", "", "Path to a cert file for the certificate authority"}, 193 InsecureSkipTLSVerify: FlagInfo{prefix + FlagInsecure, "", "false", "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure"}, 194 TLSServerName: FlagInfo{prefix + FlagTLSServerName, "", "", "If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used."}, 195 } 196} 197 198// RecommendedContextOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 199func RecommendedContextOverrideFlags(prefix string) ContextOverrideFlags { 200 return ContextOverrideFlags{ 201 ClusterName: FlagInfo{prefix + FlagClusterName, "", "", "The name of the kubeconfig cluster to use"}, 202 AuthInfoName: FlagInfo{prefix + FlagAuthInfoName, "", "", "The name of the kubeconfig user to use"}, 203 Namespace: FlagInfo{prefix + FlagNamespace, "n", "", "If present, the namespace scope for this CLI request"}, 204 } 205} 206 207// BindOverrideFlags is a convenience method to bind the specified flags to their associated variables 208func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) { 209 BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags) 210 BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags) 211 BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags) 212 flagNames.CurrentContext.BindStringFlag(flags, &overrides.CurrentContext) 213 flagNames.Timeout.BindStringFlag(flags, &overrides.Timeout) 214} 215 216// BindAuthInfoFlags is a convenience method to bind the specified flags to their associated variables 217func BindAuthInfoFlags(authInfo *clientcmdapi.AuthInfo, flags *pflag.FlagSet, flagNames AuthOverrideFlags) { 218 flagNames.ClientCertificate.BindStringFlag(flags, &authInfo.ClientCertificate).AddSecretAnnotation(flags) 219 flagNames.ClientKey.BindStringFlag(flags, &authInfo.ClientKey).AddSecretAnnotation(flags) 220 flagNames.Token.BindStringFlag(flags, &authInfo.Token).AddSecretAnnotation(flags) 221 flagNames.Impersonate.BindStringFlag(flags, &authInfo.Impersonate).AddSecretAnnotation(flags) 222 flagNames.ImpersonateGroups.BindStringArrayFlag(flags, &authInfo.ImpersonateGroups).AddSecretAnnotation(flags) 223 flagNames.Username.BindStringFlag(flags, &authInfo.Username).AddSecretAnnotation(flags) 224 flagNames.Password.BindStringFlag(flags, &authInfo.Password).AddSecretAnnotation(flags) 225} 226 227// BindClusterFlags is a convenience method to bind the specified flags to their associated variables 228func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, flagNames ClusterOverrideFlags) { 229 flagNames.APIServer.BindStringFlag(flags, &clusterInfo.Server) 230 flagNames.CertificateAuthority.BindStringFlag(flags, &clusterInfo.CertificateAuthority) 231 flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify) 232 flagNames.TLSServerName.BindStringFlag(flags, &clusterInfo.TLSServerName) 233} 234 235// BindFlags is a convenience method to bind the specified flags to their associated variables 236func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) { 237 flagNames.ClusterName.BindStringFlag(flags, &contextInfo.Cluster) 238 flagNames.AuthInfoName.BindStringFlag(flags, &contextInfo.AuthInfo) 239 flagNames.Namespace.BindTransformingStringFlag(flags, &contextInfo.Namespace, RemoveNamespacesPrefix) 240} 241 242// RemoveNamespacesPrefix is a transformer that strips "ns/", "namespace/" and "namespaces/" prefixes case-insensitively 243func RemoveNamespacesPrefix(value string) (string, error) { 244 for _, prefix := range []string{"namespaces/", "namespace/", "ns/"} { 245 if len(value) > len(prefix) && strings.EqualFold(value[0:len(prefix)], prefix) { 246 value = value[len(prefix):] 247 break 248 } 249 } 250 return value, nil 251} 252