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} 75 76// FlagInfo contains information about how to register a flag. This struct is useful if you want to provide a way for an extender to 77// get back a set of recommended flag names, descriptions, and defaults, but allow for customization by an extender. This makes for 78// coherent extension, without full prescription 79type FlagInfo struct { 80 // LongName is the long string for a flag. If this is empty, then the flag will not be bound 81 LongName string 82 // ShortName is the single character for a flag. If this is empty, then there will be no short flag 83 ShortName string 84 // Default is the default value for the flag 85 Default string 86 // Description is the description for the flag 87 Description string 88} 89 90// AddSecretAnnotation add secret flag to Annotation. 91func (f FlagInfo) AddSecretAnnotation(flags *pflag.FlagSet) FlagInfo { 92 flags.SetAnnotation(f.LongName, "classified", []string{"true"}) 93 return f 94} 95 96// BindStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered 97func (f FlagInfo) BindStringFlag(flags *pflag.FlagSet, target *string) FlagInfo { 98 // you can't register a flag without a long name 99 if len(f.LongName) > 0 { 100 flags.StringVarP(target, f.LongName, f.ShortName, f.Default, f.Description) 101 } 102 return f 103} 104 105// BindTransformingStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered 106func (f FlagInfo) BindTransformingStringFlag(flags *pflag.FlagSet, target *string, transformer func(string) (string, error)) FlagInfo { 107 // you can't register a flag without a long name 108 if len(f.LongName) > 0 { 109 flags.VarP(newTransformingStringValue(f.Default, target, transformer), f.LongName, f.ShortName, f.Description) 110 } 111 return f 112} 113 114// BindStringSliceFlag binds the flag based on the provided info. If LongName == "", nothing is registered 115func (f FlagInfo) BindStringArrayFlag(flags *pflag.FlagSet, target *[]string) FlagInfo { 116 // you can't register a flag without a long name 117 if len(f.LongName) > 0 { 118 sliceVal := []string{} 119 if len(f.Default) > 0 { 120 sliceVal = []string{f.Default} 121 } 122 flags.StringArrayVarP(target, f.LongName, f.ShortName, sliceVal, f.Description) 123 } 124 return f 125} 126 127// BindBoolFlag binds the flag based on the provided info. If LongName == "", nothing is registered 128func (f FlagInfo) BindBoolFlag(flags *pflag.FlagSet, target *bool) FlagInfo { 129 // you can't register a flag without a long name 130 if len(f.LongName) > 0 { 131 // try to parse Default as a bool. If it fails, assume false 132 boolVal, err := strconv.ParseBool(f.Default) 133 if err != nil { 134 boolVal = false 135 } 136 137 flags.BoolVarP(target, f.LongName, f.ShortName, boolVal, f.Description) 138 } 139 return f 140} 141 142const ( 143 FlagClusterName = "cluster" 144 FlagAuthInfoName = "user" 145 FlagContext = "context" 146 FlagNamespace = "namespace" 147 FlagAPIServer = "server" 148 FlagInsecure = "insecure-skip-tls-verify" 149 FlagCertFile = "client-certificate" 150 FlagKeyFile = "client-key" 151 FlagCAFile = "certificate-authority" 152 FlagEmbedCerts = "embed-certs" 153 FlagBearerToken = "token" 154 FlagImpersonate = "as" 155 FlagImpersonateGroup = "as-group" 156 FlagUsername = "username" 157 FlagPassword = "password" 158 FlagTimeout = "request-timeout" 159) 160 161// RecommendedConfigOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 162func RecommendedConfigOverrideFlags(prefix string) ConfigOverrideFlags { 163 return ConfigOverrideFlags{ 164 AuthOverrideFlags: RecommendedAuthOverrideFlags(prefix), 165 ClusterOverrideFlags: RecommendedClusterOverrideFlags(prefix), 166 ContextOverrideFlags: RecommendedContextOverrideFlags(prefix), 167 168 CurrentContext: FlagInfo{prefix + FlagContext, "", "", "The name of the kubeconfig context to use"}, 169 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."}, 170 } 171} 172 173// RecommendedAuthOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 174func RecommendedAuthOverrideFlags(prefix string) AuthOverrideFlags { 175 return AuthOverrideFlags{ 176 ClientCertificate: FlagInfo{prefix + FlagCertFile, "", "", "Path to a client certificate file for TLS"}, 177 ClientKey: FlagInfo{prefix + FlagKeyFile, "", "", "Path to a client key file for TLS"}, 178 Token: FlagInfo{prefix + FlagBearerToken, "", "", "Bearer token for authentication to the API server"}, 179 Impersonate: FlagInfo{prefix + FlagImpersonate, "", "", "Username to impersonate for the operation"}, 180 ImpersonateGroups: FlagInfo{prefix + FlagImpersonateGroup, "", "", "Group to impersonate for the operation, this flag can be repeated to specify multiple groups."}, 181 Username: FlagInfo{prefix + FlagUsername, "", "", "Username for basic authentication to the API server"}, 182 Password: FlagInfo{prefix + FlagPassword, "", "", "Password for basic authentication to the API server"}, 183 } 184} 185 186// RecommendedClusterOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 187func RecommendedClusterOverrideFlags(prefix string) ClusterOverrideFlags { 188 return ClusterOverrideFlags{ 189 APIServer: FlagInfo{prefix + FlagAPIServer, "", "", "The address and port of the Kubernetes API server"}, 190 CertificateAuthority: FlagInfo{prefix + FlagCAFile, "", "", "Path to a cert file for the certificate authority"}, 191 InsecureSkipTLSVerify: FlagInfo{prefix + FlagInsecure, "", "false", "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure"}, 192 } 193} 194 195// RecommendedContextOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing 196func RecommendedContextOverrideFlags(prefix string) ContextOverrideFlags { 197 return ContextOverrideFlags{ 198 ClusterName: FlagInfo{prefix + FlagClusterName, "", "", "The name of the kubeconfig cluster to use"}, 199 AuthInfoName: FlagInfo{prefix + FlagAuthInfoName, "", "", "The name of the kubeconfig user to use"}, 200 Namespace: FlagInfo{prefix + FlagNamespace, "n", "", "If present, the namespace scope for this CLI request"}, 201 } 202} 203 204// BindOverrideFlags is a convenience method to bind the specified flags to their associated variables 205func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) { 206 BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags) 207 BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags) 208 BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags) 209 flagNames.CurrentContext.BindStringFlag(flags, &overrides.CurrentContext) 210 flagNames.Timeout.BindStringFlag(flags, &overrides.Timeout) 211} 212 213// BindAuthInfoFlags is a convenience method to bind the specified flags to their associated variables 214func BindAuthInfoFlags(authInfo *clientcmdapi.AuthInfo, flags *pflag.FlagSet, flagNames AuthOverrideFlags) { 215 flagNames.ClientCertificate.BindStringFlag(flags, &authInfo.ClientCertificate).AddSecretAnnotation(flags) 216 flagNames.ClientKey.BindStringFlag(flags, &authInfo.ClientKey).AddSecretAnnotation(flags) 217 flagNames.Token.BindStringFlag(flags, &authInfo.Token).AddSecretAnnotation(flags) 218 flagNames.Impersonate.BindStringFlag(flags, &authInfo.Impersonate).AddSecretAnnotation(flags) 219 flagNames.ImpersonateGroups.BindStringArrayFlag(flags, &authInfo.ImpersonateGroups).AddSecretAnnotation(flags) 220 flagNames.Username.BindStringFlag(flags, &authInfo.Username).AddSecretAnnotation(flags) 221 flagNames.Password.BindStringFlag(flags, &authInfo.Password).AddSecretAnnotation(flags) 222} 223 224// BindClusterFlags is a convenience method to bind the specified flags to their associated variables 225func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, flagNames ClusterOverrideFlags) { 226 flagNames.APIServer.BindStringFlag(flags, &clusterInfo.Server) 227 flagNames.CertificateAuthority.BindStringFlag(flags, &clusterInfo.CertificateAuthority) 228 flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify) 229} 230 231// BindFlags is a convenience method to bind the specified flags to their associated variables 232func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) { 233 flagNames.ClusterName.BindStringFlag(flags, &contextInfo.Cluster) 234 flagNames.AuthInfoName.BindStringFlag(flags, &contextInfo.AuthInfo) 235 flagNames.Namespace.BindTransformingStringFlag(flags, &contextInfo.Namespace, RemoveNamespacesPrefix) 236} 237 238// RemoveNamespacesPrefix is a transformer that strips "ns/", "namespace/" and "namespaces/" prefixes case-insensitively 239func RemoveNamespacesPrefix(value string) (string, error) { 240 for _, prefix := range []string{"namespaces/", "namespace/", "ns/"} { 241 if len(value) > len(prefix) && strings.EqualFold(value[0:len(prefix)], prefix) { 242 value = value[len(prefix):] 243 break 244 } 245 } 246 return value, nil 247} 248