wire config flags through factory

pull/8/head
juanvallejo 2018-04-24 19:47:03 -04:00
parent 46e827a8a5
commit 3ca222b2d9
25 changed files with 325 additions and 208 deletions

View File

@ -17,7 +17,6 @@ go_library(
importpath = "k8s.io/kubernetes/cmd/clicheck", importpath = "k8s.io/kubernetes/cmd/clicheck",
deps = [ deps = [
"//pkg/kubectl/cmd:go_default_library", "//pkg/kubectl/cmd:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/sanity:go_default_library", "//pkg/kubectl/cmd/util/sanity:go_default_library",
], ],
) )

View File

@ -22,7 +22,6 @@ import (
"os" "os"
"k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
cmdsanity "k8s.io/kubernetes/pkg/kubectl/cmd/util/sanity" cmdsanity "k8s.io/kubernetes/pkg/kubectl/cmd/util/sanity"
) )
@ -33,7 +32,7 @@ var (
func main() { func main() {
var errorCount int var errorCount int
kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) kubectl := cmd.NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard)
errors := cmdsanity.RunCmdChecks(kubectl, cmdsanity.AllCmdChecks, []string{}) errors := cmdsanity.RunCmdChecks(kubectl, cmdsanity.AllCmdChecks, []string{})
for _, err := range errors { for _, err := range errors {
errorCount++ errorCount++

View File

@ -18,7 +18,6 @@ go_library(
deps = [ deps = [
"//cmd/genutils:go_default_library", "//cmd/genutils:go_default_library",
"//pkg/kubectl/cmd:go_default_library", "//pkg/kubectl/cmd:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//vendor/github.com/spf13/cobra/doc:go_default_library", "//vendor/github.com/spf13/cobra/doc:go_default_library",
], ],
) )

View File

@ -24,7 +24,6 @@ import (
"github.com/spf13/cobra/doc" "github.com/spf13/cobra/doc"
"k8s.io/kubernetes/cmd/genutils" "k8s.io/kubernetes/cmd/genutils"
"k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
func main() { func main() {
@ -47,6 +46,6 @@ func main() {
// regardless of where we run. // regardless of where we run.
os.Setenv("HOME", "/home/username") os.Setenv("HOME", "/home/username")
// TODO os.Stdin should really be something like ioutil.Discard, but a Reader // TODO os.Stdin should really be something like ioutil.Discard, but a Reader
kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) kubectl := cmd.NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard)
doc.GenMarkdownTree(kubectl, outDir) doc.GenMarkdownTree(kubectl, outDir)
} }

View File

@ -25,7 +25,6 @@ go_library(
"//cmd/kubeadm/app/cmd:go_default_library", "//cmd/kubeadm/app/cmd:go_default_library",
"//cmd/kubelet/app:go_default_library", "//cmd/kubelet/app:go_default_library",
"//pkg/kubectl/cmd:go_default_library", "//pkg/kubectl/cmd:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//vendor/github.com/cpuguy83/go-md2man/md2man:go_default_library", "//vendor/github.com/cpuguy83/go-md2man/md2man:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",

View File

@ -35,7 +35,6 @@ import (
kubeadmapp "k8s.io/kubernetes/cmd/kubeadm/app/cmd" kubeadmapp "k8s.io/kubernetes/cmd/kubeadm/app/cmd"
kubeletapp "k8s.io/kubernetes/cmd/kubelet/app" kubeletapp "k8s.io/kubernetes/cmd/kubelet/app"
kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd" kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
kubectlcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
func main() { func main() {
@ -106,7 +105,7 @@ func main() {
case "kubectl": case "kubectl":
// generate manpage for kubectl // generate manpage for kubectl
// TODO os.Stdin should really be something like ioutil.Discard, but a Reader // TODO os.Stdin should really be something like ioutil.Discard, but a Reader
kubectl := kubectlcmd.NewKubectlCommand(kubectlcmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) kubectl := kubectlcmd.NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard)
genMarkdown(kubectl, "", outDir) genMarkdown(kubectl, "", outDir)
for _, c := range kubectl.Commands() { for _, c := range kubectl.Commands() {
genMarkdown(c, "kubectl", outDir) genMarkdown(c, "kubectl", outDir)

View File

@ -18,7 +18,6 @@ go_library(
deps = [ deps = [
"//cmd/genutils:go_default_library", "//cmd/genutils:go_default_library",
"//pkg/kubectl/cmd:go_default_library", "//pkg/kubectl/cmd:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library", "//vendor/gopkg.in/yaml.v2:go_default_library",

View File

@ -27,7 +27,6 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"k8s.io/kubernetes/cmd/genutils" "k8s.io/kubernetes/cmd/genutils"
"k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
type cmdOption struct { type cmdOption struct {
@ -66,7 +65,7 @@ func main() {
// regardless of where we run. // regardless of where we run.
os.Setenv("HOME", "/home/username") os.Setenv("HOME", "/home/username")
// TODO os.Stdin should really be something like ioutil.Discard, but a Reader // TODO os.Stdin should really be something like ioutil.Discard, but a Reader
kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) kubectl := cmd.NewKubectlCommand(os.Stdin, ioutil.Discard, ioutil.Discard)
genYaml(kubectl, "", outDir) genYaml(kubectl, "", outDir)
for _, c := range kubectl.Commands() { for _, c := range kubectl.Commands() {
genYaml(c, "kubectl", outDir) genYaml(c, "kubectl", outDir)

View File

@ -17,12 +17,13 @@ limitations under the License.
package cmd package cmd
import ( import (
"flag"
"fmt" "fmt"
"io" "io"
"os" "os"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apiserver/pkg/util/flag" utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/auth" "k8s.io/kubernetes/pkg/kubectl/cmd/auth"
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config" cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
@ -219,11 +220,11 @@ var (
) )
func NewDefaultKubectlCommand() *cobra.Command { func NewDefaultKubectlCommand() *cobra.Command {
return NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr) return NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
} }
// NewKubectlCommand creates the `kubectl` command and its nested children. // NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command { func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
// Parent command to which all subcommands are added. // Parent command to which all subcommands are added.
cmds := &cobra.Command{ cmds := &cobra.Command{
Use: "kubectl", Use: "kubectl",
@ -237,8 +238,13 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
BashCompletionFunction: bashCompletionFunc, BashCompletionFunction: bashCompletionFunc,
} }
kubeConfigFlags := cmdutil.NewConfigFlags()
kubeConfigFlags.AddFlags(cmds.PersistentFlags())
cmds.PersistentFlags().AddGoFlagSet(flag.CommandLine)
f := cmdutil.NewFactory(kubeConfigFlags)
f.BindFlags(cmds.PersistentFlags()) f.BindFlags(cmds.PersistentFlags())
f.BindExternalFlags(cmds.PersistentFlags())
// Sending in 'nil' for the getLanguageFn() results in using // Sending in 'nil' for the getLanguageFn() results in using
// the LANG environment variable. // the LANG environment variable.
@ -248,7 +254,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
i18n.LoadTranslations("kubectl", nil) i18n.LoadTranslations("kubectl", nil)
// From this point and forward we get warnings on flags that contain "_" separators // From this point and forward we get warnings on flags that contain "_" separators
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc) cmds.SetGlobalNormalizationFunc(utilflag.WarnWordSepNormalizeFunc)
ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err} ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err}

View File

@ -239,7 +239,7 @@ func newAllPhasePodList() *api.PodList {
func TestNormalizationFuncGlobalExistence(t *testing.T) { func TestNormalizationFuncGlobalExistence(t *testing.T) {
// This test can be safely deleted when we will not support multiple flag formats // This test can be safely deleted when we will not support multiple flag formats
root := NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr) root := NewKubectlCommand(os.Stdin, os.Stdout, os.Stderr)
if root.Parent() != nil { if root.Parent() != nil {
t.Fatal("We expect the root command to be returned") t.Fatal("We expect the root command to be returned")

View File

@ -865,7 +865,7 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfig(cmdutil.NewFactory(nil), clientcmd.NewDefaultPathOptions(), buf, buf) cmd := NewCmdConfig(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), clientcmd.NewDefaultPathOptions(), buf, buf)
cmd.SetArgs(argsToUse) cmd.SetArgs(argsToUse)
cmd.Execute() cmd.Execute()

View File

@ -143,7 +143,7 @@ func (test viewClusterTest) run(t *testing.T) {
pathOptions.EnvVar = "" pathOptions.EnvVar = ""
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{}) errBuf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfigView(cmdutil.NewFactory(nil), buf, errBuf, pathOptions) cmd := NewCmdConfigView(cmdutil.NewFactory(cmdutil.NewTestConfigFlags()), buf, errBuf, pathOptions)
cmd.Flags().Parse(test.flags) cmd.Flags().Parse(test.flags)
if err := cmd.Execute(); err != nil { if err := cmd.Execute(); err != nil {
t.Fatalf("unexpected error executing command: %v,kubectl config view flags: %v", err, test.flags) t.Fatalf("unexpected error executing command: %v,kubectl config view flags: %v", err, test.flags)

View File

@ -26,7 +26,7 @@ import (
) )
func TestLocalAndDryRunFlags(t *testing.T) { func TestLocalAndDryRunFlags(t *testing.T) {
f := clientcmdutil.NewFactory(nil) f := clientcmdutil.NewFactory(clientcmdutil.NewTestConfigFlags())
setCmd := NewCmdSet(f, genericclioptions.NewTestIOStreamsDiscard()) setCmd := NewCmdSet(f, genericclioptions.NewTestIOStreamsDiscard())
ensureLocalAndDryRunFlagsOnChildren(t, setCmd, "") ensureLocalAndDryRunFlagsOnChildren(t, setCmd, "")
} }

View File

@ -253,11 +253,27 @@ type TestFactory struct {
func NewTestFactory() *TestFactory { func NewTestFactory() *TestFactory {
// specify an optionalClientConfig to explicitly use in testing // specify an optionalClientConfig to explicitly use in testing
// to avoid polluting an existing user config. // to avoid polluting an existing user config.
config, configFile := defaultFakeClientConfig() tmpFile, err := ioutil.TempFile("", "cmdtests_temp")
if err != nil {
panic(fmt.Sprintf("unable to create a fake client config: %v", err))
}
loadingRules := &clientcmd.ClientConfigLoadingRules{
Precedence: []string{tmpFile.Name()},
MigrationRules: map[string]string{},
}
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}}
fallbackReader := bytes.NewBuffer([]byte{})
clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, fallbackReader)
configFlags := cmdutil.NewTestConfigFlags().
WithClientConfig(clientConfig)
return &TestFactory{ return &TestFactory{
Factory: cmdutil.NewFactory(config), Factory: cmdutil.NewFactory(configFlags),
FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(legacyscheme.Scheme), FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(legacyscheme.Scheme),
tempConfigFile: configFile, tempConfigFile: tmpFile,
} }
} }
@ -269,31 +285,6 @@ func (f *TestFactory) Cleanup() {
os.Remove(f.tempConfigFile.Name()) os.Remove(f.tempConfigFile.Name())
} }
func defaultFakeClientConfig() (clientcmd.ClientConfig, *os.File) {
loadingRules, tmpFile, err := newDefaultFakeClientConfigLoadingRules()
if err != nil {
panic(fmt.Sprintf("unable to create a fake client config: %v", err))
}
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}}
fallbackReader := bytes.NewBuffer([]byte{})
clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, fallbackReader)
return clientConfig, tmpFile
}
func newDefaultFakeClientConfigLoadingRules() (*clientcmd.ClientConfigLoadingRules, *os.File, error) {
tmpFile, err := ioutil.TempFile("", "cmdtests_temp")
if err != nil {
return nil, nil, err
}
return &clientcmd.ClientConfigLoadingRules{
Precedence: []string{tmpFile.Name()},
MigrationRules: map[string]string{},
}, tmpFile, nil
}
func (f *TestFactory) CategoryExpander() categories.CategoryExpander { func (f *TestFactory) CategoryExpander() categories.CategoryExpander {
return categories.LegacyCategoryExpander return categories.LegacyCategoryExpander
} }

View File

@ -4,6 +4,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"cached_discovery.go", "cached_discovery.go",
"config_flags.go",
"conversion.go", "conversion.go",
"factory.go", "factory.go",
"factory_builder.go", "factory_builder.go",
@ -30,10 +31,10 @@ go_library(
"//pkg/kubectl/cmd/templates:go_default_library", "//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library", "//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/cmd/util/openapi/validation:go_default_library", "//pkg/kubectl/cmd/util/openapi/validation:go_default_library",
"//pkg/kubectl/cmd/util/transport:go_default_library",
"//pkg/kubectl/plugins:go_default_library", "//pkg/kubectl/plugins:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/scheme:go_default_library", "//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/transport:go_default_library",
"//pkg/kubectl/validation:go_default_library", "//pkg/kubectl/validation:go_default_library",
"//pkg/printers:go_default_library", "//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library", "//pkg/printers/internalversion:go_default_library",
@ -139,6 +140,7 @@ filegroup(
"//pkg/kubectl/cmd/util/jsonmerge:all-srcs", "//pkg/kubectl/cmd/util/jsonmerge:all-srcs",
"//pkg/kubectl/cmd/util/openapi:all-srcs", "//pkg/kubectl/cmd/util/openapi:all-srcs",
"//pkg/kubectl/cmd/util/sanity:all-srcs", "//pkg/kubectl/cmd/util/sanity:all-srcs",
"//pkg/kubectl/cmd/util/transport:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//build/visible_to:pkg_kubectl_cmd_util_CONSUMERS"], visibility = ["//build/visible_to:pkg_kubectl_cmd_util_CONSUMERS"],

View File

@ -22,27 +22,70 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/pflag"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir" "k8s.io/client-go/util/homedir"
"k8s.io/kubernetes/pkg/kubectl/util/transport" "k8s.io/kubernetes/pkg/kubectl/cmd/util/transport"
) )
const (
flagClusterName = "cluster"
flagAuthInfoName = "user"
flagContext = "context"
flagNamespace = "namespace"
flagAPIServer = "server"
flagInsecure = "insecure-skip-tls-verify"
flagCertFile = "client-certificate"
flagKeyFile = "client-key"
flagCAFile = "certificate-authority"
flagBearerToken = "token"
flagImpersonate = "as"
flagImpersonateGroup = "as-group"
flagUsername = "username"
flagPassword = "password"
flagTimeout = "request-timeout"
)
// TODO(juanvallejo): move to pkg/kubectl/genericclioptions once
// the dependency on cmdutil is broken here.
// ConfigFlags composes the set of values necessary // ConfigFlags composes the set of values necessary
// for obtaining a REST client config // for obtaining a REST client config
type ConfigFlags struct { type ConfigFlags struct {
CacheDir *string CacheDir *string
KubeConfig *string KubeConfig *string
// config flags
ClusterName *string
AuthInfoName *string
Context *string
Namespace *string
APIServer *string
Insecure *bool
CertFile *string
KeyFile *string
CAFile *string
BearerToken *string
Impersonate *string
ImpersonateGroup *[]string
Username *string
Password *string
Timeout *string
} }
// ToRESTConfig returns a REST client configuration based on a provided // ToRESTConfig implements RESTClientGetter.
// path to a .kubeconfig file, loading rules, and config flag overrides. // Returns a REST client configuration based on a provided path
// to a .kubeconfig file, loading rules, and config flag overrides.
// Expects the AddFlags method to have been called. // Expects the AddFlags method to have been called.
func (f *ConfigFlags) ToRESTConfig() (*rest.Config, error) { func (f *ConfigFlags) ToRESTConfig() (*rest.Config, error) {
return f.ToRawKubeConfigLoader().ClientConfig()
}
func (f *ConfigFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
// use the standard defaults for this client command // use the standard defaults for this client command
// DEPRECATED: remove and replace with something more accurate // DEPRECATED: remove and replace with something more accurate
@ -53,13 +96,74 @@ func (f *ConfigFlags) ToRESTConfig() (*rest.Config, error) {
} }
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
return clientConfig.ClientConfig() // bind auth info flag values to overrides
if f.CertFile != nil {
overrides.AuthInfo.ClientCertificate = *f.CertFile
}
if f.KeyFile != nil {
overrides.AuthInfo.ClientKey = *f.KeyFile
}
if f.BearerToken != nil {
overrides.AuthInfo.Token = *f.BearerToken
}
if f.Impersonate != nil {
overrides.AuthInfo.Impersonate = *f.Impersonate
}
if f.ImpersonateGroup != nil {
overrides.AuthInfo.ImpersonateGroups = *f.ImpersonateGroup
}
if f.Username != nil {
overrides.AuthInfo.Username = *f.Username
}
if f.Password != nil {
overrides.AuthInfo.Password = *f.Password
}
// bind cluster flags
if f.APIServer != nil {
overrides.ClusterInfo.Server = *f.APIServer
}
if f.CAFile != nil {
overrides.ClusterInfo.CertificateAuthority = *f.CAFile
}
if f.Insecure != nil {
overrides.ClusterInfo.InsecureSkipTLSVerify = *f.Insecure
}
// bind context flags
if f.Context != nil {
overrides.CurrentContext = *f.Context
}
if f.ClusterName != nil {
overrides.Context.Cluster = *f.ClusterName
}
if f.AuthInfoName != nil {
overrides.Context.AuthInfo = *f.AuthInfoName
}
if f.Namespace != nil {
overrides.Context.Namespace = *f.Namespace
}
if f.Timeout != nil {
overrides.Timeout = *f.Timeout
}
var clientConfig clientcmd.ClientConfig
// we only have an interactive prompt when a password is allowed
if f.Password == nil {
clientConfig = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
} else {
clientConfig = clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
}
return clientConfig
} }
// ToDiscoveryClient returns a CachedDiscoveryInterface using a computed RESTConfig. // ToDiscoveryClient implements RESTClientGetter.
// Expects the AddFlags method to have been called. // Expects the AddFlags method to have been called.
// Returns a CachedDiscoveryInterface using a computed RESTConfig.
func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
config, err := f.ToRESTConfig() config, err := f.ToRESTConfig()
if err != nil { if err != nil {
@ -71,7 +175,7 @@ func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, e
// double it just so we don't end up here again for a while. This config is only used for discovery. // double it just so we don't end up here again for a while. This config is only used for discovery.
config.Burst = 100 config.Burst = 100
cacheDir := "" cacheDir := filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
if f.CacheDir != nil { if f.CacheDir != nil {
cacheDir = *f.CacheDir cacheDir = *f.CacheDir
} }
@ -94,28 +198,135 @@ func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, e
return NewCachedDiscoveryClient(discoveryClient, cacheDir, time.Duration(10*time.Minute)), nil return NewCachedDiscoveryClient(discoveryClient, cacheDir, time.Duration(10*time.Minute)), nil
} }
func (f *ConfigFlags) AddFlags(cmd *cobra.Command) { func (f *ConfigFlags) AddFlags(flags *pflag.FlagSet) {
flagNames := clientcmd.RecommendedConfigOverrideFlags("") flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
// short flagnames are disabled by default. These are here for compatibility with existing scripts
flagNames.ClusterOverrideFlags.APIServer.ShortName = "s"
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} // Normalize all flags that are coming from other packages or pre-configurations
clientcmd.BindOverrideFlags(overrides, cmd.Flags(), flagNames) // a.k.a. change all "_" to "-". e.g. glog package
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
if f.KubeConfig != nil { if f.KubeConfig != nil {
cmd.Flags().StringVar(f.KubeConfig, "kubeconfig", *f.KubeConfig, "Path to the kubeconfig file to use for CLI requests.") flags.StringVar(f.KubeConfig, "kubeconfig", *f.KubeConfig, "Path to the kubeconfig file to use for CLI requests.")
} }
if f.CacheDir != nil { if f.CacheDir != nil {
cmd.Flags().StringVar(f.CacheDir, FlagHTTPCacheDir, *f.CacheDir, "Default HTTP cache directory") flags.StringVar(f.CacheDir, FlagHTTPCacheDir, *f.CacheDir, "Default HTTP cache directory")
} }
// add config options
if f.CertFile != nil {
flags.StringVar(f.CertFile, flagCertFile, *f.CertFile, "Path to a client certificate file for TLS")
}
if f.KeyFile != nil {
flags.StringVar(f.KeyFile, flagKeyFile, *f.KeyFile, "Path to a client key file for TLS")
}
if f.BearerToken != nil {
flags.StringVar(f.BearerToken, flagBearerToken, *f.BearerToken, "Bearer token for authentication to the API server")
}
if f.Impersonate != nil {
flags.StringVar(f.Impersonate, flagImpersonate, *f.Impersonate, "Username to impersonate for the operation")
}
if f.ImpersonateGroup != nil {
flags.StringArrayVar(f.ImpersonateGroup, flagImpersonateGroup, *f.ImpersonateGroup, "Group to impersonate for the operation, this flag can be repeated to specify multiple groups.")
}
if f.Username != nil {
flags.StringVar(f.Username, flagUsername, *f.Username, "Username for basic authentication to the API server")
}
if f.Password != nil {
flags.StringVar(f.Password, flagPassword, *f.Password, "Password for basic authentication to the API server")
}
if f.ClusterName != nil {
flags.StringVar(f.ClusterName, flagClusterName, *f.ClusterName, "The name of the kubeconfig cluster to use")
}
if f.AuthInfoName != nil {
flags.StringVar(f.AuthInfoName, flagAuthInfoName, *f.AuthInfoName, "The name of the kubeconfig user to use")
}
if f.Namespace != nil {
flags.StringVarP(f.Namespace, flagNamespace, "n", *f.Namespace, "If present, the namespace scope for this CLI request")
}
if f.Context != nil {
flags.StringVar(f.Context, flagContext, *f.Context, "The name of the kubeconfig context to use")
}
if f.APIServer != nil {
flags.StringVarP(f.APIServer, flagAPIServer, "s", *f.APIServer, "The address and port of the Kubernetes API server")
}
if f.Insecure != nil {
flags.BoolVar(f.Insecure, flagInsecure, *f.Insecure, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
}
if f.CAFile != nil {
flags.StringVar(f.CAFile, flagCAFile, *f.CAFile, "Path to a cert file for the certificate authority")
}
if f.Timeout != nil {
flags.StringVar(f.Timeout, flagTimeout, *f.Timeout, "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.")
}
}
func (f *ConfigFlags) WithDeprecatedPasswordFlag() *ConfigFlags {
f.Username = stringptr("")
f.Password = stringptr("")
return f
} }
func NewConfigFlags() *ConfigFlags { func NewConfigFlags() *ConfigFlags {
defaultCacheDir := filepath.Join(homedir.HomeDir(), ".kube", "http-cache") impersonateGroup := []string{}
kubeConfig := "" insecure := false
return &ConfigFlags{ return &ConfigFlags{
CacheDir: &defaultCacheDir, Insecure: &insecure,
KubeConfig: &kubeConfig, Timeout: stringptr("0"),
KubeConfig: stringptr(""),
ClusterName: stringptr(""),
AuthInfoName: stringptr(""),
Context: stringptr(""),
Namespace: stringptr(""),
APIServer: stringptr(""),
CertFile: stringptr(""),
KeyFile: stringptr(""),
CAFile: stringptr(""),
BearerToken: stringptr(""),
Impersonate: stringptr(""),
ImpersonateGroup: &impersonateGroup,
} }
} }
func stringptr(val string) *string {
return &val
}
// TODO(juanvallejo): move to separate file when config_flags are moved
// to pkg/kubectl/genericclioptions
type TestConfigFlags struct {
clientConfig clientcmd.ClientConfig
discoveryClient discovery.CachedDiscoveryInterface
}
func (f *TestConfigFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
if f.clientConfig == nil {
panic("attempt to obtain a test RawKubeConfigLoader with no clientConfig specified")
}
return f.clientConfig
}
func (f *TestConfigFlags) ToRESTConfig() (*rest.Config, error) {
return f.ToRawKubeConfigLoader().ClientConfig()
}
func (f *TestConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
return f.discoveryClient, nil
}
func (f *TestConfigFlags) WithClientConfig(clientConfig clientcmd.ClientConfig) *TestConfigFlags {
f.clientConfig = clientConfig
return f
}
func (f *TestConfigFlags) WithDiscoveryClient(c discovery.CachedDiscoveryInterface) *TestConfigFlags {
f.discoveryClient = c
return f
}
func NewTestConfigFlags() *TestConfigFlags {
return &TestConfigFlags{}
}

View File

@ -37,7 +37,6 @@ import (
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
scaleclient "k8s.io/client-go/scale" scaleclient "k8s.io/client-go/scale"
"k8s.io/client-go/tools/clientcmd"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
apiv1 "k8s.io/kubernetes/pkg/apis/core/v1" apiv1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
@ -125,10 +124,9 @@ type ClientAccessFactory interface {
// Command will stringify and return all environment arguments ie. a command run by a client // Command will stringify and return all environment arguments ie. a command run by a client
// using the factory. // using the factory.
Command(cmd *cobra.Command, showSecrets bool) string Command(cmd *cobra.Command, showSecrets bool) string
// BindFlags adds any flags that are common to all kubectl sub commands. // BindFlags adds any flags that are common to all kubectl sub commands.
BindFlags(flags *pflag.FlagSet) BindFlags(flags *pflag.FlagSet)
// BindExternalFlags adds any flags defined by external projects (not part of pflags)
BindExternalFlags(flags *pflag.FlagSet)
// SuggestedPodTemplateResources returns a list of resource types that declare a pod template // SuggestedPodTemplateResources returns a list of resource types that declare a pod template
SuggestedPodTemplateResources() []schema.GroupResource SuggestedPodTemplateResources() []schema.GroupResource
@ -227,10 +225,9 @@ type factory struct {
} }
// NewFactory creates a factory with the default Kubernetes resources defined // NewFactory creates a factory with the default Kubernetes resources defined
// if optionalClientConfig is nil, then flags will be bound to a new clientcmd.ClientConfig. // Receives a clientGetter capable of providing a discovery client and a REST client configuration.
// if optionalClientConfig is not nil, then this factory will make use of it. func NewFactory(clientGetter RESTClientGetter) Factory {
func NewFactory(optionalClientConfig clientcmd.ClientConfig) Factory { clientAccessFactory := NewClientAccessFactory(clientGetter)
clientAccessFactory := NewClientAccessFactory(optionalClientConfig)
objectMappingFactory := NewObjectMappingFactory(clientAccessFactory) objectMappingFactory := NewObjectMappingFactory(clientAccessFactory)
builderFactory := NewBuilderFactory(clientAccessFactory, objectMappingFactory) builderFactory := NewBuilderFactory(clientAccessFactory, objectMappingFactory)

View File

@ -20,23 +20,19 @@ package util
import ( import (
"errors" "errors"
"flag"
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"time" "sync"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"sync"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
appsv1beta2 "k8s.io/api/apps/v1beta2" appsv1beta2 "k8s.io/api/apps/v1beta2"
@ -50,13 +46,11 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/apps"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
@ -64,124 +58,37 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/transport"
"k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version"
) )
type RESTClientGetter interface {
ToRESTConfig() (*restclient.Config, error)
ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error)
ToRawKubeConfigLoader() clientcmd.ClientConfig
}
type ring0Factory struct { type ring0Factory struct {
flags *pflag.FlagSet clientGetter RESTClientGetter
clientConfig clientcmd.ClientConfig
discoveryCacheDir string
requireMatchedServerVersion bool requireMatchedServerVersion bool
checkServerVersion sync.Once checkServerVersion sync.Once
matchesServerVersionErr error matchesServerVersionErr error
} }
func NewClientAccessFactory(optionalClientConfig clientcmd.ClientConfig) ClientAccessFactory { func NewClientAccessFactory(clientGetter RESTClientGetter) ClientAccessFactory {
flags := pflag.NewFlagSet("", pflag.ContinueOnError) if clientGetter == nil {
panic("attempt to instantiate client_access_factory with nil clientGetter")
clientConfig := optionalClientConfig
if optionalClientConfig == nil {
clientConfig = DefaultClientConfig(flags)
} }
flags.SetNormalizeFunc(utilflag.WarnWordSepNormalizeFunc) // Warn for "_" flags
f := &ring0Factory{ f := &ring0Factory{
flags: flags, clientGetter: clientGetter,
clientConfig: clientConfig,
} }
return f return f
} }
// DefaultClientConfig creates a clientcmd.ClientConfig with the following hierarchy:
// 1. Use the kubeconfig builder. The number of merges and overrides here gets a little crazy. Stay with me.
// 1. Merge the kubeconfig itself. This is done with the following hierarchy rules:
// 1. CommandLineLocation - this parsed from the command line, so it must be late bound. If you specify this,
// then no other kubeconfig files are merged. This file must exist.
// 2. If $KUBECONFIG is set, then it is treated as a list of files that should be merged.
// 3. HomeDirectoryLocation
// Empty filenames are ignored. Files with non-deserializable content produced errors.
// The first file to set a particular value or map key wins and the value or map key is never changed.
// This means that the first file to set CurrentContext will have its context preserved. It also means
// that if two files specify a "red-user", only values from the first file's red-user are used. Even
// non-conflicting entries from the second file's "red-user" are discarded.
// 2. Determine the context to use based on the first hit in this chain
// 1. command line argument - again, parsed from the command line, so it must be late bound
// 2. CurrentContext from the merged kubeconfig file
// 3. Empty is allowed at this stage
// 3. Determine the cluster info and auth info to use. At this point, we may or may not have a context. They
// are built based on the first hit in this chain. (run it twice, once for auth, once for cluster)
// 1. command line argument
// 2. If context is present, then use the context value
// 3. Empty is allowed
// 4. Determine the actual cluster info to use. At this point, we may or may not have a cluster info. Build
// each piece of the cluster info based on the chain:
// 1. command line argument
// 2. If cluster info is present and a value for the attribute is present, use it.
// 3. If you don't have a server location, bail.
// 5. Auth info is build using the same rules as cluster info, EXCEPT that you can only have one authentication
// technique per auth info. The following conditions result in an error:
// 1. If there are two conflicting techniques specified from the command line, fail.
// 2. If the command line does not specify one, and the auth info has conflicting techniques, fail.
// 3. If the command line specifies one and the auth info specifies another, honor the command line technique.
// 2. Use default values and potentially prompt for auth information
//
// However, if it appears that we're running in a kubernetes cluster
// container environment, then run with the auth info kubernetes mounted for
// us. Specifically:
// The env vars KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT are
// set, and the file /var/run/secrets/kubernetes.io/serviceaccount/token
// exists and is not a directory.
func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
// use the standard defaults for this client command
// DEPRECATED: remove and replace with something more accurate
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
flags.StringVar(&loadingRules.ExplicitPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults}
flagNames := clientcmd.RecommendedConfigOverrideFlags("")
// short flagnames are disabled by default. These are here for compatibility with existing scripts
flagNames.ClusterOverrideFlags.APIServer.ShortName = "s"
clientcmd.BindOverrideFlags(overrides, flags, flagNames)
clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)
return clientConfig
}
func (f *ring0Factory) DiscoveryClient() (discovery.CachedDiscoveryInterface, error) { func (f *ring0Factory) DiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
cfg, err := f.clientConfig.ClientConfig() return f.clientGetter.ToDiscoveryClient()
if err != nil {
return nil, err
}
// The more groups you have, the more discovery requests you need to make.
// given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests
// double it just so we don't end up here again for a while. This config is only used for discovery.
cfg.Burst = 100
if f.discoveryCacheDir != "" {
wt := cfg.WrapTransport
cfg.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
if wt != nil {
rt = wt(rt)
}
return transport.NewCacheRoundTripper(f.discoveryCacheDir, rt)
}
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg)
if err != nil {
return nil, err
}
cacheDir := computeDiscoverCacheDir(filepath.Join(homedir.HomeDir(), ".kube", "cache", "discovery"), cfg.Host)
return NewCachedDiscoveryClient(discoveryClient, cacheDir, time.Duration(10*time.Minute)), nil
} }
func (f *ring0Factory) KubernetesClientSet() (*kubernetes.Clientset, error) { func (f *ring0Factory) KubernetesClientSet() (*kubernetes.Clientset, error) {
@ -227,7 +134,7 @@ func (f *ring0Factory) ClientConfig() (*restclient.Config, error) {
if err := f.checkMatchingServerVersion(); err != nil { if err := f.checkMatchingServerVersion(); err != nil {
return nil, err return nil, err
} }
clientConfig, err := f.clientConfig.ClientConfig() clientConfig, err := f.clientGetter.ToRESTConfig()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -235,7 +142,7 @@ func (f *ring0Factory) ClientConfig() (*restclient.Config, error) {
return clientConfig, nil return clientConfig, nil
} }
func (f *ring0Factory) BareClientConfig() (*restclient.Config, error) { func (f *ring0Factory) BareClientConfig() (*restclient.Config, error) {
return f.clientConfig.ClientConfig() return f.clientGetter.ToRESTConfig()
} }
func (f *ring0Factory) RESTClient() (*restclient.RESTClient, error) { func (f *ring0Factory) RESTClient() (*restclient.RESTClient, error) {
@ -413,26 +320,11 @@ func (f *ring0Factory) Command(cmd *cobra.Command, showSecrets bool) string {
} }
func (f *ring0Factory) BindFlags(flags *pflag.FlagSet) { func (f *ring0Factory) BindFlags(flags *pflag.FlagSet) {
// Merge factory's flags
flags.AddFlagSet(f.flags)
// Globally persistent flags across all subcommands. // Globally persistent flags across all subcommands.
// TODO Change flag names to consts to allow safer lookup from subcommands. // TODO Change flag names to consts to allow safer lookup from subcommands.
// TODO Add a verbose flag that turns on glog logging. Probably need a way // TODO Add a verbose flag that turns on glog logging. Probably need a way
// to do that automatically for every subcommand. // to do that automatically for every subcommand.
flags.BoolVar(&f.requireMatchedServerVersion, FlagMatchBinaryVersion, false, "Require server version to match client version") flags.BoolVar(&f.requireMatchedServerVersion, FlagMatchBinaryVersion, false, "Require server version to match client version")
defaultCacheDir := filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
flags.StringVar(&f.discoveryCacheDir, FlagHTTPCacheDir, defaultCacheDir, "Default HTTP cache directory")
// Normalize all flags that are coming from other packages or pre-configurations
// a.k.a. change all "_" to "-". e.g. glog package
flags.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
}
func (f *ring0Factory) BindExternalFlags(flags *pflag.FlagSet) {
// any flags defined by external projects (not part of pflags)
flags.AddGoFlagSet(flag.CommandLine)
} }
func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource { func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource {
@ -476,7 +368,7 @@ func (f *ring0Factory) Resumer(info *resource.Info) ([]byte, error) {
} }
func (f *ring0Factory) DefaultNamespace() (string, bool, error) { func (f *ring0Factory) DefaultNamespace() (string, bool, error) {
return f.clientConfig.Namespace() return f.clientGetter.ToRawKubeConfigLoader().Namespace()
} }
const ( const (

View File

@ -44,7 +44,7 @@ import (
) )
func TestPortsForObject(t *testing.T) { func TestPortsForObject(t *testing.T) {
f := NewFactory(nil) f := NewFactory(NewTestConfigFlags())
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
@ -75,7 +75,7 @@ func TestPortsForObject(t *testing.T) {
} }
func TestProtocolsForObject(t *testing.T) { func TestProtocolsForObject(t *testing.T) {
f := NewFactory(nil) f := NewFactory(NewTestConfigFlags())
pod := &api.Pod{ pod := &api.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
@ -113,7 +113,7 @@ func TestProtocolsForObject(t *testing.T) {
} }
func TestLabelsForObject(t *testing.T) { func TestLabelsForObject(t *testing.T) {
f := NewFactory(nil) f := NewFactory(NewTestConfigFlags())
tests := []struct { tests := []struct {
name string name string
@ -164,7 +164,7 @@ func TestLabelsForObject(t *testing.T) {
} }
func TestCanBeExposed(t *testing.T) { func TestCanBeExposed(t *testing.T) {
factory := NewFactory(nil) factory := NewFactory(NewTestConfigFlags())
tests := []struct { tests := []struct {
kind schema.GroupKind kind schema.GroupKind
expectErr bool expectErr bool

View File

@ -3,7 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["round_tripper.go"], srcs = ["round_tripper.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/transport", importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/transport",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//vendor/github.com/gregjones/httpcache:go_default_library", "//vendor/github.com/gregjones/httpcache:go_default_library",

View File

@ -104,7 +104,6 @@ filegroup(
"//pkg/kubectl/util/logs:all-srcs", "//pkg/kubectl/util/logs:all-srcs",
"//pkg/kubectl/util/slice:all-srcs", "//pkg/kubectl/util/slice:all-srcs",
"//pkg/kubectl/util/term:all-srcs", "//pkg/kubectl/util/term:all-srcs",
"//pkg/kubectl/util/transport:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//build/visible_to:pkg_kubectl_util_CONSUMERS"], visibility = ["//build/visible_to:pkg_kubectl_util_CONSUMERS"],

View File

@ -45,6 +45,7 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apiserver/pkg/features:go_default_library", "//vendor/k8s.io/apiserver/pkg/features:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", "//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",

View File

@ -19,9 +19,12 @@ package apiserver
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"time"
batchv2alpha1 "k8s.io/api/batch/v2alpha1" batchv2alpha1 "k8s.io/api/batch/v2alpha1"
rbacv1alpha1 "k8s.io/api/rbac/v1alpha1" rbacv1alpha1 "k8s.io/api/rbac/v1alpha1"
@ -31,6 +34,7 @@ import (
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/discovery"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/gengo/examples/set-gen/sets" "k8s.io/gengo/examples/set-gen/sets"
@ -146,7 +150,29 @@ func TestServerSidePrint(t *testing.T) {
tableParam := fmt.Sprintf("application/json;as=Table;g=%s;v=%s, application/json", metav1beta1.GroupName, metav1beta1.SchemeGroupVersion.Version) tableParam := fmt.Sprintf("application/json;as=Table;g=%s;v=%s, application/json", metav1beta1.GroupName, metav1beta1.SchemeGroupVersion.Version)
printer := newFakePrinter(printersinternal.AddHandlers) printer := newFakePrinter(printersinternal.AddHandlers)
factory := util.NewFactory(clientcmd.NewDefaultClientConfig(*createKubeConfig(s.URL), &clientcmd.ConfigOverrides{})) configFlags := util.NewTestConfigFlags().
WithClientConfig(clientcmd.NewDefaultClientConfig(*createKubeConfig(s.URL), &clientcmd.ConfigOverrides{}))
restConfig, err := configFlags.ToRESTConfig()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(restConfig)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
cacheDir, err := ioutil.TempDir(os.TempDir(), "test-integration-apiserver-print")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
defer func() {
os.Remove(cacheDir)
}()
configFlags.WithDiscoveryClient(util.NewCachedDiscoveryClient(discoveryClient, cacheDir, time.Duration(10*time.Minute)))
factory := util.NewFactory(configFlags)
mapper, err := factory.RESTMapper() mapper, err := factory.RESTMapper()
if err != nil { if err != nil {
t.Errorf("unexpected error getting mapper: %v", err) t.Errorf("unexpected error getting mapper: %v", err)