diff --git a/kubernetes/config b/kubernetes/config new file mode 120000 index 0000000..70be64a --- /dev/null +++ b/kubernetes/config @@ -0,0 +1 @@ +base/config/ \ No newline at end of file diff --git a/kubernetes/config/api/README.md b/kubernetes/config/api/README.md deleted file mode 100644 index 4472b6f..0000000 --- a/kubernetes/config/api/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Kubernetes Config type Definition and Deepcopy Utility - -This directory contains type definition and deepcopy utility copied from -k8s.io/client-go that are used for parsing and persist kube config yaml -file. - -### types.go - -The Config type definition is copied from k8s.io/client-go/tools/clientcmd/api/v1/types.go -for parsing the kube config yaml. The "k8s.io/apimachinery/pkg/runtime" dependency has -been removed. An example of using this type definition to parse a kube config -yaml is: - -```go - // Init an empty api.Config as unmarshal layout template - c := api.Config{} - err = yaml.Unmarshal(kubeConfig, &c) - if err != nil { - return nil, err - } -``` - -### zz\_generated.deepcopy.go -The Config type deepcopy util file is copied from -k8s.io/client-go/tools/clientcmd/api/v1/zz\_generated.deepcopy.go -for deepcopy the kube config. The "k8s.io/apimachinery/pkg/runtime" dependency has -been removed. diff --git a/kubernetes/config/api/types.go b/kubernetes/config/api/types.go deleted file mode 100644 index da916d3..0000000 --- a/kubernetes/config/api/types.go +++ /dev/null @@ -1,204 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package api - -// NOTE: This Config type definition is copied from k8s.io/client-go/tools/clientcmd/api/v1/types.go -// for parsing the kube config yaml. The "k8s.io/apimachinery/pkg/runtime" dependency has -// been removed. - -// Where possible, json tags match the cli argument names. -// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. - -// Config holds the information needed to build connect to remote kubernetes clusters as a given user -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type Config struct { - // Legacy field from pkg/api/types.go TypeMeta. - // TODO(jlowdermilk): remove this after eliminating downstream dependencies. - // +optional - Kind string `json:"kind,omitempty"` - // Legacy field from pkg/api/types.go TypeMeta. - // TODO(jlowdermilk): remove this after eliminating downstream dependencies. - // +optional - APIVersion string `json:"apiVersion,omitempty"` - // Preferences holds general information to be use for cli interactions - Preferences Preferences `json:"preferences"` - // Clusters is a map of referencable names to cluster configs - Clusters []NamedCluster `json:"clusters"` - // AuthInfos is a map of referencable names to user configs - AuthInfos []NamedAuthInfo `json:"users"` - // Contexts is a map of referencable names to context configs - Contexts []NamedContext `json:"contexts"` - // CurrentContext is the name of the context that you would like to use by default - CurrentContext string `json:"current-context"` - // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields - // +optional - Extensions []NamedExtension `json:"extensions,omitempty"` -} - -// Preferences holds general information to be use for cli interactions -type Preferences struct { - // +optional - Colors bool `json:"colors,omitempty"` - // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields - // +optional - Extensions []NamedExtension `json:"extensions,omitempty"` -} - -// Cluster contains information about how to communicate with a kubernetes cluster -type Cluster struct { - // Server is the address of the kubernetes cluster (https://hostname:port). - Server string `json:"server"` - // InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure. - // +optional - InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"` - // CertificateAuthority is the path to a cert file for the certificate authority. - // +optional - CertificateAuthority string `json:"certificate-authority,omitempty"` - // CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority - // +optional - CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"` - // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields - // +optional - Extensions []NamedExtension `json:"extensions,omitempty"` -} - -// AuthInfo contains information that describes identity information. This is use to tell the kubernetes cluster who you are. -type AuthInfo struct { - // ClientCertificate is the path to a client cert file for TLS. - // +optional - ClientCertificate string `json:"client-certificate,omitempty"` - // ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate - // +optional - ClientCertificateData []byte `json:"client-certificate-data,omitempty"` - // ClientKey is the path to a client key file for TLS. - // +optional - ClientKey string `json:"client-key,omitempty"` - // ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey - // +optional - ClientKeyData []byte `json:"client-key-data,omitempty"` - // Token is the bearer token for authentication to the kubernetes cluster. - // +optional - Token string `json:"token,omitempty"` - // TokenFile is a pointer to a file that contains a bearer token (as described above). If both Token and TokenFile are present, Token takes precedence. - // +optional - TokenFile string `json:"tokenFile,omitempty"` - // Impersonate is the username to imperonate. The name matches the flag. - // +optional - Impersonate string `json:"as,omitempty"` - // ImpersonateGroups is the groups to imperonate. - // +optional - ImpersonateGroups []string `json:"as-groups,omitempty"` - // ImpersonateUserExtra contains additional information for impersonated user. - // +optional - ImpersonateUserExtra map[string][]string `json:"as-user-extra,omitempty"` - // Username is the username for basic authentication to the kubernetes cluster. - // +optional - Username string `json:"username,omitempty"` - // Password is the password for basic authentication to the kubernetes cluster. - // +optional - Password string `json:"password,omitempty"` - // AuthProvider specifies a custom authentication plugin for the kubernetes cluster. - // +optional - AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"` - // Exec specifies a custom exec-based authentication plugin for the kubernetes cluster. - // +optional - Exec *ExecConfig `json:"exec,omitempty"` - // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields - // +optional - Extensions []NamedExtension `json:"extensions,omitempty"` -} - -// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with) -type Context struct { - // Cluster is the name of the cluster for this context - Cluster string `json:"cluster"` - // AuthInfo is the name of the authInfo for this context - AuthInfo string `json:"user"` - // Namespace is the default namespace to use on unspecified requests - // +optional - Namespace string `json:"namespace,omitempty"` - // Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields - // +optional - Extensions []NamedExtension `json:"extensions,omitempty"` -} - -// NamedCluster relates nicknames to cluster information -type NamedCluster struct { - // Name is the nickname for this Cluster - Name string `json:"name"` - // Cluster holds the cluster information - Cluster Cluster `json:"cluster"` -} - -// NamedContext relates nicknames to context information -type NamedContext struct { - // Name is the nickname for this Context - Name string `json:"name"` - // Context holds the context information - Context Context `json:"context"` -} - -// NamedAuthInfo relates nicknames to auth information -type NamedAuthInfo struct { - // Name is the nickname for this AuthInfo - Name string `json:"name"` - // AuthInfo holds the auth information - AuthInfo AuthInfo `json:"user"` -} - -// NamedExtension relates nicknames to extension information -type NamedExtension struct { - // Name is the nickname for this Extension - Name string `json:"name"` - // Extension holds the extension information - Extension interface{} `json:"extension"` -} - -// AuthProviderConfig holds the configuration for a specified auth provider. -type AuthProviderConfig struct { - Name string `json:"name"` - Config map[string]string `json:"config"` -} - -// ExecConfig specifies a command to provide client credentials. The command is exec'd -// and outputs structured stdout holding credentials. -// -// See the client.authentiction.k8s.io API group for specifications of the exact input -// and output format -type ExecConfig struct { - // Command to execute. - Command string `json:"command"` - // Arguments to pass to the command when executing it. - // +optional - Args []string `json:"args"` - // Env defines additional environment variables to expose to the process. These - // are unioned with the host's environment, as well as variables client-go uses - // to pass argument to the plugin. - // +optional - Env []ExecEnvVar `json:"env"` - - // Preferred input version of the ExecInfo. The returned ExecCredentials MUST use - // the same encoding version as the input. - APIVersion string `json:"apiVersion,omitempty"` -} - -// ExecEnvVar is used for setting environment variables when executing an exec-based -// credential plugin. -type ExecEnvVar struct { - Name string `json:"name"` - Value string `json:"value"` -} diff --git a/kubernetes/config/api/zz_generated.deepcopy.go b/kubernetes/config/api/zz_generated.deepcopy.go deleted file mode 100644 index 77c5d02..0000000 --- a/kubernetes/config/api/zz_generated.deepcopy.go +++ /dev/null @@ -1,344 +0,0 @@ -// +build !ignore_autogenerated - -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by deepcopy-gen. DO NOT EDIT. - -// NOTE: This Config type deepcopy util file is copied from k8s.io/client-go/tools/clientcmd/api/v1/zz_generated.deepcopy.go -// for deepcopy the kube config. The "k8s.io/apimachinery/pkg/runtime" dependency has -// been removed. - -package api - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AuthInfo) DeepCopyInto(out *AuthInfo) { - *out = *in - if in.ClientCertificateData != nil { - in, out := &in.ClientCertificateData, &out.ClientCertificateData - *out = make([]byte, len(*in)) - copy(*out, *in) - } - if in.ClientKeyData != nil { - in, out := &in.ClientKeyData, &out.ClientKeyData - *out = make([]byte, len(*in)) - copy(*out, *in) - } - if in.ImpersonateGroups != nil { - in, out := &in.ImpersonateGroups, &out.ImpersonateGroups - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.ImpersonateUserExtra != nil { - in, out := &in.ImpersonateUserExtra, &out.ImpersonateUserExtra - *out = make(map[string][]string, len(*in)) - for key, val := range *in { - if val == nil { - (*out)[key] = nil - } else { - (*out)[key] = make([]string, len(val)) - copy((*out)[key], val) - } - } - } - if in.AuthProvider != nil { - in, out := &in.AuthProvider, &out.AuthProvider - if *in == nil { - *out = nil - } else { - *out = new(AuthProviderConfig) - (*in).DeepCopyInto(*out) - } - } - if in.Exec != nil { - in, out := &in.Exec, &out.Exec - if *in == nil { - *out = nil - } else { - *out = new(ExecConfig) - (*in).DeepCopyInto(*out) - } - } - if in.Extensions != nil { - in, out := &in.Extensions, &out.Extensions - *out = make([]NamedExtension, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthInfo. -func (in *AuthInfo) DeepCopy() *AuthInfo { - if in == nil { - return nil - } - out := new(AuthInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *AuthProviderConfig) DeepCopyInto(out *AuthProviderConfig) { - *out = *in - if in.Config != nil { - in, out := &in.Config, &out.Config - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthProviderConfig. -func (in *AuthProviderConfig) DeepCopy() *AuthProviderConfig { - if in == nil { - return nil - } - out := new(AuthProviderConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Cluster) DeepCopyInto(out *Cluster) { - *out = *in - if in.CertificateAuthorityData != nil { - in, out := &in.CertificateAuthorityData, &out.CertificateAuthorityData - *out = make([]byte, len(*in)) - copy(*out, *in) - } - if in.Extensions != nil { - in, out := &in.Extensions, &out.Extensions - *out = make([]NamedExtension, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. -func (in *Cluster) DeepCopy() *Cluster { - if in == nil { - return nil - } - out := new(Cluster) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Config) DeepCopyInto(out *Config) { - *out = *in - in.Preferences.DeepCopyInto(&out.Preferences) - if in.Clusters != nil { - in, out := &in.Clusters, &out.Clusters - *out = make([]NamedCluster, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.AuthInfos != nil { - in, out := &in.AuthInfos, &out.AuthInfos - *out = make([]NamedAuthInfo, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Contexts != nil { - in, out := &in.Contexts, &out.Contexts - *out = make([]NamedContext, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Extensions != nil { - in, out := &in.Extensions, &out.Extensions - *out = make([]NamedExtension, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. -func (in *Config) DeepCopy() *Config { - if in == nil { - return nil - } - out := new(Config) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Context) DeepCopyInto(out *Context) { - *out = *in - if in.Extensions != nil { - in, out := &in.Extensions, &out.Extensions - *out = make([]NamedExtension, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Context. -func (in *Context) DeepCopy() *Context { - if in == nil { - return nil - } - out := new(Context) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExecConfig) DeepCopyInto(out *ExecConfig) { - *out = *in - if in.Args != nil { - in, out := &in.Args, &out.Args - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Env != nil { - in, out := &in.Env, &out.Env - *out = make([]ExecEnvVar, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecConfig. -func (in *ExecConfig) DeepCopy() *ExecConfig { - if in == nil { - return nil - } - out := new(ExecConfig) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExecEnvVar) DeepCopyInto(out *ExecEnvVar) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecEnvVar. -func (in *ExecEnvVar) DeepCopy() *ExecEnvVar { - if in == nil { - return nil - } - out := new(ExecEnvVar) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NamedAuthInfo) DeepCopyInto(out *NamedAuthInfo) { - *out = *in - in.AuthInfo.DeepCopyInto(&out.AuthInfo) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedAuthInfo. -func (in *NamedAuthInfo) DeepCopy() *NamedAuthInfo { - if in == nil { - return nil - } - out := new(NamedAuthInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NamedCluster) DeepCopyInto(out *NamedCluster) { - *out = *in - in.Cluster.DeepCopyInto(&out.Cluster) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedCluster. -func (in *NamedCluster) DeepCopy() *NamedCluster { - if in == nil { - return nil - } - out := new(NamedCluster) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NamedContext) DeepCopyInto(out *NamedContext) { - *out = *in - in.Context.DeepCopyInto(&out.Context) - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedContext. -func (in *NamedContext) DeepCopy() *NamedContext { - if in == nil { - return nil - } - out := new(NamedContext) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NamedExtension) DeepCopyInto(out *NamedExtension) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamedExtension. -func (in *NamedExtension) DeepCopy() *NamedExtension { - if in == nil { - return nil - } - out := new(NamedExtension) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Preferences) DeepCopyInto(out *Preferences) { - *out = *in - if in.Extensions != nil { - in, out := &in.Extensions, &out.Extensions - *out = make([]NamedExtension, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Preferences. -func (in *Preferences) DeepCopy() *Preferences { - if in == nil { - return nil - } - out := new(Preferences) - in.DeepCopyInto(out) - return out -} diff --git a/kubernetes/config/authentication.go b/kubernetes/config/authentication.go deleted file mode 100644 index 48904d6..0000000 --- a/kubernetes/config/authentication.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "io/ioutil" - "time" -) - -var ( - // time.Duration that prevents the client dropping valid credential - // due to time skew - expirySkewPreventionDelay = 5 * time.Minute -) - -// Read authentication from kube-config user section if exists. -// -// This function goes through various authentication methods in user -// section of kube-config and stops if it finds a valid authentication -// method. The order of authentication methods is: -// -// 1. GCP auth-provider -// 2. token_data -// 3. token field (point to a token file) -// 4. username/password -func (l *KubeConfigLoader) loadAuthentication() { - // The function walks though authentication methods. It doesn't fail on - // single method loading failure. It is each loading function's responsiblity - // to log meaningful failure message. Kubeconfig is allowed to have no user - // in current context, therefore it is allowed that no authentication is loaded. - - if l.loadGCPToken() || l.loadUserToken() || l.loadUserPassToken() { - return - } -} - -func (l *KubeConfigLoader) loadUserToken() bool { - if l.user.Token == "" && l.user.TokenFile == "" { - return false - } - // Token takes precedence than TokenFile - if l.user.Token != "" { - l.restConfig.token = "Bearer " + l.user.Token - return true - } - - // Read TokenFile - token, err := ioutil.ReadFile(l.user.TokenFile) - if err != nil { - // A user may not provide any TokenFile, so we don't log error here - return false - } - l.restConfig.token = "Bearer " + string(token) - return true -} - -func (l *KubeConfigLoader) loadUserPassToken() bool { - if l.user.Username != "" && l.user.Password != "" { - l.restConfig.token = basicAuthToken(l.user.Username, l.user.Password) - return true - } - return false -} diff --git a/kubernetes/config/gcp.go b/kubernetes/config/gcp.go deleted file mode 100644 index 3652c5b..0000000 --- a/kubernetes/config/gcp.go +++ /dev/null @@ -1,111 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "context" - "fmt" - - "github.com/golang/glog" - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" -) - -const ( - gcpRFC3339Format = "2006-01-02 15:04:05" -) - -// GoogleCredentialLoader defines the interface for getting GCP token -type GoogleCredentialLoader interface { - GetGoogleCredentials() (*oauth2.Token, error) -} - -func (l *KubeConfigLoader) loadGCPToken() bool { - if l.user.AuthProvider == nil || l.user.AuthProvider.Name != "gcp" { - return false - } - - // Refresh GCP token if necessary - if l.user.AuthProvider.Config == nil { - if err := l.refreshGCPToken(); err != nil { - glog.Errorf("failed to refresh GCP token: %v", err) - return false - } - } - if _, ok := l.user.AuthProvider.Config["expiry"]; !ok { - if err := l.refreshGCPToken(); err != nil { - glog.Errorf("failed to refresh GCP token: %v", err) - return false - } - } - expired, err := isExpired(l.user.AuthProvider.Config["expiry"]) - if err != nil { - glog.Errorf("failed to determine if GCP token is expired: %v", err) - return false - } - - if expired { - if err := l.refreshGCPToken(); err != nil { - glog.Errorf("failed to refresh GCP token: %v", err) - return false - } - } - - // Use GCP access token - l.restConfig.token = "Bearer " + l.user.AuthProvider.Config["access-token"] - return true -} - -func (l *KubeConfigLoader) refreshGCPToken() error { - if l.user.AuthProvider.Config == nil { - l.user.AuthProvider.Config = map[string]string{} - } - - // Get *oauth2.Token through Google APIs - if l.gcLoader == nil { - l.gcLoader = DefaultGoogleCredentialLoader{} - } - credentials, err := l.gcLoader.GetGoogleCredentials() - if err != nil { - return err - } - - // Store credentials to Config - l.user.AuthProvider.Config["access-token"] = credentials.AccessToken - l.user.AuthProvider.Config["expiry"] = credentials.Expiry.Format(gcpRFC3339Format) - - setUserWithName(l.rawConfig.AuthInfos, l.currentContext.AuthInfo, &l.user) - // Persist kube config file - if !l.skipConfigPersist { - if err := l.persistConfig(); err != nil { - return err - } - } - return nil -} - -// DefaultGoogleCredentialLoader provides the default method for getting GCP token -type DefaultGoogleCredentialLoader struct{} - -// GetGoogleCredentials fetches GCP using default locations -func (l DefaultGoogleCredentialLoader) GetGoogleCredentials() (*oauth2.Token, error) { - credentials, err := google.FindDefaultCredentials(context.Background(), "https://www.googleapis.com/auth/cloud-platform") - if err != nil { - return nil, fmt.Errorf("failed to get Google credentials: %v", err) - } - return credentials.TokenSource.Token() -} diff --git a/kubernetes/config/incluster_config.go b/kubernetes/config/incluster_config.go deleted file mode 100644 index c98069e..0000000 --- a/kubernetes/config/incluster_config.go +++ /dev/null @@ -1,74 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "crypto/tls" - "crypto/x509" - "fmt" - "io/ioutil" - "net" - "net/http" - "os" - - "k8s.io/client/kubernetes/client" -) - -const ( - serviceHostEnvName = "KUBERNETES_SERVICE_HOST" - servicePortEnvName = "KUBERNETES_SERVICE_PORT" - serviceTokenFilename = "/var/run/secrets/kubernetes.io/serviceaccount/token" - serviceCertFilename = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -) - -// InClusterConfig returns a config object which uses the service account -// kubernetes gives to pods. It's intended for clients that expect to be -// running inside a pod running on kubernetes. It will return an error if -// called from a process not running in a kubernetes environment. -func InClusterConfig() (*client.Configuration, error) { - host, port := os.Getenv(serviceHostEnvName), os.Getenv(servicePortEnvName) - if len(host) == 0 || len(port) == 0 { - return nil, fmt.Errorf("unable to load in-cluster configuration, %v and %v must be defined", serviceHostEnvName, servicePortEnvName) - } - - token, err := ioutil.ReadFile(serviceTokenFilename) - if err != nil { - return nil, err - } - caCert, err := ioutil.ReadFile(serviceCertFilename) - if err != nil { - return nil, err - } - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - c := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - RootCAs: caCertPool, - }, - }, - } - - return &client.Configuration{ - BasePath: "https://" + net.JoinHostPort(host, port), - Host: net.JoinHostPort(host, port), - Scheme: "https", - DefaultHeader: map[string]string{"Authentication": "Bearer " + string(token)}, - UserAgent: defaultUserAgent, - HTTPClient: c, - }, nil -} diff --git a/kubernetes/config/kube_config.go b/kubernetes/config/kube_config.go deleted file mode 100644 index 2744150..0000000 --- a/kubernetes/config/kube_config.go +++ /dev/null @@ -1,277 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "crypto/tls" - "crypto/x509" - "io/ioutil" - "net/http" - "net/url" - "os" - "strings" - - "github.com/ghodss/yaml" - - "k8s.io/client/kubernetes/client" - "k8s.io/client/kubernetes/config/api" -) - -const ( - defaultUserAgent = "Swagger-Codegen/0.1.0a1/go" - kubeConfigEnvName = "KUBECONFIG" - kubeConfigDefaultFilename = "~/.kube/config" -) - -// KubeConfigLoader implements the util functions to load authentication and cluster -// info and hosts intermediate info values. -type KubeConfigLoader struct { - rawConfig api.Config - restConfig RestConfig - - // Skip config persistence, default to false - skipConfigPersist bool - configFilename string - - // Current cluster, user and context - cluster api.Cluster - user api.AuthInfo - currentContext api.Context - - // Set this interface to pass in custom Google credential loader instead of - // using the default loader - gcLoader GoogleCredentialLoader -} - -// RestConfig contains the information that a rest client needs to talk with a server -type RestConfig struct { - basePath string - host string - scheme string - - // authentication token - token string - - // TLS info - caCert []byte - clientCert []byte - clientKey []byte - - // skip TLS verification, default to false - skipTLSVerify bool -} - -// LoadKubeConfig loads authentication and cluster information from kube-config file -// and stores them in returned client.Configuration. -func LoadKubeConfig() (*client.Configuration, error) { - kubeConfigFilename := os.Getenv(kubeConfigEnvName) - // Fallback to default kubeconfig file location if no env variable set - if kubeConfigFilename == "" { - kubeConfigFilename = kubeConfigDefaultFilename - } - - loader, err := NewKubeConfigLoaderFromYAMLFile(kubeConfigFilename, false) - if err != nil { - return nil, err - } - - return loader.LoadAndSet() -} - -// NewKubeConfigLoaderFromYAMLFile creates a new KubeConfigLoader with a parsed -// config yaml file. -func NewKubeConfigLoaderFromYAMLFile(filename string, skipConfigPersist bool) (*KubeConfigLoader, error) { - kubeConfig, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - - // Init an empty api.Config as unmarshal layout template - c := api.Config{} - if err := yaml.Unmarshal(kubeConfig, &c); err != nil { - return nil, err - } - - l := KubeConfigLoader{ - rawConfig: c, - skipConfigPersist: skipConfigPersist, - configFilename: filename, - } - - // Init loader with current cluster, user and context - if err := l.LoadActiveContext(); err != nil { - return nil, err - } - return &l, nil -} - -// LoadAndSet loads authentication and cluster information from kube-config file and -// stores them in returned client.Configuration. -func (l *KubeConfigLoader) LoadAndSet() (*client.Configuration, error) { - l.loadAuthentication() - - if err := l.loadClusterInfo(); err != nil { - return nil, err - } - return l.setConfig() -} - -// loadClusterInfo uses the current cluster, user and context info stored in loader and -// gets necessary TLS information -func (l *KubeConfigLoader) loadClusterInfo() error { - // The swagger-codegen go client doesn't work well with base path having trailing slash. - // This is a short term fix. - l.restConfig.basePath = strings.TrimRight(l.cluster.Server, "/") - - u, err := url.Parse(l.cluster.Server) - if err != nil { - return err - } - l.restConfig.host = u.Host - l.restConfig.scheme = u.Scheme - - if l.cluster.InsecureSkipTLSVerify { - l.restConfig.skipTLSVerify = true - } - - if l.restConfig.scheme == "https" { - if !l.restConfig.skipTLSVerify { - l.restConfig.caCert, err = DataOrFile(l.cluster.CertificateAuthorityData, l.cluster.CertificateAuthority) - if err != nil { - return err - } - } - l.restConfig.clientCert, err = DataOrFile(l.user.ClientCertificateData, l.user.ClientCertificate) - if err != nil { - return err - } - l.restConfig.clientKey, err = DataOrFile(l.user.ClientKeyData, l.user.ClientKey) - if err != nil { - return err - } - } - - return nil -} - -// setConfig converts authentication and TLS info into client Configuration -func (l *KubeConfigLoader) setConfig() (*client.Configuration, error) { - // Set TLS info - transport := http.Transport{} - if l.restConfig.scheme == "https" && !l.restConfig.skipTLSVerify { - cert, err := tls.X509KeyPair(l.restConfig.clientCert, l.restConfig.clientKey) - if err != nil { - return nil, err - } - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(l.restConfig.caCert) - transport.TLSClientConfig = &tls.Config{ - RootCAs: caCertPool, - Certificates: []tls.Certificate{cert}, - } - } - - c := &http.Client{ - Transport: &transport, - } - - header := make(map[string]string) - // Add authentication info to default header - if l.restConfig.token != "" { - header["Authorization"] = l.restConfig.token - // Handle Golang dropping headers on redirect - c.CheckRedirect = func(req *http.Request, via []*http.Request) error { - req.Header.Add("Authorization", l.restConfig.token) - return nil - } - } - - return &client.Configuration{ - BasePath: l.restConfig.basePath, - Host: l.restConfig.host, - Scheme: l.restConfig.scheme, - DefaultHeader: header, - UserAgent: defaultUserAgent, - HTTPClient: c, - }, nil -} - -// RestConfig returns the value of RestConfig in a KubeConfigLoader -func (l *KubeConfigLoader) RestConfig() RestConfig { - return l.restConfig -} - -// SetActiveContext sets the active context in rawConfig, performs necessary persistence, -// and reload active context. This function enables context switch -func (l *KubeConfigLoader) SetActiveContext(ctx string) error { - currentContext, err := getContextWithName(l.rawConfig.Contexts, ctx) - if err != nil { - return err - } - currentContext.DeepCopyInto(&l.currentContext) - l.rawConfig.CurrentContext = ctx - - // Persist kube config file - if !l.skipConfigPersist { - if err := l.persistConfig(); err != nil { - return err - } - } - - return l.LoadActiveContext() -} - -// LoadActiveContext parses the loader's rawConfig using current context and set loader's -// current cluster and user. -func (l *KubeConfigLoader) LoadActiveContext() error { - currentContext, err := getContextWithName(l.rawConfig.Contexts, l.rawConfig.CurrentContext) - if err != nil { - return err - } - currentContext.DeepCopyInto(&l.currentContext) - - cluster, err := getClusterWithName(l.rawConfig.Clusters, l.currentContext.Cluster) - if err != nil { - return err - } - cluster.DeepCopyInto(&l.cluster) - - user, err := getUserWithName(l.rawConfig.AuthInfos, l.currentContext.AuthInfo) - if err != nil { - return err - } - - // kube config may have no (current) user - if user != nil { - user.DeepCopyInto(&l.user) - } - return nil -} - -// persisConfig saves the stored rawConfig to the config file. This function is not exposed and -// should be called only when skipConfigPersist is false. -// TODO(roycaihw): enable custom persistConfig function -func (l *KubeConfigLoader) persistConfig() error { - if l.skipConfigPersist { - return nil - } - data, err := yaml.Marshal(l.rawConfig) - if err != nil { - return err - } - return ioutil.WriteFile(l.configFilename, data, 0644) -} diff --git a/kubernetes/config/kube_config_test.go b/kubernetes/config/kube_config_test.go deleted file mode 100644 index 3ea5dc9..0000000 --- a/kubernetes/config/kube_config_test.go +++ /dev/null @@ -1,484 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - b64 "encoding/base64" - "fmt" - "io/ioutil" - "net/url" - "os" - "reflect" - "strings" - "testing" - "time" - - "golang.org/x/oauth2" - "k8s.io/client/kubernetes/config/api" -) - -const ( - testData = "test-data" - testAnotherData = "test-another-data" - - testServer = "http://test-server" - testUsername = "me" - testPassword = "pass" - - // token for me:pass - testBasicToken = "Basic bWU6cGFzcw==" - - testSSLServer = "https://test-server" - testCertAuth = "cert-auth" - testClientKey = "client-key" - testClientCert = "client-cert" - - bearerTokenFormat = "Bearer %s" - testTokenExpiry = "2000-01-01 12:00:00" // always in past -) - -var ( - // base64 encoded string, used as a test token - testDataBase64 = b64.StdEncoding.EncodeToString([]byte(testData)) - - // base64 encoded string, used as another test token - testAnotherDataBase64 = b64.StdEncoding.EncodeToString([]byte(testAnotherData)) - - testCertAuthBase64 = stringToBase64(testCertAuth) - - testClientKeyBase64 = stringToBase64(testClientKey) - - testClientCertBase64 = stringToBase64(testClientCert) - - // test time set to time.Now() + 2 * expirySkewPreventionDelay, which doesn't expire - testTokenNoExpiry = time.Now().Add(2 * expirySkewPreventionDelay).UTC().Format(gcpRFC3339Format) -) - -var testKubeConfig = api.Config{ - CurrentContext: "no_user", - Contexts: []api.NamedContext{ - { - Name: "no_user", - Context: api.Context{ - Cluster: "default", - }, - }, - { - Name: "non_existing_user", - Context: api.Context{ - Cluster: "default", - AuthInfo: "non_existing_user", - }, - }, - { - Name: "simple_token", - Context: api.Context{ - Cluster: "default", - AuthInfo: "simple_token", - }, - }, - { - Name: "gcp", - Context: api.Context{ - Cluster: "default", - AuthInfo: "gcp", - }, - }, - { - Name: "expired_gcp", - Context: api.Context{ - Cluster: "default", - AuthInfo: "expired_gcp", - }, - }, - { - Name: "user_pass", - Context: api.Context{ - Cluster: "default", - AuthInfo: "user_pass", - }, - }, - { - Name: "ssl", - Context: api.Context{ - Cluster: "ssl", - AuthInfo: "ssl", - }, - }, - { - Name: "ssl_no_verification", - Context: api.Context{ - Cluster: "ssl_no_verification", - AuthInfo: "ssl", - }, - }, - { - Name: "ssl_no_file", - Context: api.Context{ - Cluster: "ssl_no_file", - AuthInfo: "ssl_no_file", - }, - }, - }, - Clusters: []api.NamedCluster{ - { - Name: "default", - Cluster: api.Cluster{ - Server: testServer, - }, - }, - { - Name: "ssl", - Cluster: api.Cluster{ - Server: testSSLServer, - CertificateAuthorityData: testCertAuthBase64, - }, - }, - { - Name: "ssl_no_verification", - Cluster: api.Cluster{ - Server: testSSLServer, - InsecureSkipTLSVerify: true, - }, - }, - { - Name: "ssl_no_file", - Cluster: api.Cluster{ - Server: testSSLServer, - CertificateAuthority: "test-cert-no-file", - }, - }, - }, - AuthInfos: []api.NamedAuthInfo{ - { - Name: "simple_token", - AuthInfo: api.AuthInfo{ - Token: testDataBase64, - Username: testUsername, - Password: testPassword, - }, - }, - { - Name: "gcp", - AuthInfo: api.AuthInfo{ - AuthProvider: &api.AuthProviderConfig{ - Name: "gcp", - Config: map[string]string{ - "access-token": testDataBase64, - "expiry": testTokenNoExpiry, - }, - }, - Token: testDataBase64, - Username: testUsername, - Password: testPassword, - }, - }, - { - Name: "expired_gcp", - AuthInfo: api.AuthInfo{ - AuthProvider: &api.AuthProviderConfig{ - Name: "gcp", - Config: map[string]string{ - "access-token": testDataBase64, - "expiry": testTokenExpiry, - }, - }, - Token: testDataBase64, - Username: testUsername, - Password: testPassword, - }, - }, - { - Name: "user_pass", - AuthInfo: api.AuthInfo{ - Username: testUsername, - Password: testPassword, - }, - }, - { - Name: "ssl", - AuthInfo: api.AuthInfo{ - Token: testDataBase64, - ClientCertificateData: testClientCertBase64, - ClientKeyData: testClientKeyBase64, - }, - }, - { - Name: "ssl_no_file", - AuthInfo: api.AuthInfo{ - Token: testDataBase64, - ClientCertificate: "test-client-cert-no-file", - ClientKey: "test-client-key-no-file", - }, - }, - }, -} - -func TestLoadKubeConfig(t *testing.T) { - tcs := []struct { - ActiveContext string - - Server string - Token string - CACert []byte - Cert []byte - Key []byte - SkipTLSVerify bool - GCLoader GoogleCredentialLoader - }{ - { - ActiveContext: "no_user", - Server: testServer, - }, - { - ActiveContext: "non_existing_user", - Server: testServer, - }, - { - ActiveContext: "simple_token", - Server: testServer, - Token: fmt.Sprintf(bearerTokenFormat, testDataBase64), - }, - { - ActiveContext: "user_pass", - Server: testServer, - Token: testBasicToken, - }, - { - ActiveContext: "gcp", - Server: testServer, - Token: fmt.Sprintf(bearerTokenFormat, testDataBase64), - GCLoader: FakeGoogleCredentialLoaderNoRefresh{}, - }, - { - ActiveContext: "expired_gcp", - Server: testServer, - Token: fmt.Sprintf(bearerTokenFormat, testAnotherDataBase64), - GCLoader: FakeGoogleCredentialLoader{}, - }, - { - ActiveContext: "ssl", - Server: testSSLServer, - Token: fmt.Sprintf(bearerTokenFormat, testDataBase64), - CACert: testCertAuthBase64, - Cert: testClientCertBase64, - Key: testClientKeyBase64, - }, - { - ActiveContext: "ssl_no_verification", - Server: testSSLServer, - Token: fmt.Sprintf(bearerTokenFormat, testDataBase64), - Cert: testClientCertBase64, - Key: testClientKeyBase64, - SkipTLSVerify: true, - }, - } - - for _, tc := range tcs { - expected, err := FakeConfig(tc.Server, tc.Token, tc.CACert, tc.Cert, tc.Key, tc.SkipTLSVerify) - if err != nil { - t.Errorf("context %v, unexpected error setting up fake config: %v", tc.ActiveContext, err) - } - - actual := KubeConfigLoader{ - rawConfig: testKubeConfig, - skipConfigPersist: true, - gcLoader: tc.GCLoader, - } - if err := actual.SetActiveContext(tc.ActiveContext); err != nil { - t.Errorf("context %v, unexpected error setting config active context: %v", tc.ActiveContext, err) - } - - // We are only testing loading auth and TLS info in LoadAndSet; we are not testing setting - // the generate client's Configuration based on the restConfig, because we are using fake - // data as TLS cert, which would fail PEM validation - actual.loadAuthentication() - if err := actual.loadClusterInfo(); err != nil { - t.Errorf("context %v, unexpected error loading kube config: %v", tc.ActiveContext, err) - } - if !reflect.DeepEqual(expected, actual.RestConfig()) { - t.Errorf("context %v, config loaded mismatch: want %v, got %v", tc.ActiveContext, expected, actual.RestConfig()) - } - } -} - -func TestLoadKubeConfigSSLNoFile(t *testing.T) { - actual := KubeConfigLoader{ - rawConfig: testKubeConfig, - skipConfigPersist: true, - } - if err := actual.SetActiveContext("ssl_no_file"); err != nil { - t.Errorf("context %v, unexpected error setting config active context: %v", "ssl_no_file", err) - } - - // We are only testing loading auth and TLS info in LoadAndSet; we are not testing setting - // the generate client's Configuration based on the restConfig, because we are using fake - // data as TLS cert, which would fail PEM validation - actual.loadAuthentication() - if err := actual.loadClusterInfo(); err == nil || !strings.Contains(err.Error(), "failed to get data or file") { - t.Errorf("context %v, expecting failure to get file, got: %v", "ssl_no_file", err) - } -} - -func TestLoadKubeConfigSSLLocalFile(t *testing.T) { - tc := struct { - ActiveContext string - - Server string - Token string - CACert []byte - Cert []byte - Key []byte - SkipTLSVerify bool - }{ - - ActiveContext: "ssl_local_file", - Server: testSSLServer, - Token: fmt.Sprintf(bearerTokenFormat, testDataBase64), - CACert: testCertAuthBase64, - Cert: testClientCertBase64, - Key: testClientKeyBase64, - } - - expected, err := FakeConfig(tc.Server, tc.Token, tc.CACert, tc.Cert, tc.Key, tc.SkipTLSVerify) - if err != nil { - t.Errorf("context %v, unexpected error setting up fake config: %v", tc.ActiveContext, err) - } - - // Set up CA cert file - testCACertFile, err := ioutil.TempFile(os.TempDir(), "ca-cert") - if err != nil { - t.Errorf("error: failed to create temp ca-cert file") - } - defer os.Remove(testCACertFile.Name()) - if err := ioutil.WriteFile(testCACertFile.Name(), testCertAuthBase64, 0644); err != nil { - t.Errorf("context %v, unexpected error writing temp file %v: %v", tc.ActiveContext, testCACertFile.Name(), err) - } - - // Set up token file - testTokenFile, err := ioutil.TempFile(os.TempDir(), "token") - if err != nil { - t.Errorf("error: failed to create temp token file") - } - defer os.Remove(testTokenFile.Name()) - if err := ioutil.WriteFile(testTokenFile.Name(), []byte(testDataBase64), 0644); err != nil { - t.Errorf("context %v, unexpected error writing temp file %v: %v", tc.ActiveContext, testTokenFile.Name(), err) - } - - // Set up client cert file - testClientCertFile, err := ioutil.TempFile(os.TempDir(), "client-cert") - if err != nil { - t.Errorf("error: failed to create temp client-cert file") - } - defer os.Remove(testClientCertFile.Name()) - if err := ioutil.WriteFile(testClientCertFile.Name(), testClientCertBase64, 0644); err != nil { - t.Errorf("context %v, unexpected error writing temp file %v: %v", tc.ActiveContext, testClientCertFile.Name(), err) - } - - // Set up client key file - testClientKeyFile, err := ioutil.TempFile(os.TempDir(), "client-key") - if err != nil { - t.Errorf("error: failed to create temp client-key file") - } - defer os.Remove(testClientKeyFile.Name()) - if err := ioutil.WriteFile(testClientKeyFile.Name(), testClientKeyBase64, 0644); err != nil { - t.Errorf("context %v, unexpected error writing temp file %v: %v", tc.ActiveContext, testClientKeyFile.Name(), err) - } - - actual := KubeConfigLoader{ - rawConfig: api.Config{ - CurrentContext: "ssl_local_file", - Contexts: []api.NamedContext{ - { - Name: "ssl_local_file", - Context: api.Context{ - Cluster: "ssl_local_file", - AuthInfo: "ssl_local_file", - }, - }, - }, - Clusters: []api.NamedCluster{ - { - Name: "ssl_local_file", - Cluster: api.Cluster{ - Server: testSSLServer, - CertificateAuthority: testCACertFile.Name(), - }, - }, - }, - AuthInfos: []api.NamedAuthInfo{ - { - Name: "ssl_local_file", - AuthInfo: api.AuthInfo{ - TokenFile: testTokenFile.Name(), - ClientCertificate: testClientCertFile.Name(), - ClientKey: testClientKeyFile.Name(), - }, - }, - }, - }, - skipConfigPersist: true, - } - if err := actual.SetActiveContext(tc.ActiveContext); err != nil { - t.Errorf("context %v, unexpected error setting config active context: %v", tc.ActiveContext, err) - } - - // We are only testing loading auth and TLS info in LoadAndSet; we are not testing setting - // the generate client's Configuration based on the restConfig, because we are using fake - // data as TLS cert, which would fail PEM validation - actual.loadAuthentication() - if err := actual.loadClusterInfo(); err != nil { - t.Errorf("context %v, unexpected error loading kube config: %v", tc.ActiveContext, err) - } - if !reflect.DeepEqual(expected, actual.RestConfig()) { - t.Errorf("context %v, config loaded mismatch: want %v, got %v", tc.ActiveContext, expected, actual.RestConfig()) - } -} - -func FakeConfig(server, token string, caCert, clientCert, clientKey []byte, skipTLSVerify bool) (RestConfig, error) { - u, err := url.Parse(server) - if err != nil { - return RestConfig{}, err - } - - return RestConfig{ - basePath: strings.TrimRight(server, "/"), - host: u.Host, - scheme: u.Scheme, - token: token, - caCert: caCert, - clientCert: clientCert, - clientKey: clientKey, - skipTLSVerify: skipTLSVerify, - }, nil -} - -func stringToBase64(str string) []byte { - return []byte(b64.StdEncoding.EncodeToString([]byte(str))) -} - -type FakeGoogleCredentialLoader struct{} - -func (l FakeGoogleCredentialLoader) GetGoogleCredentials() (*oauth2.Token, error) { - return &oauth2.Token{AccessToken: testAnotherDataBase64, Expiry: time.Now().UTC()}, nil -} - -type FakeGoogleCredentialLoaderNoRefresh struct{} - -func (l FakeGoogleCredentialLoaderNoRefresh) GetGoogleCredentials() (*oauth2.Token, error) { - return nil, fmt.Errorf("should not be called") -} diff --git a/kubernetes/config/util.go b/kubernetes/config/util.go deleted file mode 100644 index 9a10af9..0000000 --- a/kubernetes/config/util.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "encoding/base64" - "fmt" - "io/ioutil" - "time" - - "k8s.io/client/kubernetes/config/api" -) - -// DataOrFile reads content of data, or file's content if data doesn't exist -// and represent it as []byte data. -func DataOrFile(data []byte, file string) ([]byte, error) { - if data != nil { - return data, nil - } - result, err := ioutil.ReadFile(file) - if err != nil { - return nil, fmt.Errorf("failed to get data or file: %v", err) - } - return result, nil -} - -// isExpired returns true if the token expired in expirySkewPreventionDelay time (default is 5 minutes) -func isExpired(timestamp string) (bool, error) { - ts, err := time.Parse(gcpRFC3339Format, timestamp) - if err != nil { - return false, err - } - return ts.Before(time.Now().UTC().Add(expirySkewPreventionDelay)), nil -} - -func basicAuthToken(username, password string) string { - return "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password)) -} - -func getContextWithName(contexts []api.NamedContext, name string) (*api.Context, error) { - var context *api.Context - for _, c := range contexts { - if c.Name == name { - if context != nil { - return nil, fmt.Errorf("error parsing kube config: duplicate contexts with name %v", name) - } - context = c.Context.DeepCopy() - } - } - if context == nil { - return nil, fmt.Errorf("error parsing kube config: couldn't find context with name %v", name) - } - return context, nil -} - -func getClusterWithName(clusters []api.NamedCluster, name string) (*api.Cluster, error) { - var cluster *api.Cluster - for _, c := range clusters { - if c.Name == name { - if cluster != nil { - return nil, fmt.Errorf("error parsing kube config: duplicate clusters with name %v", name) - } - cluster = c.Cluster.DeepCopy() - } - } - if cluster == nil { - return nil, fmt.Errorf("error parsing kube config: couldn't find cluster with name %v", name) - } - return cluster, nil -} - -func getUserWithName(users []api.NamedAuthInfo, name string) (*api.AuthInfo, error) { - var user *api.AuthInfo - for _, u := range users { - if u.Name == name { - if user != nil { - return nil, fmt.Errorf("error parsing kube config: duplicate users with name %v", name) - } - user = u.AuthInfo.DeepCopy() - } - } - // A context may have no user, or using non-existing user name. We simply return nil *api.AuthInfo in this case. - return user, nil -} - -func setUserWithName(users []api.NamedAuthInfo, name string, user *api.AuthInfo) error { - var userFound bool - var userTarget *api.AuthInfo - - for i, u := range users { - if u.Name == name { - if userFound { - return fmt.Errorf("error setting kube config: duplicate users with name %v", name) - } - userTarget = &users[i].AuthInfo - userFound = true - } - } - if !userFound { - return fmt.Errorf("error setting kube config: cannot find user with name: %v", name) - } - user.DeepCopyInto(userTarget) - return nil -} diff --git a/kubernetes/config/util_test.go b/kubernetes/config/util_test.go deleted file mode 100644 index 7c9f69b..0000000 --- a/kubernetes/config/util_test.go +++ /dev/null @@ -1,213 +0,0 @@ -/* -Copyright 2018 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package config - -import ( - "fmt" - "reflect" - "testing" - - "k8s.io/client/kubernetes/config/api" -) - -func TestSetUserWithName(t *testing.T) { - tcs := []struct { - Origin []api.NamedAuthInfo - Name string - User *api.AuthInfo - Expected []api.NamedAuthInfo - }{ - { - Origin: []api.NamedAuthInfo{ - {"A", api.AuthInfo{}}, - {"B", api.AuthInfo{}}, - {"C", api.AuthInfo{}}, - }, - Name: "B", - User: &api.AuthInfo{Token: "test-token"}, - Expected: []api.NamedAuthInfo{ - {"A", api.AuthInfo{}}, - {"B", api.AuthInfo{Token: "test-token"}}, - {"C", api.AuthInfo{}}, - }, - }, - } - - for _, tc := range tcs { - if err := setUserWithName(tc.Origin, tc.Name, tc.User); err != nil { - t.Errorf("unexpected error setting user with name %v: %v", tc.Name, err) - } - - if !reflect.DeepEqual(tc.Origin, tc.Expected) { - t.Errorf("setUserWithName mismatch: want %v, got %v", tc.Expected, tc.Origin) - } - } -} - -func TestGetUserWithName(t *testing.T) { - users := []api.NamedAuthInfo{ - {"A", api.AuthInfo{}}, - {"B", api.AuthInfo{Token: "test-token"}}, - {"D", api.AuthInfo{}}, - {"D", api.AuthInfo{}}, - } - - tcs := []struct { - Name string - ExpectedUser *api.AuthInfo - ExpectedError error - }{ - { - Name: "A", - ExpectedUser: &api.AuthInfo{}, - ExpectedError: nil, - }, - { - Name: "B", - ExpectedUser: &api.AuthInfo{Token: "test-token"}, - ExpectedError: nil, - }, - { - Name: "C", - ExpectedUser: nil, - // A context may have no user, or using non-existing user name. - // We simply return nil *api.AuthInfo in this case. - ExpectedError: nil, - }, - { - Name: "D", - ExpectedUser: nil, - ExpectedError: fmt.Errorf("error parsing kube config: duplicate users with name D"), - }, - } - - for _, tc := range tcs { - user, err := getUserWithName(users, tc.Name) - - if !reflect.DeepEqual(tc.ExpectedUser, user) { - t.Errorf("getUserWithName mismatch: want %v, got %v", tc.ExpectedUser, user) - } - - if !reflect.DeepEqual(tc.ExpectedError, err) { - t.Errorf("getUserWithName error mismatch: want %v, got %v", tc.ExpectedError, err) - } - } -} - -func TestGetContextWithName(t *testing.T) { - contexts := []api.NamedContext{ - {"A", api.Context{}}, - {"B", api.Context{ - Cluster: "test-cluster", - AuthInfo: "test-user", - Namespace: "test-namespace", - }}, - {"D", api.Context{}}, - {"D", api.Context{}}, - } - - tcs := []struct { - Name string - ExpectedContext *api.Context - ExpectedError error - }{ - { - Name: "A", - ExpectedContext: &api.Context{}, - ExpectedError: nil, - }, - { - Name: "B", - ExpectedContext: &api.Context{ - Cluster: "test-cluster", - AuthInfo: "test-user", - Namespace: "test-namespace", - }, - ExpectedError: nil, - }, - { - Name: "C", - ExpectedContext: nil, - ExpectedError: fmt.Errorf("error parsing kube config: couldn't find context with name C"), - }, - { - Name: "D", - ExpectedContext: nil, - ExpectedError: fmt.Errorf("error parsing kube config: duplicate contexts with name D"), - }, - } - - for _, tc := range tcs { - context, err := getContextWithName(contexts, tc.Name) - - if !reflect.DeepEqual(tc.ExpectedContext, context) { - t.Errorf("getContextWithName mismatch: want %v, got %v", tc.ExpectedContext, context) - } - - if !reflect.DeepEqual(tc.ExpectedError, err) { - t.Errorf("getContextWithName error mismatch: want %v, got %v", tc.ExpectedError, err) - } - } -} - -func TestGetClusterWithName(t *testing.T) { - clusters := []api.NamedCluster{ - {"A", api.Cluster{}}, - {"B", api.Cluster{Server: "test-server"}}, - {"D", api.Cluster{}}, - {"D", api.Cluster{}}, - } - - tcs := []struct { - Name string - ExpectedCluster *api.Cluster - ExpectedError error - }{ - { - Name: "A", - ExpectedCluster: &api.Cluster{}, - ExpectedError: nil, - }, - { - Name: "B", - ExpectedCluster: &api.Cluster{Server: "test-server"}, - ExpectedError: nil, - }, - { - Name: "C", - ExpectedCluster: nil, - ExpectedError: fmt.Errorf("error parsing kube config: couldn't find cluster with name C"), - }, - { - Name: "D", - ExpectedCluster: nil, - ExpectedError: fmt.Errorf("error parsing kube config: duplicate clusters with name D"), - }, - } - - for _, tc := range tcs { - cluster, err := getClusterWithName(clusters, tc.Name) - - if !reflect.DeepEqual(tc.ExpectedCluster, cluster) { - t.Errorf("getClusterWithName mismatch: want %v, got %v", tc.ExpectedCluster, cluster) - } - - if !reflect.DeepEqual(tc.ExpectedError, err) { - t.Errorf("getClusterWithName error mismatch: want %v, got %v", tc.ExpectedError, err) - } - } -}