Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

respect namespace from .kubeconfig file #3470

Merged
merged 1 commit into from
Jan 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
78 changes: 39 additions & 39 deletions docs/kubectl.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pkg/client/clientcmd/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ type Context struct {
AuthInfo string `json:"user"`
// Namespace is the default namespace to use on unspecified requests
Namespace string `json:"namespace,omitempty"`
// NamespacePath is the path to a kubernetes ns file (~/.kubernetes_ns)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to add a comment somewhere in here that we want to nuke this. I'd prefer it be on client_config.go. We also need a decision on when we can nuke backwards compatibility with .kubernetes_ns now that we have context, and that all the use cases are covered. @brendandburns do you think we could reasonably just nuke namespace-path right now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think we could reasonably just nuke namespace-path right now?

My preference would be to have a second pull request so that any ripples from a breaking change are more self-contained.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to nuking namespace-path. I don't think we have anything using it now, but removing it in a separate PR sgtm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove it when we remove kubecfg. I thought they used the same file.

Sent from my iPhone

On Jan 20, 2015, at 3:57 PM, Jeff Lowdermilk notifications@github.com wrote:

In pkg/client/clientcmd/api/types.go:

@@ -83,6 +83,8 @@ type Context struct {
AuthInfo string json:"user"
// Namespace is the default namespace to use on unspecified requests
Namespace string json:"namespace,omitempty"

  • // NamespacePath is the path to a kubernetes ns file (~/.kubernetes_ns)
    +1 to nuking namespace-path. I don't think we have anything using it now, but removing it in a separate PR sgtm.


Reply to this email directly or view it on GitHub.

NamespacePath string `json:"namespace-path,omitempty"`
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
Extensions map[string]runtime.EmbeddedObject `json:"extensions,omitempty"`
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/client/clientcmd/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ type Context struct {
AuthInfo string `json:"user"`
// Namespace is the default namespace to use on unspecified requests
Namespace string `json:"namespace,omitempty"`
// NamespacePath is the path to a kubernetes ns file (~/.kubernetes_ns)
NamespacePath string `json:"namespace-path,omitempty"`
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
Extensions []NamedExtension `json:"extensions,omitempty"`
}
Expand Down
52 changes: 47 additions & 5 deletions pkg/client/clientcmd/client_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
)

Expand All @@ -36,9 +37,12 @@ var (

// ClientConfig is used to make it easy to get an api server client
type ClientConfig interface {
// RawConfig returns the merged result of all overrides
RawConfig() (clientcmdapi.Config, error)
// ClientConfig returns a complete client config
ClientConfig() (*client.Config, error)
// Namespace returns the namespace resulting from the merged result of all overrides
Namespace() (string, error)
}

// DirectClientConfig is a ClientConfig interface that is backed by a clientcmdapi.Config, options overrides, and an optional fallbackReader for auth information
Expand Down Expand Up @@ -226,6 +230,35 @@ func canIdentifyUser(config client.Config) bool {

}

// Namespace implements KubeConfig
func (config DirectClientConfig) Namespace() (string, error) {
if err := config.ConfirmUsable(); err != nil {
return "", err
}

configContext := config.getContext()

if len(configContext.Namespace) != 0 {
return configContext.Namespace, nil
}

if len(configContext.NamespacePath) != 0 {
nsInfo, err := kubectl.LoadNamespaceInfo(configContext.NamespacePath)
if err != nil {
return "", err
}

return nsInfo.Namespace, nil
}

// if nothing was specified, try the default file
nsInfo, err := kubectl.LoadNamespaceInfo(os.Getenv("HOME") + "/.kubernetes_ns")
if err != nil {
return "", err
}
return nsInfo.Namespace, nil
}

// ConfirmUsable looks a particular context and determines if that particular part of the config is useable. There might still be errors in the config,
// but no errors in the sections requested or referenced. It does not return early so that it can find as many errors as possible.
func (config DirectClientConfig) ConfirmUsable() error {
Expand All @@ -248,21 +281,30 @@ func (config DirectClientConfig) getContextName() string {
}

func (config DirectClientConfig) getAuthInfoName() string {
if len(config.overrides.AuthInfoName) != 0 {
return config.overrides.AuthInfoName
if len(config.overrides.Context.AuthInfo) != 0 {
return config.overrides.Context.AuthInfo
}
return config.getContext().AuthInfo
}

func (config DirectClientConfig) getClusterName() string {
if len(config.overrides.ClusterName) != 0 {
return config.overrides.ClusterName
if len(config.overrides.Context.Cluster) != 0 {
return config.overrides.Context.Cluster
}
return config.getContext().Cluster
}

func (config DirectClientConfig) getContext() clientcmdapi.Context {
return config.config.Contexts[config.getContextName()]
contexts := config.config.Contexts
contextName := config.getContextName()

var mergedContext clientcmdapi.Context
if configContext, exists := contexts[contextName]; exists {
mergo.Merge(&mergedContext, configContext)
}
mergo.Merge(&mergedContext, config.overrides.Context)

return mergedContext
}

func (config DirectClientConfig) getAuthInfo() clientcmdapi.AuthInfo {
Expand Down
18 changes: 18 additions & 0 deletions pkg/client/clientcmd/client_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ func createValidTestConfig() *clientcmdapi.Config {
return config
}

func TestMergeContext(t *testing.T) {
const namespace = "overriden-namespace"

config := createValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
Context: clientcmdapi.Context{
Namespace: namespace,
},
})

actual, err := clientBuilder.Namespace()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}

matchStringArg(namespace, actual, t)
}

func TestCreateClean(t *testing.T) {
config := createValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
Expand Down
10 changes: 10 additions & 0 deletions pkg/client/clientcmd/merged_client_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,13 @@ func (config DeferredLoadingClientConfig) ClientConfig() (*client.Config, error)

return mergedClientConfig.ClientConfig()
}

// Namespace implements KubeConfig
func (config DeferredLoadingClientConfig) Namespace() (string, error) {
mergedKubeConfig, err := config.createClientConfig()
if err != nil {
return "", err
}

return mergedKubeConfig.Namespace()
}
68 changes: 43 additions & 25 deletions pkg/client/clientcmd/overrides.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,17 @@ import (
type ConfigOverrides struct {
AuthInfo clientcmdapi.AuthInfo
ClusterInfo clientcmdapi.Cluster
Namespace string
Context clientcmdapi.Context
CurrentContext string
ClusterName string
AuthInfoName string
}

// ConfigOverrideFlags holds the flag names to be used for binding command line flags. Notice that this structure tightly
// corresponds to ConfigOverrides
type ConfigOverrideFlags struct {
AuthOverrideFlags AuthOverrideFlags
ClusterOverrideFlags ClusterOverrideFlags
Namespace string
ContextOverrideFlags ContextOverrideFlags
CurrentContext string
ClusterName string
AuthInfoName string
}

// AuthOverrideFlags holds the flag names to be used for binding command line flags for AuthInfo objects
Expand All @@ -52,6 +48,14 @@ type AuthOverrideFlags struct {
Token string
}

// ContextOverrideFlags holds the flag names to be used for binding command line flags for Cluster objects
type ContextOverrideFlags struct {
ClusterName string
AuthInfoName string
Namespace string
NamespacePath string
}

// ClusterOverride holds the flag names to be used for binding command line flags for Cluster objects
type ClusterOverrideFlags struct {
APIServer string
Expand All @@ -61,18 +65,19 @@ type ClusterOverrideFlags struct {
}

const (
FlagClusterName = "cluster"
FlagAuthInfoName = "user"
FlagContext = "context"
FlagNamespace = "namespace"
FlagAPIServer = "server"
FlagAPIVersion = "api-version"
FlagAuthPath = "auth-path"
FlagInsecure = "insecure-skip-tls-verify"
FlagCertFile = "client-certificate"
FlagKeyFile = "client-key"
FlagCAFile = "certificate-authority"
FlagBearerToken = "token"
FlagClusterName = "cluster"
FlagAuthInfoName = "user"
FlagContext = "context"
FlagNamespace = "namespace"
FlagNamespacePath = "ns-path"
FlagAPIServer = "server"
FlagAPIVersion = "api-version"
FlagAuthPath = "auth-path"
FlagInsecure = "insecure-skip-tls-verify"
FlagCertFile = "client-certificate"
FlagKeyFile = "client-key"
FlagCAFile = "certificate-authority"
FlagBearerToken = "token"
)

// RecommendedAuthOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing
Expand Down Expand Up @@ -100,10 +105,18 @@ func RecommendedConfigOverrideFlags(prefix string) ConfigOverrideFlags {
return ConfigOverrideFlags{
AuthOverrideFlags: RecommendedAuthOverrideFlags(prefix),
ClusterOverrideFlags: RecommendedClusterOverrideFlags(prefix),
Namespace: prefix + FlagNamespace,
ContextOverrideFlags: RecommendedContextOverrideFlags(prefix),
CurrentContext: prefix + FlagContext,
ClusterName: prefix + FlagClusterName,
AuthInfoName: prefix + FlagAuthInfoName,
}
}

// RecommendedContextOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing
func RecommendedContextOverrideFlags(prefix string) ContextOverrideFlags {
return ContextOverrideFlags{
ClusterName: prefix + FlagClusterName,
AuthInfoName: prefix + FlagAuthInfoName,
Namespace: prefix + FlagNamespace,
NamespacePath: prefix + FlagNamespacePath,
}
}

Expand All @@ -129,9 +142,14 @@ func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, f
func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) {
BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags)
BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags)
// TODO not integrated yet
// flags.StringVar(&overrides.Namespace, flagNames.Namespace, "", "If present, the namespace scope for this CLI request.")
BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags)
flags.StringVar(&overrides.CurrentContext, flagNames.CurrentContext, "", "The name of the kubeconfig context to use")
flags.StringVar(&overrides.ClusterName, flagNames.ClusterName, "", "The name of the kubeconfig cluster to use")
flags.StringVar(&overrides.AuthInfoName, flagNames.AuthInfoName, "", "The name of the kubeconfig user to use")
}

// BindFlags is a convenience method to bind the specified flags to their associated variables
func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) {
flags.StringVar(&contextInfo.Cluster, flagNames.ClusterName, "", "The name of the kubeconfig cluster to use")
flags.StringVar(&contextInfo.AuthInfo, flagNames.AuthInfoName, "", "The name of the kubeconfig user to use")
flags.StringVar(&contextInfo.Namespace, flagNames.Namespace, "", "If present, the namespace scope for this CLI request.")
flags.StringVar(&contextInfo.NamespacePath, flagNames.NamespacePath, "", "Path to the namespace info file that holds the namespace context to use for CLI requests.")
}
46 changes: 10 additions & 36 deletions pkg/kubectl/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ type Factory struct {
Resizer func(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.Resizer, error)
// Returns a schema that can validate objects stored on disk.
Validator func(*cobra.Command) (validation.Schema, error)
// Returns the default namespace to use in cases where no other namespace is specified
DefaultNamespace func(cmd *cobra.Command) (string, error)
}

// NewFactory creates a factory with the default Kubernetes resources defined
Expand All @@ -84,8 +86,11 @@ func NewFactory() *Factory {
flags: flags,

Object: func(cmd *cobra.Command) (meta.RESTMapper, runtime.ObjectTyper) {
version := GetFlagString(cmd, "api-version")
return kubectl.OutputVersionMapper{mapper, version}, api.Scheme
cfg, err := clientConfig.ClientConfig()
checkErr(err)
cmdApiVersion := cfg.Version

return kubectl.OutputVersionMapper{mapper, cmdApiVersion}, api.Scheme
},
Client: func(cmd *cobra.Command) (*client.Client, error) {
return clients.ClientForVersion("")
Expand Down Expand Up @@ -135,6 +140,9 @@ func NewFactory() *Factory {
}
return validation.NullSchema{}, nil
},
DefaultNamespace: func(cmd *cobra.Command) (string, error) {
return clientConfig.Namespace()
},
}
}

Expand All @@ -158,8 +166,6 @@ func (f *Factory) BindFlags(flags *pflag.FlagSet) {
// TODO Add a verbose flag that turns on glog logging. Probably need a way
// to do that automatically for every subcommand.
flags.BoolVar(&f.clients.matchVersion, FlagMatchBinaryVersion, false, "Require server version to match client version")
flags.String("ns-path", os.Getenv("HOME")+"/.kubernetes_ns", "Path to the namespace info file that holds the namespace context to use for CLI requests.")
flags.StringP("namespace", "n", "", "If present, the namespace scope for this CLI request.")
flags.Bool("validate", false, "If true, use a schema to validate the input before sending it")
}

Expand Down Expand Up @@ -264,38 +270,6 @@ func runHelp(cmd *cobra.Command, args []string) {
cmd.Help()
}

// GetKubeNamespace returns the value of the namespace a
// user provided on the command line or use the default
// namespace.
func GetKubeNamespace(cmd *cobra.Command) string {
result := api.NamespaceDefault
if ns := GetFlagString(cmd, "namespace"); len(ns) > 0 {
result = ns
glog.V(2).Infof("Using namespace from -ns flag")
} else {
nsPath := GetFlagString(cmd, "ns-path")
nsInfo, err := kubectl.LoadNamespaceInfo(nsPath)
if err != nil {
glog.Fatalf("Error loading current namespace: %v", err)
}
result = nsInfo.Namespace
}
glog.V(2).Infof("Using namespace %s", result)
return result
}

// GetExplicitKubeNamespace returns the value of the namespace a
// user explicitly provided on the command line, or false if no
// such namespace was specified.
func GetExplicitKubeNamespace(cmd *cobra.Command) (string, bool) {
if ns := GetFlagString(cmd, "namespace"); len(ns) > 0 {
return ns, true
}
// TODO: determine when --ns-path is set but equal to the default
// value and return its value and true.
return "", false
}

type clientSwaggerSchema struct {
c *client.Client
t runtime.ObjectTyper
Expand Down
29 changes: 22 additions & 7 deletions pkg/kubectl/cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
. "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/resource"
Expand Down Expand Up @@ -92,13 +93,15 @@ func (t *testDescriber) Describe(namespace, name string) (output string, err err
}

type testFactory struct {
Mapper meta.RESTMapper
Typer runtime.ObjectTyper
Client kubectl.RESTClient
Describer kubectl.Describer
Printer kubectl.ResourcePrinter
Validator validation.Schema
Err error
Mapper meta.RESTMapper
Typer runtime.ObjectTyper
Client kubectl.RESTClient
Describer kubectl.Describer
Printer kubectl.ResourcePrinter
Validator validation.Schema
Namespace string
ClientConfig *client.Config
Err error
}

func NewTestFactory() (*Factory, *testFactory, runtime.Codec) {
Expand All @@ -124,6 +127,12 @@ func NewTestFactory() (*Factory, *testFactory, runtime.Codec) {
Validator: func(cmd *cobra.Command) (validation.Schema, error) {
return t.Validator, t.Err
},
DefaultNamespace: func(cmd *cobra.Command) (string, error) {
return t.Namespace, t.Err
},
ClientConfig: func(cmd *cobra.Command) (*client.Config, error) {
return t.ClientConfig, t.Err
},
}, t, codec
}

Expand All @@ -147,6 +156,12 @@ func NewAPIFactory() (*Factory, *testFactory, runtime.Codec) {
Validator: func(cmd *cobra.Command) (validation.Schema, error) {
return t.Validator, t.Err
},
DefaultNamespace: func(cmd *cobra.Command) (string, error) {
return t.Namespace, t.Err
},
ClientConfig: func(cmd *cobra.Command) (*client.Config, error) {
return t.ClientConfig, t.Err
},
}, t, latest.Codec
}

Expand Down