mirror of https://github.com/k3s-io/k3s
mechanical
parent
0fed47b27f
commit
335ef747d6
|
@ -19,7 +19,6 @@ go_library(
|
||||||
"//pkg/client/leaderelection:go_default_library",
|
"//pkg/client/leaderelection:go_default_library",
|
||||||
"//pkg/client/leaderelection/resourcelock:go_default_library",
|
"//pkg/client/leaderelection/resourcelock:go_default_library",
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/controller/cloud:go_default_library",
|
"//pkg/controller/cloud:go_default_library",
|
||||||
|
@ -35,6 +34,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"k8s.io/apiserver/pkg/server/healthz"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/cmd/cloud-controller-manager/app/options"
|
"k8s.io/kubernetes/cmd/cloud-controller-manager/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
|
@ -36,7 +37,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection"
|
"k8s.io/kubernetes/pkg/client/leaderelection"
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
nodecontroller "k8s.io/kubernetes/pkg/controller/cloud"
|
nodecontroller "k8s.io/kubernetes/pkg/controller/cloud"
|
||||||
|
|
|
@ -36,7 +36,6 @@ go_library(
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/typed/dynamic:go_default_library",
|
"//pkg/client/typed/dynamic:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/cloudprovider/providers:go_default_library",
|
"//pkg/cloudprovider/providers:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/aws:go_default_library",
|
"//pkg/cloudprovider/providers/aws:go_default_library",
|
||||||
|
@ -101,6 +100,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert",
|
"//vendor:k8s.io/client-go/pkg/util/cert",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"k8s.io/apiserver/pkg/server/healthz"
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
|
@ -46,7 +47,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/controller/informers"
|
"k8s.io/kubernetes/pkg/controller/informers"
|
||||||
|
|
|
@ -22,7 +22,6 @@ go_library(
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/proxy:go_default_library",
|
"//pkg/proxy:go_default_library",
|
||||||
"//pkg/proxy/config:go_default_library",
|
"//pkg/proxy/config:go_default_library",
|
||||||
"//pkg/proxy/iptables:go_default_library",
|
"//pkg/proxy/iptables:go_default_library",
|
||||||
|
@ -45,6 +44,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/net",
|
"//vendor:k8s.io/apimachinery/pkg/util/net",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/cmd/kube-proxy/app/options"
|
"k8s.io/kubernetes/cmd/kube-proxy/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
@ -39,7 +40,6 @@ import (
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/proxy"
|
"k8s.io/kubernetes/pkg/proxy"
|
||||||
proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
|
proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
|
||||||
"k8s.io/kubernetes/pkg/proxy/iptables"
|
"k8s.io/kubernetes/pkg/proxy/iptables"
|
||||||
|
|
|
@ -22,8 +22,8 @@ go_library(
|
||||||
"//cmd/kubeadm/app/discovery/token:go_default_library",
|
"//cmd/kubeadm/app/discovery/token:go_default_library",
|
||||||
"//cmd/kubeadm/app/node:go_default_library",
|
"//cmd/kubeadm/app/node:go_default_library",
|
||||||
"//cmd/kubeadm/app/util:go_default_library",
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//vendor:github.com/spf13/pflag",
|
"//vendor:github.com/spf13/pflag",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,11 +21,11 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubenode "k8s.io/kubernetes/cmd/kubeadm/app/node"
|
kubenode "k8s.io/kubernetes/cmd/kubeadm/app/node"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// For identifies and executes the desired discovery mechanism.
|
// For identifies and executes the desired discovery mechanism.
|
||||||
|
|
|
@ -31,7 +31,6 @@ go_library(
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
|
@ -41,6 +40,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert",
|
"//vendor:k8s.io/client-go/pkg/util/cert",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,13 +25,13 @@ import (
|
||||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
extensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiCallRetryInterval = 500 * time.Millisecond
|
const apiCallRetryInterval = 500 * time.Millisecond
|
||||||
|
|
|
@ -22,7 +22,6 @@ go_library(
|
||||||
"//cmd/kubeadm/app/util:go_default_library",
|
"//cmd/kubeadm/app/util:go_default_library",
|
||||||
"//pkg/apis/certificates:go_default_library",
|
"//pkg/apis/certificates:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubelet/util/csr:go_default_library",
|
"//pkg/kubelet/util/csr:go_default_library",
|
||||||
"//vendor:github.com/square/go-jose",
|
"//vendor:github.com/square/go-jose",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
|
@ -30,6 +29,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/types",
|
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert",
|
"//vendor:k8s.io/client-go/pkg/util/cert",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,13 +26,13 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
kubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// retryTimeout between the subsequent attempts to connect
|
// retryTimeout between the subsequent attempts to connect
|
||||||
|
|
|
@ -22,9 +22,9 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,8 @@ go_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//cmd/kubeadm/app/constants:go_default_library",
|
"//cmd/kubeadm/app/constants:go_default_library",
|
||||||
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
"//cmd/kubeadm/app/phases/certs/pkiutil:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert",
|
"//vendor:k8s.io/client-go/pkg/util/cert",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,10 +26,10 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
"k8s.io/kubernetes/cmd/kubeadm/app/phases/certs/pkiutil"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -47,8 +47,6 @@ go_library(
|
||||||
"//pkg/client/clientset_generated/clientset/typed/certificates/v1beta1:go_default_library",
|
"//pkg/client/clientset_generated/clientset/typed/certificates/v1beta1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
|
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/unversioned/auth:go_default_library",
|
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/cloudprovider/providers:go_default_library",
|
"//pkg/cloudprovider/providers:go_default_library",
|
||||||
"//pkg/credentialprovider:go_default_library",
|
"//pkg/credentialprovider:go_default_library",
|
||||||
|
|
|
@ -28,9 +28,9 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
certificates "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/certificates/v1beta1"
|
certificates "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/certificates/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ import (
|
||||||
"k8s.io/client-go/pkg/util/cert"
|
"k8s.io/client-go/pkg/util/cert"
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
clientauth "k8s.io/client-go/tools/auth"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/cmd/kubelet/app/options"
|
"k8s.io/kubernetes/cmd/kubelet/app/options"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
@ -58,8 +60,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1"
|
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
"k8s.io/kubernetes/pkg/credentialprovider"
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
"k8s.io/kubernetes/pkg/kubelet"
|
"k8s.io/kubernetes/pkg/kubelet"
|
||||||
|
|
|
@ -24,7 +24,6 @@ go_library(
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/client/metrics/prometheus:go_default_library",
|
"//pkg/client/metrics/prometheus:go_default_library",
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockertools:go_default_library",
|
||||||
|
@ -37,6 +36,7 @@ go_library(
|
||||||
"//vendor:github.com/spf13/pflag",
|
"//vendor:github.com/spf13/pflag",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
|
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
||||||
|
|
|
@ -33,7 +33,6 @@ go_library(
|
||||||
"//federation/pkg/federation-controller/service:go_default_library",
|
"//federation/pkg/federation-controller/service:go_default_library",
|
||||||
"//federation/pkg/federation-controller/util:go_default_library",
|
"//federation/pkg/federation-controller/util:go_default_library",
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/util/config:go_default_library",
|
"//pkg/util/config:go_default_library",
|
||||||
"//pkg/util/configz:go_default_library",
|
"//pkg/util/configz:go_default_library",
|
||||||
"//pkg/version:go_default_library",
|
"//pkg/version:go_default_library",
|
||||||
|
@ -46,6 +45,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"k8s.io/apiserver/pkg/server/healthz"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/federation/cmd/federation-controller-manager/app/options"
|
"k8s.io/kubernetes/federation/cmd/federation-controller-manager/app/options"
|
||||||
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
"k8s.io/kubernetes/federation/pkg/dnsprovider"
|
||||||
|
@ -43,7 +44,6 @@ import (
|
||||||
secretcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/secret"
|
secretcontroller "k8s.io/kubernetes/federation/pkg/federation-controller/secret"
|
||||||
servicecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service"
|
servicecontroller "k8s.io/kubernetes/federation/pkg/federation-controller/service"
|
||||||
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
"k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/util/configz"
|
"k8s.io/kubernetes/pkg/util/configz"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
|
|
||||||
|
|
|
@ -49,10 +49,10 @@ go_test(
|
||||||
"//federation/pkg/federation-controller/util:go_default_library",
|
"//federation/pkg/federation-controller/util:go_default_library",
|
||||||
"//pkg/api/testapi:go_default_library",
|
"//pkg/api/testapi:go_default_library",
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/util/uuid:go_default_library",
|
"//pkg/util/uuid:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,13 +25,13 @@ import (
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federationv1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
federationclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
controllerutil "k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
controllerutil "k8s.io/kubernetes/federation/pkg/federation-controller/util"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/util/uuid"
|
"k8s.io/kubernetes/pkg/util/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ go_library(
|
||||||
"//pkg/client/cache:go_default_library",
|
"//pkg/client/cache:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/controller/deployment/util:go_default_library",
|
"//pkg/controller/deployment/util:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
@ -43,6 +42,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/flowcontrol",
|
"//vendor:k8s.io/client-go/pkg/util/flowcontrol",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,12 +27,12 @@ import (
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
federation_v1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federation_v1beta1 "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -21,7 +21,6 @@ go_library(
|
||||||
"//federation/pkg/kubefed/init:go_default_library",
|
"//federation/pkg/kubefed/init:go_default_library",
|
||||||
"//federation/pkg/kubefed/util:go_default_library",
|
"//federation/pkg/kubefed/util:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd:go_default_library",
|
"//pkg/kubectl/cmd:go_default_library",
|
||||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||||
|
@ -33,6 +32,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -55,12 +55,12 @@ go_test(
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/client/restclient/fake:go_default_library",
|
"//pkg/client/restclient/fake:go_default_library",
|
||||||
"//pkg/client/typed/dynamic:go_default_library",
|
"//pkg/client/typed/dynamic:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,6 @@ go_library(
|
||||||
"//pkg/api/resource:go_default_library",
|
"//pkg/api/resource:go_default_library",
|
||||||
"//pkg/apis/extensions:go_default_library",
|
"//pkg/apis/extensions:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
|
@ -29,6 +28,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert",
|
"//vendor:k8s.io/client-go/pkg/util/cert",
|
||||||
"//vendor:k8s.io/client-go/pkg/util/cert/triple",
|
"//vendor:k8s.io/client-go/pkg/util/cert/triple",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -48,13 +48,13 @@ go_test(
|
||||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/client/restclient/fake:go_default_library",
|
"//pkg/client/restclient/fake:go_default_library",
|
||||||
"//pkg/client/typed/dynamic:go_default_library",
|
"//pkg/client/typed/dynamic:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
certutil "k8s.io/client-go/pkg/util/cert"
|
certutil "k8s.io/client-go/pkg/util/cert"
|
||||||
triple "k8s.io/client-go/pkg/util/cert/triple"
|
triple "k8s.io/client-go/pkg/util/cert/triple"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||||
|
@ -47,7 +48,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/intstr"
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
@ -42,7 +43,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/intstr"
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||||
|
@ -34,7 +35,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,9 +19,9 @@ package kubefed
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
kubefedinit "k8s.io/kubernetes/federation/pkg/kubefed/init"
|
kubefedinit "k8s.io/kubernetes/federation/pkg/kubefed/init"
|
||||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
|
kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
|
|
@ -15,10 +15,10 @@ go_library(
|
||||||
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
||||||
"//federation/pkg/kubefed/util:go_default_library",
|
"//federation/pkg/kubefed/util:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -25,11 +25,11 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@ go_library(
|
||||||
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd:go_default_library",
|
"//pkg/kubectl/cmd:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,11 +18,11 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
|
kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,6 @@ filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//pkg/client/unversioned/auth:all-srcs",
|
|
||||||
"//pkg/client/unversioned/clientcmd:all-srcs",
|
|
||||||
"//pkg/client/unversioned/portforward:all-srcs",
|
"//pkg/client/unversioned/portforward:all-srcs",
|
||||||
"//pkg/client/unversioned/remotecommand:all-srcs",
|
"//pkg/client/unversioned/remotecommand:all-srcs",
|
||||||
"//pkg/client/unversioned/testclient/simple:all-srcs",
|
"//pkg/client/unversioned/testclient/simple:all-srcs",
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
package(default_visibility = ["//visibility:public"])
|
|
||||||
|
|
||||||
licenses(["notice"])
|
|
||||||
|
|
||||||
load(
|
|
||||||
"@io_bazel_rules_go//go:def.bzl",
|
|
||||||
"go_library",
|
|
||||||
"go_test",
|
|
||||||
)
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = ["clientauth.go"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
deps = ["//vendor:k8s.io/client-go/rest"],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "go_default_xtest",
|
|
||||||
srcs = ["clientauth_test.go"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
deps = ["//pkg/client/unversioned/auth:go_default_library"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
)
|
|
|
@ -1,125 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 auth defines a file format for holding authentication
|
|
||||||
information needed by clients of Kubernetes. Typically,
|
|
||||||
a Kubernetes cluster will put auth info for the admin in a known
|
|
||||||
location when it is created, and will (soon) put it in a known
|
|
||||||
location within a Container's file tree for Containers that
|
|
||||||
need access to the Kubernetes API.
|
|
||||||
|
|
||||||
Having a defined format allows:
|
|
||||||
- clients to be implmented in multiple languages
|
|
||||||
- applications which link clients to be portable across
|
|
||||||
clusters with different authentication styles (e.g.
|
|
||||||
some may use SSL Client certs, others may not, etc)
|
|
||||||
- when the format changes, applications only
|
|
||||||
need to update this code.
|
|
||||||
|
|
||||||
The file format is json, marshalled from a struct authcfg.Info.
|
|
||||||
|
|
||||||
Clinet libraries in other languages should use the same format.
|
|
||||||
|
|
||||||
It is not intended to store general preferences, such as default
|
|
||||||
namespace, output options, etc. CLIs (such as kubectl) and UIs should
|
|
||||||
develop their own format and may wish to inline the authcfg.Info type.
|
|
||||||
|
|
||||||
The authcfg.Info is just a file format. It is distinct from
|
|
||||||
client.Config which holds options for creating a client.Client.
|
|
||||||
Helper functions are provided in this package to fill in a
|
|
||||||
client.Client from an authcfg.Info.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
import (
|
|
||||||
"pkg/client"
|
|
||||||
"pkg/client/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
info, err := auth.LoadFromFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
clientConfig = client.Config{}
|
|
||||||
clientConfig.Host = "example.com:4901"
|
|
||||||
clientConfig = info.MergeWithConfig()
|
|
||||||
client := client.New(clientConfig)
|
|
||||||
client.Pods(ns).List()
|
|
||||||
*/
|
|
||||||
package auth
|
|
||||||
|
|
||||||
// TODO: need a way to rotate Tokens. Therefore, need a way for client object to be reset when the authcfg is updated.
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Info holds Kubernetes API authorization config. It is intended
|
|
||||||
// to be read/written from a file as a JSON object.
|
|
||||||
type Info struct {
|
|
||||||
User string
|
|
||||||
Password string
|
|
||||||
CAFile string
|
|
||||||
CertFile string
|
|
||||||
KeyFile string
|
|
||||||
BearerToken string
|
|
||||||
Insecure *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadFromFile parses an Info object from a file path.
|
|
||||||
// If the file does not exist, then os.IsNotExist(err) == true
|
|
||||||
func LoadFromFile(path string) (*Info, error) {
|
|
||||||
var info Info
|
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
data, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(data, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeWithConfig returns a copy of a client.Config with values from the Info.
|
|
||||||
// The fields of client.Config with a corresponding field in the Info are set
|
|
||||||
// with the value from the Info.
|
|
||||||
func (info Info) MergeWithConfig(c restclient.Config) (restclient.Config, error) {
|
|
||||||
var config restclient.Config = c
|
|
||||||
config.Username = info.User
|
|
||||||
config.Password = info.Password
|
|
||||||
config.CAFile = info.CAFile
|
|
||||||
config.CertFile = info.CertFile
|
|
||||||
config.KeyFile = info.KeyFile
|
|
||||||
config.BearerToken = info.BearerToken
|
|
||||||
if info.Insecure != nil {
|
|
||||||
config.Insecure = *info.Insecure
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (info Info) Complete() bool {
|
|
||||||
return len(info.User) > 0 ||
|
|
||||||
len(info.CertFile) > 0 ||
|
|
||||||
len(info.BearerToken) > 0
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 auth_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLoadFromFile(t *testing.T) {
|
|
||||||
loadAuthInfoTests := []struct {
|
|
||||||
authData string
|
|
||||||
authInfo *clientauth.Info
|
|
||||||
expectErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
`{"user": "user", "password": "pass"}`,
|
|
||||||
&clientauth.Info{User: "user", Password: "pass"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"", nil, true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, loadAuthInfoTest := range loadAuthInfoTests {
|
|
||||||
tt := loadAuthInfoTest
|
|
||||||
aifile, err := ioutil.TempFile("", "testAuthInfo")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if tt.authData != "missing" {
|
|
||||||
defer os.Remove(aifile.Name())
|
|
||||||
defer aifile.Close()
|
|
||||||
_, err = aifile.WriteString(tt.authData)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aifile.Close()
|
|
||||||
os.Remove(aifile.Name())
|
|
||||||
}
|
|
||||||
authInfo, err := clientauth.LoadFromFile(aifile.Name())
|
|
||||||
gotErr := err != nil
|
|
||||||
if gotErr != tt.expectErr {
|
|
||||||
t.Errorf("expected errorness: %v, actual errorness: %v", tt.expectErr, gotErr)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(authInfo, tt.authInfo) {
|
|
||||||
t.Errorf("Expected %v, got %v", tt.authInfo, authInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package(default_visibility = ["//visibility:public"])
|
|
||||||
|
|
||||||
licenses(["notice"])
|
|
||||||
|
|
||||||
load(
|
|
||||||
"@io_bazel_rules_go//go:def.bzl",
|
|
||||||
"go_library",
|
|
||||||
"go_test",
|
|
||||||
)
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"auth_loaders.go",
|
|
||||||
"client_config.go",
|
|
||||||
"config.go",
|
|
||||||
"doc.go",
|
|
||||||
"helpers.go",
|
|
||||||
"loader.go",
|
|
||||||
"merged_client_builder.go",
|
|
||||||
"overrides.go",
|
|
||||||
"validation.go",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
deps = [
|
|
||||||
"//pkg/api:go_default_library",
|
|
||||||
"//pkg/client/unversioned/auth:go_default_library",
|
|
||||||
"//pkg/util/homedir:go_default_library",
|
|
||||||
"//vendor:github.com/golang/glog",
|
|
||||||
"//vendor:github.com/howeyc/gopass",
|
|
||||||
"//vendor:github.com/imdario/mergo",
|
|
||||||
"//vendor:github.com/spf13/pflag",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation",
|
|
||||||
"//vendor:k8s.io/client-go/rest",
|
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api/latest",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
go_test(
|
|
||||||
name = "go_default_test",
|
|
||||||
srcs = [
|
|
||||||
"client_config_test.go",
|
|
||||||
"loader_test.go",
|
|
||||||
"merged_client_builder_test.go",
|
|
||||||
"validation_test.go",
|
|
||||||
],
|
|
||||||
library = ":go_default_library",
|
|
||||||
tags = ["automanaged"],
|
|
||||||
deps = [
|
|
||||||
"//vendor:github.com/ghodss/yaml",
|
|
||||||
"//vendor:github.com/imdario/mergo",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
|
||||||
"//vendor:k8s.io/client-go/rest",
|
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api/latest",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
)
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/howeyc/gopass"
|
|
||||||
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AuthLoaders are used to build clientauth.Info objects.
|
|
||||||
type AuthLoader interface {
|
|
||||||
// LoadAuth takes a path to a config file and can then do anything it needs in order to return a valid clientauth.Info
|
|
||||||
LoadAuth(path string) (*clientauth.Info, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// default implementation of an AuthLoader
|
|
||||||
type defaultAuthLoader struct{}
|
|
||||||
|
|
||||||
// LoadAuth for defaultAuthLoader simply delegates to clientauth.LoadFromFile
|
|
||||||
func (*defaultAuthLoader) LoadAuth(path string) (*clientauth.Info, error) {
|
|
||||||
return clientauth.LoadFromFile(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
type PromptingAuthLoader struct {
|
|
||||||
reader io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadAuth parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist.
|
|
||||||
func (a *PromptingAuthLoader) LoadAuth(path string) (*clientauth.Info, error) {
|
|
||||||
// Prompt for user/pass and write a file if none exists.
|
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
||||||
authPtr, err := a.Prompt()
|
|
||||||
auth := *authPtr
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(auth)
|
|
||||||
if err != nil {
|
|
||||||
return &auth, err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(path, data, 0600)
|
|
||||||
return &auth, err
|
|
||||||
}
|
|
||||||
authPtr, err := clientauth.LoadFromFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return authPtr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prompt pulls the user and password from a reader
|
|
||||||
func (a *PromptingAuthLoader) Prompt() (*clientauth.Info, error) {
|
|
||||||
var err error
|
|
||||||
auth := &clientauth.Info{}
|
|
||||||
auth.User, err = promptForString("Username", a.reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
auth.Password, err = promptForString("Password", nil, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return auth, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func promptForString(field string, r io.Reader, show bool) (result string, err error) {
|
|
||||||
fmt.Printf("Please enter %s: ", field)
|
|
||||||
if show {
|
|
||||||
_, err = fmt.Fscan(r, &result)
|
|
||||||
} else {
|
|
||||||
var data []byte
|
|
||||||
data, err = gopass.GetPasswdMasked()
|
|
||||||
result = string(data)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPromptingAuthLoader is an AuthLoader that parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist.
|
|
||||||
func NewPromptingAuthLoader(reader io.Reader) *PromptingAuthLoader {
|
|
||||||
return &PromptingAuthLoader{reader}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultAuthLoader returns a default implementation of an AuthLoader that only reads from a config file
|
|
||||||
func NewDefaultAuthLoader() AuthLoader {
|
|
||||||
return &defaultAuthLoader{}
|
|
||||||
}
|
|
|
@ -1,537 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/imdario/mergo"
|
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ClusterDefaults has the same behavior as the old EnvVar and DefaultCluster fields
|
|
||||||
// DEPRECATED will be replaced
|
|
||||||
ClusterDefaults = clientcmdapi.Cluster{Server: getDefaultServer()}
|
|
||||||
// DefaultClientConfig represents the legacy behavior of this package for defaulting
|
|
||||||
// DEPRECATED will be replace
|
|
||||||
DefaultClientConfig = DirectClientConfig{*clientcmdapi.NewConfig(), "", &ConfigOverrides{
|
|
||||||
ClusterDefaults: ClusterDefaults,
|
|
||||||
}, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
|
|
||||||
)
|
|
||||||
|
|
||||||
// getDefaultServer returns a default setting for DefaultClientConfig
|
|
||||||
// DEPRECATED
|
|
||||||
func getDefaultServer() string {
|
|
||||||
if server := os.Getenv("KUBERNETES_MASTER"); len(server) > 0 {
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
return "http://localhost:8080"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() (*restclient.Config, error)
|
|
||||||
// Namespace returns the namespace resulting from the merged
|
|
||||||
// result of all overrides and a boolean indicating if it was
|
|
||||||
// overridden
|
|
||||||
Namespace() (string, bool, error)
|
|
||||||
// ConfigAccess returns the rules for loading/persisting the config.
|
|
||||||
ConfigAccess() ConfigAccess
|
|
||||||
}
|
|
||||||
|
|
||||||
type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
|
|
||||||
|
|
||||||
type promptedCredentials struct {
|
|
||||||
username string
|
|
||||||
password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DirectClientConfig is a ClientConfig interface that is backed by a clientcmdapi.Config, options overrides, and an optional fallbackReader for auth information
|
|
||||||
type DirectClientConfig struct {
|
|
||||||
config clientcmdapi.Config
|
|
||||||
contextName string
|
|
||||||
overrides *ConfigOverrides
|
|
||||||
fallbackReader io.Reader
|
|
||||||
configAccess ConfigAccess
|
|
||||||
// promptedCredentials store the credentials input by the user
|
|
||||||
promptedCredentials promptedCredentials
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultClientConfig creates a DirectClientConfig using the config.CurrentContext as the context name
|
|
||||||
func NewDefaultClientConfig(config clientcmdapi.Config, overrides *ConfigOverrides) ClientConfig {
|
|
||||||
return &DirectClientConfig{config, config.CurrentContext, overrides, nil, NewDefaultClientConfigLoadingRules(), promptedCredentials{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNonInteractiveClientConfig creates a DirectClientConfig using the passed context name and does not have a fallback reader for auth information
|
|
||||||
func NewNonInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, configAccess ConfigAccess) ClientConfig {
|
|
||||||
return &DirectClientConfig{config, contextName, overrides, nil, configAccess, promptedCredentials{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInteractiveClientConfig creates a DirectClientConfig using the passed context name and a reader in case auth information is not provided via files or flags
|
|
||||||
func NewInteractiveClientConfig(config clientcmdapi.Config, contextName string, overrides *ConfigOverrides, fallbackReader io.Reader, configAccess ConfigAccess) ClientConfig {
|
|
||||||
return &DirectClientConfig{config, contextName, overrides, fallbackReader, configAccess, promptedCredentials{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
|
||||||
return config.config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientConfig implements ClientConfig
|
|
||||||
func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
|
|
||||||
// check that getAuthInfo, getContext, and getCluster do not return an error.
|
|
||||||
// Do this before checking if the curent config is usable in the event that an
|
|
||||||
// AuthInfo, Context, or Cluster config with user-defined names are not found.
|
|
||||||
// This provides a user with the immediate cause for error if one is found
|
|
||||||
configAuthInfo, err := config.getAuthInfo()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = config.getContext()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
configClusterInfo, err := config.getCluster()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.ConfirmUsable(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientConfig := &restclient.Config{}
|
|
||||||
clientConfig.Host = configClusterInfo.Server
|
|
||||||
|
|
||||||
if len(config.overrides.Timeout) > 0 {
|
|
||||||
timeout, err := ParseTimeout(config.overrides.Timeout)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
clientConfig.Timeout = timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
if u, err := url.ParseRequestURI(clientConfig.Host); err == nil && u.Opaque == "" && len(u.Path) > 1 {
|
|
||||||
u.RawQuery = ""
|
|
||||||
u.Fragment = ""
|
|
||||||
clientConfig.Host = u.String()
|
|
||||||
}
|
|
||||||
if len(configAuthInfo.Impersonate) > 0 {
|
|
||||||
clientConfig.Impersonate = restclient.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only try to read the auth information if we are secure
|
|
||||||
if restclient.IsConfigTransportTLS(*clientConfig) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// mergo is a first write wins for map value and a last writing wins for interface values
|
|
||||||
// NOTE: This behavior changed with https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a.
|
|
||||||
// Our mergo.Merge version is older than this change.
|
|
||||||
var persister restclient.AuthProviderConfigPersister
|
|
||||||
if config.configAccess != nil {
|
|
||||||
authInfoName, _ := config.getAuthInfoName()
|
|
||||||
persister = PersisterForUser(config.configAccess, authInfoName)
|
|
||||||
}
|
|
||||||
userAuthPartialConfig, err := config.getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader, persister)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mergo.Merge(clientConfig, userAuthPartialConfig)
|
|
||||||
|
|
||||||
serverAuthPartialConfig, err := getServerIdentificationPartialConfig(configAuthInfo, configClusterInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mergo.Merge(clientConfig, serverAuthPartialConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
return clientConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientauth.Info object contain both user identification and server identification. We want different precedence orders for
|
|
||||||
// both, so we have to split the objects and merge them separately
|
|
||||||
// we want this order of precedence for the server identification
|
|
||||||
// 1. configClusterInfo (the final result of command line flags and merged .kubeconfig files)
|
|
||||||
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
|
|
||||||
// 3. load the ~/.kubernetes_auth file as a default
|
|
||||||
func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
|
|
||||||
mergedConfig := &restclient.Config{}
|
|
||||||
|
|
||||||
// configClusterInfo holds the information identify the server provided by .kubeconfig
|
|
||||||
configClientConfig := &restclient.Config{}
|
|
||||||
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
|
|
||||||
configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
|
|
||||||
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
|
|
||||||
mergo.Merge(mergedConfig, configClientConfig)
|
|
||||||
|
|
||||||
return mergedConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientauth.Info object contain both user identification and server identification. We want different precedence orders for
|
|
||||||
// both, so we have to split the objects and merge them separately
|
|
||||||
// we want this order of precedence for user identifcation
|
|
||||||
// 1. configAuthInfo minus auth-path (the final result of command line flags and merged .kubeconfig files)
|
|
||||||
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
|
|
||||||
// 3. if there is not enough information to idenfity the user, load try the ~/.kubernetes_auth file
|
|
||||||
// 4. if there is not enough information to identify the user, prompt if possible
|
|
||||||
func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig restclient.AuthProviderConfigPersister) (*restclient.Config, error) {
|
|
||||||
mergedConfig := &restclient.Config{}
|
|
||||||
|
|
||||||
// blindly overwrite existing values based on precedence
|
|
||||||
if len(configAuthInfo.Token) > 0 {
|
|
||||||
mergedConfig.BearerToken = configAuthInfo.Token
|
|
||||||
} else if len(configAuthInfo.TokenFile) > 0 {
|
|
||||||
tokenBytes, err := ioutil.ReadFile(configAuthInfo.TokenFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mergedConfig.BearerToken = string(tokenBytes)
|
|
||||||
}
|
|
||||||
if len(configAuthInfo.Impersonate) > 0 {
|
|
||||||
mergedConfig.Impersonate = restclient.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
|
|
||||||
}
|
|
||||||
if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
|
|
||||||
mergedConfig.CertFile = configAuthInfo.ClientCertificate
|
|
||||||
mergedConfig.CertData = configAuthInfo.ClientCertificateData
|
|
||||||
mergedConfig.KeyFile = configAuthInfo.ClientKey
|
|
||||||
mergedConfig.KeyData = configAuthInfo.ClientKeyData
|
|
||||||
}
|
|
||||||
if len(configAuthInfo.Username) > 0 || len(configAuthInfo.Password) > 0 {
|
|
||||||
mergedConfig.Username = configAuthInfo.Username
|
|
||||||
mergedConfig.Password = configAuthInfo.Password
|
|
||||||
}
|
|
||||||
if configAuthInfo.AuthProvider != nil {
|
|
||||||
mergedConfig.AuthProvider = configAuthInfo.AuthProvider
|
|
||||||
mergedConfig.AuthConfigPersister = persistAuthConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there still isn't enough information to authenticate the user, try prompting
|
|
||||||
if !canIdentifyUser(*mergedConfig) && (fallbackReader != nil) {
|
|
||||||
if len(config.promptedCredentials.username) > 0 && len(config.promptedCredentials.password) > 0 {
|
|
||||||
mergedConfig.Username = config.promptedCredentials.username
|
|
||||||
mergedConfig.Password = config.promptedCredentials.password
|
|
||||||
return mergedConfig, nil
|
|
||||||
}
|
|
||||||
prompter := NewPromptingAuthLoader(fallbackReader)
|
|
||||||
promptedAuthInfo, err := prompter.Prompt()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
|
|
||||||
previouslyMergedConfig := mergedConfig
|
|
||||||
mergedConfig = &restclient.Config{}
|
|
||||||
mergo.Merge(mergedConfig, promptedConfig)
|
|
||||||
mergo.Merge(mergedConfig, previouslyMergedConfig)
|
|
||||||
config.promptedCredentials.username = mergedConfig.Username
|
|
||||||
config.promptedCredentials.password = mergedConfig.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
return mergedConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
|
|
||||||
func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config {
|
|
||||||
config := &restclient.Config{}
|
|
||||||
config.Username = info.User
|
|
||||||
config.Password = info.Password
|
|
||||||
config.CertFile = info.CertFile
|
|
||||||
config.KeyFile = info.KeyFile
|
|
||||||
config.BearerToken = info.BearerToken
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information
|
|
||||||
func makeServerIdentificationConfig(info clientauth.Info) restclient.Config {
|
|
||||||
config := restclient.Config{}
|
|
||||||
config.CAFile = info.CAFile
|
|
||||||
if info.Insecure != nil {
|
|
||||||
config.Insecure = *info.Insecure
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func canIdentifyUser(config restclient.Config) bool {
|
|
||||||
return len(config.Username) > 0 ||
|
|
||||||
(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
|
|
||||||
len(config.BearerToken) > 0 ||
|
|
||||||
config.AuthProvider != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Namespace implements ClientConfig
|
|
||||||
func (config *DirectClientConfig) Namespace() (string, bool, error) {
|
|
||||||
if err := config.ConfirmUsable(); err != nil {
|
|
||||||
return "", false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
configContext, err := config.getContext()
|
|
||||||
if err != nil {
|
|
||||||
return "", false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(configContext.Namespace) == 0 {
|
|
||||||
return api.NamespaceDefault, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
overridden := false
|
|
||||||
if config.overrides != nil && config.overrides.Context.Namespace != "" {
|
|
||||||
overridden = true
|
|
||||||
}
|
|
||||||
return configContext.Namespace, overridden, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigAccess implements ClientConfig
|
|
||||||
func (config *DirectClientConfig) ConfigAccess() ConfigAccess {
|
|
||||||
return config.configAccess
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
var contextName string
|
|
||||||
if len(config.contextName) != 0 {
|
|
||||||
contextName = config.contextName
|
|
||||||
} else {
|
|
||||||
contextName = config.config.CurrentContext
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(contextName) > 0 {
|
|
||||||
_, exists := config.config.Contexts[contextName]
|
|
||||||
if !exists {
|
|
||||||
validationErrors = append(validationErrors, &errContextNotFound{contextName})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
authInfoName, _ := config.getAuthInfoName()
|
|
||||||
authInfo, _ := config.getAuthInfo()
|
|
||||||
validationErrors = append(validationErrors, validateAuthInfo(authInfoName, authInfo)...)
|
|
||||||
clusterName, _ := config.getClusterName()
|
|
||||||
cluster, _ := config.getCluster()
|
|
||||||
validationErrors = append(validationErrors, validateClusterInfo(clusterName, cluster)...)
|
|
||||||
// when direct client config is specified, and our only error is that no server is defined, we should
|
|
||||||
// return a standard "no config" error
|
|
||||||
if len(validationErrors) == 1 && validationErrors[0] == ErrEmptyCluster {
|
|
||||||
return newErrConfigurationInvalid([]error{ErrEmptyConfig})
|
|
||||||
}
|
|
||||||
return newErrConfigurationInvalid(validationErrors)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getContextName returns the default, or user-set context name, and a boolean that indicates
|
|
||||||
// whether the default context name has been overwritten by a user-set flag, or left as its default value
|
|
||||||
func (config *DirectClientConfig) getContextName() (string, bool) {
|
|
||||||
if len(config.overrides.CurrentContext) != 0 {
|
|
||||||
return config.overrides.CurrentContext, true
|
|
||||||
}
|
|
||||||
if len(config.contextName) != 0 {
|
|
||||||
return config.contextName, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return config.config.CurrentContext, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAuthInfoName returns a string containing the current authinfo name for the current context,
|
|
||||||
// and a boolean indicating whether the default authInfo name is overwritten by a user-set flag, or
|
|
||||||
// left as its default value
|
|
||||||
func (config *DirectClientConfig) getAuthInfoName() (string, bool) {
|
|
||||||
if len(config.overrides.Context.AuthInfo) != 0 {
|
|
||||||
return config.overrides.Context.AuthInfo, true
|
|
||||||
}
|
|
||||||
context, _ := config.getContext()
|
|
||||||
return context.AuthInfo, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// getClusterName returns a string containing the default, or user-set cluster name, and a boolean
|
|
||||||
// indicating whether the default clusterName has been overwritten by a user-set flag, or left as
|
|
||||||
// its default value
|
|
||||||
func (config *DirectClientConfig) getClusterName() (string, bool) {
|
|
||||||
if len(config.overrides.Context.Cluster) != 0 {
|
|
||||||
return config.overrides.Context.Cluster, true
|
|
||||||
}
|
|
||||||
context, _ := config.getContext()
|
|
||||||
return context.Cluster, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// getContext returns the clientcmdapi.Context, or an error if a required context is not found.
|
|
||||||
func (config *DirectClientConfig) getContext() (clientcmdapi.Context, error) {
|
|
||||||
contexts := config.config.Contexts
|
|
||||||
contextName, required := config.getContextName()
|
|
||||||
|
|
||||||
var mergedContext clientcmdapi.Context
|
|
||||||
if configContext, exists := contexts[contextName]; exists {
|
|
||||||
mergo.Merge(&mergedContext, configContext)
|
|
||||||
} else if required {
|
|
||||||
return clientcmdapi.Context{}, fmt.Errorf("context %q does not exist", contextName)
|
|
||||||
}
|
|
||||||
mergo.Merge(&mergedContext, config.overrides.Context)
|
|
||||||
|
|
||||||
return mergedContext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAuthInfo returns the clientcmdapi.AuthInfo, or an error if a required auth info is not found.
|
|
||||||
func (config *DirectClientConfig) getAuthInfo() (clientcmdapi.AuthInfo, error) {
|
|
||||||
authInfos := config.config.AuthInfos
|
|
||||||
authInfoName, required := config.getAuthInfoName()
|
|
||||||
|
|
||||||
var mergedAuthInfo clientcmdapi.AuthInfo
|
|
||||||
if configAuthInfo, exists := authInfos[authInfoName]; exists {
|
|
||||||
mergo.Merge(&mergedAuthInfo, configAuthInfo)
|
|
||||||
} else if required {
|
|
||||||
return clientcmdapi.AuthInfo{}, fmt.Errorf("auth info %q does not exist", authInfoName)
|
|
||||||
}
|
|
||||||
mergo.Merge(&mergedAuthInfo, config.overrides.AuthInfo)
|
|
||||||
|
|
||||||
return mergedAuthInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCluster returns the clientcmdapi.Cluster, or an error if a required cluster is not found.
|
|
||||||
func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
|
|
||||||
clusterInfos := config.config.Clusters
|
|
||||||
clusterInfoName, required := config.getClusterName()
|
|
||||||
|
|
||||||
var mergedClusterInfo clientcmdapi.Cluster
|
|
||||||
mergo.Merge(&mergedClusterInfo, config.overrides.ClusterDefaults)
|
|
||||||
if configClusterInfo, exists := clusterInfos[clusterInfoName]; exists {
|
|
||||||
mergo.Merge(&mergedClusterInfo, configClusterInfo)
|
|
||||||
} else if required {
|
|
||||||
return clientcmdapi.Cluster{}, fmt.Errorf("cluster %q does not exist", clusterInfoName)
|
|
||||||
}
|
|
||||||
mergo.Merge(&mergedClusterInfo, config.overrides.ClusterInfo)
|
|
||||||
// An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
|
|
||||||
// otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set"
|
|
||||||
caLen := len(config.overrides.ClusterInfo.CertificateAuthority)
|
|
||||||
caDataLen := len(config.overrides.ClusterInfo.CertificateAuthorityData)
|
|
||||||
if config.overrides.ClusterInfo.InsecureSkipTLSVerify && caLen == 0 && caDataLen == 0 {
|
|
||||||
mergedClusterInfo.CertificateAuthority = ""
|
|
||||||
mergedClusterInfo.CertificateAuthorityData = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return mergedClusterInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// inClusterClientConfig makes a config that will work from within a kubernetes cluster container environment.
|
|
||||||
// Can take options overrides for flags explicitly provided to the command inside the cluster container.
|
|
||||||
type inClusterClientConfig struct {
|
|
||||||
overrides *ConfigOverrides
|
|
||||||
inClusterConfigProvider func() (*restclient.Config, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ ClientConfig = &inClusterClientConfig{}
|
|
||||||
|
|
||||||
func (config *inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
|
||||||
return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *inClusterClientConfig) ClientConfig() (*restclient.Config, error) {
|
|
||||||
if config.inClusterConfigProvider == nil {
|
|
||||||
config.inClusterConfigProvider = restclient.InClusterConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
icc, err := config.inClusterConfigProvider()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// in-cluster configs only takes a host, token, or CA file
|
|
||||||
// if any of them were individually provided, ovewrite anything else
|
|
||||||
if config.overrides != nil {
|
|
||||||
if server := config.overrides.ClusterInfo.Server; len(server) > 0 {
|
|
||||||
icc.Host = server
|
|
||||||
}
|
|
||||||
if token := config.overrides.AuthInfo.Token; len(token) > 0 {
|
|
||||||
icc.BearerToken = token
|
|
||||||
}
|
|
||||||
if certificateAuthorityFile := config.overrides.ClusterInfo.CertificateAuthority; len(certificateAuthorityFile) > 0 {
|
|
||||||
icc.TLSClientConfig.CAFile = certificateAuthorityFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return icc, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *inClusterClientConfig) Namespace() (string, bool, error) {
|
|
||||||
// This way assumes you've set the POD_NAMESPACE environment variable using the downward API.
|
|
||||||
// This check has to be done first for backwards compatibility with the way InClusterConfig was originally set up
|
|
||||||
if ns := os.Getenv("POD_NAMESPACE"); ns != "" {
|
|
||||||
return ns, true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to the namespace associated with the service account token, if available
|
|
||||||
if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil {
|
|
||||||
if ns := strings.TrimSpace(string(data)); len(ns) > 0 {
|
|
||||||
return ns, true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "default", false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *inClusterClientConfig) ConfigAccess() ConfigAccess {
|
|
||||||
return NewDefaultClientConfigLoadingRules()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possible returns true if loading an inside-kubernetes-cluster is possible.
|
|
||||||
func (config *inClusterClientConfig) Possible() bool {
|
|
||||||
fi, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token")
|
|
||||||
return os.Getenv("KUBERNETES_SERVICE_HOST") != "" &&
|
|
||||||
os.Getenv("KUBERNETES_SERVICE_PORT") != "" &&
|
|
||||||
err == nil && !fi.IsDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildConfigFromFlags is a helper function that builds configs from a master
|
|
||||||
// url or a kubeconfig filepath. These are passed in as command line flags for cluster
|
|
||||||
// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
|
|
||||||
// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
|
|
||||||
// to the default config.
|
|
||||||
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
|
|
||||||
if kubeconfigPath == "" && masterUrl == "" {
|
|
||||||
glog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
|
|
||||||
kubeconfig, err := restclient.InClusterConfig()
|
|
||||||
if err == nil {
|
|
||||||
return kubeconfig, nil
|
|
||||||
}
|
|
||||||
glog.Warning("error creating inClusterConfig, falling back to default config: ", err)
|
|
||||||
}
|
|
||||||
return NewNonInteractiveDeferredLoadingClientConfig(
|
|
||||||
&ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
|
|
||||||
&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master
|
|
||||||
// url and a kubeconfigGetter.
|
|
||||||
func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) {
|
|
||||||
// TODO: We do not need a DeferredLoader here. Refactor code and see if we can use DirectClientConfig here.
|
|
||||||
cc := NewNonInteractiveDeferredLoadingClientConfig(
|
|
||||||
&ClientConfigGetter{kubeconfigGetter: kubeconfigGetter},
|
|
||||||
&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}})
|
|
||||||
return cc.ClientConfig()
|
|
||||||
}
|
|
|
@ -1,506 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/imdario/mergo"
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOldMergoLib(t *testing.T) {
|
|
||||||
type T struct {
|
|
||||||
X string
|
|
||||||
}
|
|
||||||
dst := T{X: "one"}
|
|
||||||
src := T{X: "two"}
|
|
||||||
mergo.Merge(&dst, &src)
|
|
||||||
if dst.X != "two" {
|
|
||||||
// mergo.Merge changed in an incompatible way with
|
|
||||||
//
|
|
||||||
// https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a
|
|
||||||
//
|
|
||||||
// We have to stay with the old version which still does eager
|
|
||||||
// copying from src to dst in structs.
|
|
||||||
t.Errorf("mergo.Merge library found with incompatible, new behavior")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createValidTestConfig() *clientcmdapi.Config {
|
|
||||||
const (
|
|
||||||
server = "https://anything.com:8080"
|
|
||||||
token = "the-token"
|
|
||||||
)
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: server,
|
|
||||||
}
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
Token: token,
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
config.CurrentContext = "clean"
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func createCAValidTestConfig() *clientcmdapi.Config {
|
|
||||||
|
|
||||||
config := createValidTestConfig()
|
|
||||||
config.Clusters["clean"].CertificateAuthorityData = []byte{0, 0}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInsecureOverridesCA(t *testing.T) {
|
|
||||||
config := createCAValidTestConfig()
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
InsecureSkipTLSVerify: true,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
actualCfg, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchBoolArg(true, actualCfg.Insecure, t)
|
|
||||||
matchStringArg("", actualCfg.TLSClientConfig.CAFile, t)
|
|
||||||
matchByteArg(nil, actualCfg.TLSClientConfig.CAData, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMergeContext(t *testing.T) {
|
|
||||||
const namespace = "overriden-namespace"
|
|
||||||
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
_, overridden, err := clientBuilder.Namespace()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if overridden {
|
|
||||||
t.Error("Expected namespace to not be overridden")
|
|
||||||
}
|
|
||||||
|
|
||||||
clientBuilder = NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
|
|
||||||
Context: clientcmdapi.Context{
|
|
||||||
Namespace: namespace,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
actual, overridden, err := clientBuilder.Namespace()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !overridden {
|
|
||||||
t.Error("Expected namespace to be overridden")
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(namespace, actual, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCertificateData(t *testing.T) {
|
|
||||||
caData := []byte("ca-data")
|
|
||||||
certData := []byte("cert-data")
|
|
||||||
keyData := []byte("key-data")
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "https://localhost:8443",
|
|
||||||
CertificateAuthorityData: caData,
|
|
||||||
}
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
ClientCertificateData: certData,
|
|
||||||
ClientKeyData: keyData,
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
config.CurrentContext = "clean"
|
|
||||||
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure cert data gets into config (will override file paths)
|
|
||||||
matchByteArg(caData, clientConfig.TLSClientConfig.CAData, t)
|
|
||||||
matchByteArg(certData, clientConfig.TLSClientConfig.CertData, t)
|
|
||||||
matchByteArg(keyData, clientConfig.TLSClientConfig.KeyData, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBasicAuthData(t *testing.T) {
|
|
||||||
username := "myuser"
|
|
||||||
password := "mypass"
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "https://localhost:8443",
|
|
||||||
}
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
Username: username,
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
config.CurrentContext = "clean"
|
|
||||||
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure basic auth data gets into config
|
|
||||||
matchStringArg(username, clientConfig.Username, t)
|
|
||||||
matchStringArg(password, clientConfig.Password, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBasicTokenFile(t *testing.T) {
|
|
||||||
token := "exampletoken"
|
|
||||||
f, err := ioutil.TempFile("", "tokenfile")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(f.Name())
|
|
||||||
if err := ioutil.WriteFile(f.Name(), []byte(token), 0644); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "https://localhost:8443",
|
|
||||||
}
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
TokenFile: f.Name(),
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
config.CurrentContext = "clean"
|
|
||||||
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(token, clientConfig.BearerToken, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrecedenceTokenFile(t *testing.T) {
|
|
||||||
token := "exampletoken"
|
|
||||||
f, err := ioutil.TempFile("", "tokenfile")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(f.Name())
|
|
||||||
if err := ioutil.WriteFile(f.Name(), []byte(token), 0644); err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "https://localhost:8443",
|
|
||||||
}
|
|
||||||
expectedToken := "expected"
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
Token: expectedToken,
|
|
||||||
TokenFile: f.Name(),
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
config.CurrentContext = "clean"
|
|
||||||
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(expectedToken, clientConfig.BearerToken, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateClean(t *testing.T) {
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t)
|
|
||||||
matchStringArg("", clientConfig.APIPath, t)
|
|
||||||
matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t)
|
|
||||||
matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateCleanWithPrefix(t *testing.T) {
|
|
||||||
tt := []struct {
|
|
||||||
server string
|
|
||||||
host string
|
|
||||||
}{
|
|
||||||
{"https://anything.com:8080/foo/bar", "https://anything.com:8080/foo/bar"},
|
|
||||||
{"http://anything.com:8080/foo/bar", "http://anything.com:8080/foo/bar"},
|
|
||||||
{"http://anything.com:8080/foo/bar/", "http://anything.com:8080/foo/bar/"},
|
|
||||||
{"http://anything.com:8080/", "http://anything.com:8080/"},
|
|
||||||
{"http://anything.com:8080//", "http://anything.com:8080//"},
|
|
||||||
{"anything.com:8080/foo/bar", "anything.com:8080/foo/bar"},
|
|
||||||
{"anything.com:8080", "anything.com:8080"},
|
|
||||||
{"anything.com", "anything.com"},
|
|
||||||
{"anything", "anything"},
|
|
||||||
}
|
|
||||||
|
|
||||||
tt = append(tt, struct{ server, host string }{"", "http://localhost:8080"})
|
|
||||||
|
|
||||||
for _, tc := range tt {
|
|
||||||
config := createValidTestConfig()
|
|
||||||
|
|
||||||
cleanConfig := config.Clusters["clean"]
|
|
||||||
cleanConfig.Server = tc.server
|
|
||||||
config.Clusters["clean"] = cleanConfig
|
|
||||||
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
|
|
||||||
ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(tc.host, clientConfig.Host, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateCleanDefault(t *testing.T) {
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewDefaultClientConfig(*config, &ConfigOverrides{})
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t)
|
|
||||||
matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t)
|
|
||||||
matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateCleanDefaultCluster(t *testing.T) {
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewDefaultClientConfig(*config, &ConfigOverrides{
|
|
||||||
ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"},
|
|
||||||
})
|
|
||||||
|
|
||||||
clientConfig, err := clientBuilder.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t)
|
|
||||||
matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t)
|
|
||||||
matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateMissingContextNoDefault(t *testing.T) {
|
|
||||||
const expectedErrorContains = "Context was not found for specified context"
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "not-present", &ConfigOverrides{}, nil)
|
|
||||||
|
|
||||||
_, err := clientBuilder.ClientConfig()
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateMissingContext(t *testing.T) {
|
|
||||||
const expectedErrorContains = "context was not found for specified context: not-present"
|
|
||||||
config := createValidTestConfig()
|
|
||||||
clientBuilder := NewNonInteractiveClientConfig(*config, "not-present", &ConfigOverrides{
|
|
||||||
ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
_, err := clientBuilder.ClientConfig()
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected error: %v", expectedErrorContains)
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), expectedErrorContains) {
|
|
||||||
t.Fatalf("Expected error: %v, but got %v", expectedErrorContains, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInClusterClientConfigPrecedence(t *testing.T) {
|
|
||||||
tt := []struct {
|
|
||||||
overrides *ConfigOverrides
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
Server: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
AuthInfo: clientcmdapi.AuthInfo{
|
|
||||||
Token: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
CertificateAuthority: "/path/to/ca-from-overrides.crt",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
Server: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
AuthInfo: clientcmdapi.AuthInfo{
|
|
||||||
Token: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
Server: "https://host-from-overrides.com",
|
|
||||||
CertificateAuthority: "/path/to/ca-from-overrides.crt",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
CertificateAuthority: "/path/to/ca-from-overrides.crt",
|
|
||||||
},
|
|
||||||
AuthInfo: clientcmdapi.AuthInfo{
|
|
||||||
Token: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{
|
|
||||||
ClusterInfo: clientcmdapi.Cluster{
|
|
||||||
Server: "https://host-from-overrides.com",
|
|
||||||
CertificateAuthority: "/path/to/ca-from-overrides.crt",
|
|
||||||
},
|
|
||||||
AuthInfo: clientcmdapi.AuthInfo{
|
|
||||||
Token: "https://host-from-overrides.com",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
overrides: &ConfigOverrides{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tt {
|
|
||||||
expectedServer := "https://host-from-cluster.com"
|
|
||||||
expectedToken := "token-from-cluster"
|
|
||||||
expectedCAFile := "/path/to/ca-from-cluster.crt"
|
|
||||||
|
|
||||||
icc := &inClusterClientConfig{
|
|
||||||
inClusterConfigProvider: func() (*restclient.Config, error) {
|
|
||||||
return &restclient.Config{
|
|
||||||
Host: expectedServer,
|
|
||||||
BearerToken: expectedToken,
|
|
||||||
TLSClientConfig: restclient.TLSClientConfig{
|
|
||||||
CAFile: expectedCAFile,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
overrides: tc.overrides,
|
|
||||||
}
|
|
||||||
|
|
||||||
clientConfig, err := icc.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unxpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if overridenServer := tc.overrides.ClusterInfo.Server; len(overridenServer) > 0 {
|
|
||||||
expectedServer = overridenServer
|
|
||||||
}
|
|
||||||
if overridenToken := tc.overrides.AuthInfo.Token; len(overridenToken) > 0 {
|
|
||||||
expectedToken = overridenToken
|
|
||||||
}
|
|
||||||
if overridenCAFile := tc.overrides.ClusterInfo.CertificateAuthority; len(overridenCAFile) > 0 {
|
|
||||||
expectedCAFile = overridenCAFile
|
|
||||||
}
|
|
||||||
|
|
||||||
if clientConfig.Host != expectedServer {
|
|
||||||
t.Errorf("Expected server %v, got %v", expectedServer, clientConfig.Host)
|
|
||||||
}
|
|
||||||
if clientConfig.BearerToken != expectedToken {
|
|
||||||
t.Errorf("Expected token %v, got %v", expectedToken, clientConfig.BearerToken)
|
|
||||||
}
|
|
||||||
if clientConfig.TLSClientConfig.CAFile != expectedCAFile {
|
|
||||||
t.Errorf("Expected Certificate Authority %v, got %v", expectedCAFile, clientConfig.TLSClientConfig.CAFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchBoolArg(expected, got bool, t *testing.T) {
|
|
||||||
if expected != got {
|
|
||||||
t.Errorf("Expected %v, got %v", expected, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchStringArg(expected, got string, t *testing.T) {
|
|
||||||
if expected != got {
|
|
||||||
t.Errorf("Expected %q, got %q", expected, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchByteArg(expected, got []byte, t *testing.T) {
|
|
||||||
if !reflect.DeepEqual(expected, got) {
|
|
||||||
t.Errorf("Expected %v, got %v", expected, got)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,472 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfigAccess is used by subcommands and methods in this package to load and modify the appropriate config files
|
|
||||||
type ConfigAccess interface {
|
|
||||||
// GetLoadingPrecedence returns the slice of files that should be used for loading and inspecting the config
|
|
||||||
GetLoadingPrecedence() []string
|
|
||||||
// GetStartingConfig returns the config that subcommands should being operating against. It may or may not be merged depending on loading rules
|
|
||||||
GetStartingConfig() (*clientcmdapi.Config, error)
|
|
||||||
// GetDefaultFilename returns the name of the file you should write into (create if necessary), if you're trying to create a new stanza as opposed to updating an existing one.
|
|
||||||
GetDefaultFilename() string
|
|
||||||
// IsExplicitFile indicates whether or not this command is interested in exactly one file. This implementation only ever does that via a flag, but implementations that handle local, global, and flags may have more
|
|
||||||
IsExplicitFile() bool
|
|
||||||
// GetExplicitFile returns the particular file this command is operating against. This implementation only ever has one, but implementations that handle local, global, and flags may have more
|
|
||||||
GetExplicitFile() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PathOptions struct {
|
|
||||||
// GlobalFile is the full path to the file to load as the global (final) option
|
|
||||||
GlobalFile string
|
|
||||||
// EnvVar is the env var name that points to the list of kubeconfig files to load
|
|
||||||
EnvVar string
|
|
||||||
// ExplicitFileFlag is the name of the flag to use for prompting for the kubeconfig file
|
|
||||||
ExplicitFileFlag string
|
|
||||||
|
|
||||||
// GlobalFileSubpath is an optional value used for displaying help
|
|
||||||
GlobalFileSubpath string
|
|
||||||
|
|
||||||
LoadingRules *ClientConfigLoadingRules
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetEnvVarFiles() []string {
|
|
||||||
if len(o.EnvVar) == 0 {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
envVarValue := os.Getenv(o.EnvVar)
|
|
||||||
if len(envVarValue) == 0 {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.SplitList(envVarValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetLoadingPrecedence() []string {
|
|
||||||
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
|
||||||
return envVarFiles
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{o.GlobalFile}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetStartingConfig() (*clientcmdapi.Config, error) {
|
|
||||||
// don't mutate the original
|
|
||||||
loadingRules := *o.LoadingRules
|
|
||||||
loadingRules.Precedence = o.GetLoadingPrecedence()
|
|
||||||
|
|
||||||
clientConfig := NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, &ConfigOverrides{})
|
|
||||||
rawConfig, err := clientConfig.RawConfig()
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return clientcmdapi.NewConfig(), nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &rawConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetDefaultFilename() string {
|
|
||||||
if o.IsExplicitFile() {
|
|
||||||
return o.GetExplicitFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
if envVarFiles := o.GetEnvVarFiles(); len(envVarFiles) > 0 {
|
|
||||||
if len(envVarFiles) == 1 {
|
|
||||||
return envVarFiles[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// if any of the envvar files already exists, return it
|
|
||||||
for _, envVarFile := range envVarFiles {
|
|
||||||
if _, err := os.Stat(envVarFile); err == nil {
|
|
||||||
return envVarFile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, return the last one in the list
|
|
||||||
return envVarFiles[len(envVarFiles)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return o.GlobalFile
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) IsExplicitFile() bool {
|
|
||||||
if len(o.LoadingRules.ExplicitPath) > 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *PathOptions) GetExplicitFile() string {
|
|
||||||
return o.LoadingRules.ExplicitPath
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultPathOptions() *PathOptions {
|
|
||||||
ret := &PathOptions{
|
|
||||||
GlobalFile: RecommendedHomeFile,
|
|
||||||
EnvVar: RecommendedConfigPathEnvVar,
|
|
||||||
ExplicitFileFlag: RecommendedConfigPathFlag,
|
|
||||||
|
|
||||||
GlobalFileSubpath: path.Join(RecommendedHomeDir, RecommendedFileName),
|
|
||||||
|
|
||||||
LoadingRules: NewDefaultClientConfigLoadingRules(),
|
|
||||||
}
|
|
||||||
ret.LoadingRules.DoNotResolvePaths = true
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyConfig takes a Config object, iterates through Clusters, AuthInfos, and Contexts, uses the LocationOfOrigin if specified or
|
|
||||||
// uses the default destination file to write the results into. This results in multiple file reads, but it's very easy to follow.
|
|
||||||
// Preferences and CurrentContext should always be set in the default destination file. Since we can't distinguish between empty and missing values
|
|
||||||
// (no nil strings), we're forced have separate handling for them. In the kubeconfig cases, newConfig should have at most one difference,
|
|
||||||
// that means that this code will only write into a single file. If you want to relativizePaths, you must provide a fully qualified path in any
|
|
||||||
// modified element.
|
|
||||||
func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, relativizePaths bool) error {
|
|
||||||
possibleSources := configAccess.GetLoadingPrecedence()
|
|
||||||
// sort the possible kubeconfig files so we always "lock" in the same order
|
|
||||||
// to avoid deadlock (note: this can fail w/ symlinks, but... come on).
|
|
||||||
sort.Strings(possibleSources)
|
|
||||||
for _, filename := range possibleSources {
|
|
||||||
if err := lockFile(filename); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer unlockFile(filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
startingConfig, err := configAccess.GetStartingConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to find all differences, locate their original files, read a partial config to modify only that stanza and write out the file.
|
|
||||||
// Special case the test for current context and preferences since those always write to the default file.
|
|
||||||
if reflect.DeepEqual(*startingConfig, newConfig) {
|
|
||||||
// nothing to do
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if startingConfig.CurrentContext != newConfig.CurrentContext {
|
|
||||||
if err := writeCurrentContext(configAccess, newConfig.CurrentContext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(startingConfig.Preferences, newConfig.Preferences) {
|
|
||||||
if err := writePreferences(configAccess, newConfig.Preferences); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search every cluster, authInfo, and context. First from new to old for differences, then from old to new for deletions
|
|
||||||
for key, cluster := range newConfig.Clusters {
|
|
||||||
startingCluster, exists := startingConfig.Clusters[key]
|
|
||||||
if !reflect.DeepEqual(cluster, startingCluster) || !exists {
|
|
||||||
destinationFile := cluster.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t := *cluster
|
|
||||||
|
|
||||||
configToWrite.Clusters[key] = &t
|
|
||||||
configToWrite.Clusters[key].LocationOfOrigin = destinationFile
|
|
||||||
if relativizePaths {
|
|
||||||
if err := RelativizeClusterLocalPaths(configToWrite.Clusters[key]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, context := range newConfig.Contexts {
|
|
||||||
startingContext, exists := startingConfig.Contexts[key]
|
|
||||||
if !reflect.DeepEqual(context, startingContext) || !exists {
|
|
||||||
destinationFile := context.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
configToWrite.Contexts[key] = context
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, authInfo := range newConfig.AuthInfos {
|
|
||||||
startingAuthInfo, exists := startingConfig.AuthInfos[key]
|
|
||||||
if !reflect.DeepEqual(authInfo, startingAuthInfo) || !exists {
|
|
||||||
destinationFile := authInfo.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t := *authInfo
|
|
||||||
configToWrite.AuthInfos[key] = &t
|
|
||||||
configToWrite.AuthInfos[key].LocationOfOrigin = destinationFile
|
|
||||||
if relativizePaths {
|
|
||||||
if err := RelativizeAuthInfoLocalPaths(configToWrite.AuthInfos[key]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, cluster := range startingConfig.Clusters {
|
|
||||||
if _, exists := newConfig.Clusters[key]; !exists {
|
|
||||||
destinationFile := cluster.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
delete(configToWrite.Clusters, key)
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, context := range startingConfig.Contexts {
|
|
||||||
if _, exists := newConfig.Contexts[key]; !exists {
|
|
||||||
destinationFile := context.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
delete(configToWrite.Contexts, key)
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, authInfo := range startingConfig.AuthInfos {
|
|
||||||
if _, exists := newConfig.AuthInfos[key]; !exists {
|
|
||||||
destinationFile := authInfo.LocationOfOrigin
|
|
||||||
if len(destinationFile) == 0 {
|
|
||||||
destinationFile = configAccess.GetDefaultFilename()
|
|
||||||
}
|
|
||||||
|
|
||||||
configToWrite, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
delete(configToWrite.AuthInfos, key)
|
|
||||||
|
|
||||||
if err := WriteToFile(*configToWrite, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PersisterForUser(configAccess ConfigAccess, user string) restclient.AuthProviderConfigPersister {
|
|
||||||
return &persister{configAccess, user}
|
|
||||||
}
|
|
||||||
|
|
||||||
type persister struct {
|
|
||||||
configAccess ConfigAccess
|
|
||||||
user string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *persister) Persist(config map[string]string) error {
|
|
||||||
newConfig, err := p.configAccess.GetStartingConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
authInfo, ok := newConfig.AuthInfos[p.user]
|
|
||||||
if ok && authInfo.AuthProvider != nil {
|
|
||||||
authInfo.AuthProvider.Config = config
|
|
||||||
ModifyConfig(p.configAccess, *newConfig, false)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeCurrentContext takes three possible paths.
|
|
||||||
// If newCurrentContext is the same as the startingConfig's current context, then we exit.
|
|
||||||
// If newCurrentContext has a value, then that value is written into the default destination file.
|
|
||||||
// If newCurrentContext is empty, then we find the config file that is setting the CurrentContext and clear the value from that file
|
|
||||||
func writeCurrentContext(configAccess ConfigAccess, newCurrentContext string) error {
|
|
||||||
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if startingConfig.CurrentContext == newCurrentContext {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if configAccess.IsExplicitFile() {
|
|
||||||
file := configAccess.GetExplicitFile()
|
|
||||||
currConfig, err := getConfigFromFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
currConfig.CurrentContext = newCurrentContext
|
|
||||||
if err := WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(newCurrentContext) > 0 {
|
|
||||||
destinationFile := configAccess.GetDefaultFilename()
|
|
||||||
config, err := getConfigFromFile(destinationFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
config.CurrentContext = newCurrentContext
|
|
||||||
|
|
||||||
if err := WriteToFile(*config, destinationFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're supposed to be clearing the current context. We need to find the first spot in the chain that is setting it and clear it
|
|
||||||
for _, file := range configAccess.GetLoadingPrecedence() {
|
|
||||||
if _, err := os.Stat(file); err == nil {
|
|
||||||
currConfig, err := getConfigFromFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(currConfig.CurrentContext) > 0 {
|
|
||||||
currConfig.CurrentContext = newCurrentContext
|
|
||||||
if err := WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("no config found to write context")
|
|
||||||
}
|
|
||||||
|
|
||||||
func writePreferences(configAccess ConfigAccess, newPrefs clientcmdapi.Preferences) error {
|
|
||||||
if startingConfig, err := configAccess.GetStartingConfig(); err != nil {
|
|
||||||
return err
|
|
||||||
} else if reflect.DeepEqual(startingConfig.Preferences, newPrefs) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if configAccess.IsExplicitFile() {
|
|
||||||
file := configAccess.GetExplicitFile()
|
|
||||||
currConfig, err := getConfigFromFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
currConfig.Preferences = newPrefs
|
|
||||||
if err := WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range configAccess.GetLoadingPrecedence() {
|
|
||||||
currConfig, err := getConfigFromFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(currConfig.Preferences, newPrefs) {
|
|
||||||
currConfig.Preferences = newPrefs
|
|
||||||
if err := WriteToFile(*currConfig, file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("no config found to write preferences")
|
|
||||||
}
|
|
||||||
|
|
||||||
// getConfigFromFile tries to read a kubeconfig file and if it can't, returns an error. One exception, missing files result in empty configs, not an error.
|
|
||||||
func getConfigFromFile(filename string) (*clientcmdapi.Config, error) {
|
|
||||||
config, err := LoadFromFile(filename)
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if config == nil {
|
|
||||||
config = clientcmdapi.NewConfig()
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetConfigFromFileOrDie tries to read a kubeconfig file and if it can't, it calls exit. One exception, missing files result in empty configs, not an exit
|
|
||||||
func GetConfigFromFileOrDie(filename string) *clientcmdapi.Config {
|
|
||||||
config, err := getConfigFromFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
glog.FatalDepth(1, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd provides one stop shopping for building a working client from a fixed config,
|
|
||||||
from a .kubeconfig file, from command line flags, or from any merged combination.
|
|
||||||
|
|
||||||
Sample usage from merged .kubeconfig files (local directory, home directory)
|
|
||||||
|
|
||||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
|
||||||
// if you want to change the loading rules (which files in which order), you can do so here
|
|
||||||
|
|
||||||
configOverrides := &clientcmd.ConfigOverrides{}
|
|
||||||
// if you want to change override values or bind them to flags, there are methods to help you
|
|
||||||
|
|
||||||
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
|
|
||||||
config, err := kubeConfig.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
// Do something
|
|
||||||
}
|
|
||||||
client, err := metav1.New(config)
|
|
||||||
// ...
|
|
||||||
*/
|
|
||||||
package clientcmd // import "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2016 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseTimeout returns a parsed duration from a string
|
|
||||||
// A duration string value must be a positive integer, optionally followed by a corresponding time unit (s|m|h).
|
|
||||||
func ParseTimeout(duration string) (time.Duration, error) {
|
|
||||||
if i, err := strconv.ParseInt(duration, 10, 64); err == nil && i >= 0 {
|
|
||||||
return (time.Duration(i) * time.Second), nil
|
|
||||||
}
|
|
||||||
if requestTimeout, err := time.ParseDuration(duration); err == nil {
|
|
||||||
return requestTimeout, nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("Invalid timeout value. Timeout must be a single integer in seconds, or an integer followed by a corresponding time unit (e.g. 1s | 2m | 3h)")
|
|
||||||
}
|
|
|
@ -1,609 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
goruntime "runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/imdario/mergo"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
|
|
||||||
"k8s.io/kubernetes/pkg/util/homedir"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
RecommendedConfigPathFlag = "kubeconfig"
|
|
||||||
RecommendedConfigPathEnvVar = "KUBECONFIG"
|
|
||||||
RecommendedHomeDir = ".kube"
|
|
||||||
RecommendedFileName = "config"
|
|
||||||
RecommendedSchemaName = "schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
var RecommendedHomeFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedFileName)
|
|
||||||
var RecommendedSchemaFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedSchemaName)
|
|
||||||
|
|
||||||
// currentMigrationRules returns a map that holds the history of recommended home directories used in previous versions.
|
|
||||||
// Any future changes to RecommendedHomeFile and related are expected to add a migration rule here, in order to make
|
|
||||||
// sure existing config files are migrated to their new locations properly.
|
|
||||||
func currentMigrationRules() map[string]string {
|
|
||||||
oldRecommendedHomeFile := path.Join(os.Getenv("HOME"), "/.kube/.kubeconfig")
|
|
||||||
oldRecommendedWindowsHomeFile := path.Join(os.Getenv("HOME"), RecommendedHomeDir, RecommendedFileName)
|
|
||||||
|
|
||||||
migrationRules := map[string]string{}
|
|
||||||
migrationRules[RecommendedHomeFile] = oldRecommendedHomeFile
|
|
||||||
if goruntime.GOOS == "windows" {
|
|
||||||
migrationRules[RecommendedHomeFile] = oldRecommendedWindowsHomeFile
|
|
||||||
}
|
|
||||||
return migrationRules
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientConfigLoader interface {
|
|
||||||
ConfigAccess
|
|
||||||
// IsDefaultConfig returns true if the returned config matches the defaults.
|
|
||||||
IsDefaultConfig(*restclient.Config) bool
|
|
||||||
// Load returns the latest config
|
|
||||||
Load() (*clientcmdapi.Config, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type KubeconfigGetter func() (*clientcmdapi.Config, error)
|
|
||||||
|
|
||||||
type ClientConfigGetter struct {
|
|
||||||
kubeconfigGetter KubeconfigGetter
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientConfigGetter implements the ClientConfigLoader interface.
|
|
||||||
var _ ClientConfigLoader = &ClientConfigGetter{}
|
|
||||||
|
|
||||||
func (g *ClientConfigGetter) Load() (*clientcmdapi.Config, error) {
|
|
||||||
return g.kubeconfigGetter()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *ClientConfigGetter) GetLoadingPrecedence() []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (g *ClientConfigGetter) GetStartingConfig() (*clientcmdapi.Config, error) {
|
|
||||||
return g.kubeconfigGetter()
|
|
||||||
}
|
|
||||||
func (g *ClientConfigGetter) GetDefaultFilename() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
func (g *ClientConfigGetter) IsExplicitFile() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
func (g *ClientConfigGetter) GetExplicitFile() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
func (g *ClientConfigGetter) IsDefaultConfig(config *restclient.Config) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config
|
|
||||||
// Callers can put the chain together however they want, but we'd recommend:
|
|
||||||
// EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath
|
|
||||||
// ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if thie file is not present
|
|
||||||
type ClientConfigLoadingRules struct {
|
|
||||||
ExplicitPath string
|
|
||||||
Precedence []string
|
|
||||||
|
|
||||||
// MigrationRules is a map of destination files to source files. If a destination file is not present, then the source file is checked.
|
|
||||||
// If the source file is present, then it is copied to the destination file BEFORE any further loading happens.
|
|
||||||
MigrationRules map[string]string
|
|
||||||
|
|
||||||
// DoNotResolvePaths indicates whether or not to resolve paths with respect to the originating files. This is phrased as a negative so
|
|
||||||
// that a default object that doesn't set this will usually get the behavior it wants.
|
|
||||||
DoNotResolvePaths bool
|
|
||||||
|
|
||||||
// DefaultClientConfig is an optional field indicating what rules to use to calculate a default configuration.
|
|
||||||
// This should match the overrides passed in to ClientConfig loader.
|
|
||||||
DefaultClientConfig ClientConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientConfigLoadingRules implements the ClientConfigLoader interface.
|
|
||||||
var _ ClientConfigLoader = &ClientConfigLoadingRules{}
|
|
||||||
|
|
||||||
// NewDefaultClientConfigLoadingRules returns a ClientConfigLoadingRules object with default fields filled in. You are not required to
|
|
||||||
// use this constructor
|
|
||||||
func NewDefaultClientConfigLoadingRules() *ClientConfigLoadingRules {
|
|
||||||
chain := []string{}
|
|
||||||
|
|
||||||
envVarFiles := os.Getenv(RecommendedConfigPathEnvVar)
|
|
||||||
if len(envVarFiles) != 0 {
|
|
||||||
chain = append(chain, filepath.SplitList(envVarFiles)...)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
chain = append(chain, RecommendedHomeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ClientConfigLoadingRules{
|
|
||||||
Precedence: chain,
|
|
||||||
MigrationRules: currentMigrationRules(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load starts by running the MigrationRules and then
|
|
||||||
// takes the loading rules and returns a Config object based on following rules.
|
|
||||||
// if the ExplicitPath, return the unmerged explicit file
|
|
||||||
// Otherwise, return a merged config based on the Precedence slice
|
|
||||||
// A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored.
|
|
||||||
// Read errors or files with non-deserializable content produce errors.
|
|
||||||
// The first file to set a particular map key wins and map key's value is never changed.
|
|
||||||
// BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed.
|
|
||||||
// This results in some odd looking logic to merge in one direction, merge in the other, and then merge the two.
|
|
||||||
// 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.
|
|
||||||
// Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder
|
|
||||||
// and only absolute file paths are returned.
|
|
||||||
func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
|
|
||||||
if err := rules.Migrate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
errlist := []error{}
|
|
||||||
|
|
||||||
kubeConfigFiles := []string{}
|
|
||||||
|
|
||||||
// Make sure a file we were explicitly told to use exists
|
|
||||||
if len(rules.ExplicitPath) > 0 {
|
|
||||||
if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeconfigs := []*clientcmdapi.Config{}
|
|
||||||
// read and cache the config files so that we only look at them once
|
|
||||||
for _, filename := range kubeConfigFiles {
|
|
||||||
if len(filename) == 0 {
|
|
||||||
// no work to do
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := LoadFromFile(filename)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
// skip missing files
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
errlist = append(errlist, fmt.Errorf("Error loading config file \"%s\": %v", filename, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeconfigs = append(kubeconfigs, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// first merge all of our maps
|
|
||||||
mapConfig := clientcmdapi.NewConfig()
|
|
||||||
|
|
||||||
for _, kubeconfig := range kubeconfigs {
|
|
||||||
mergo.Merge(mapConfig, kubeconfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge all of the struct values in the reverse order so that priority is given correctly
|
|
||||||
// errors are not added to the list the second time
|
|
||||||
nonMapConfig := clientcmdapi.NewConfig()
|
|
||||||
for i := len(kubeconfigs) - 1; i >= 0; i-- {
|
|
||||||
kubeconfig := kubeconfigs[i]
|
|
||||||
mergo.Merge(nonMapConfig, kubeconfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
|
|
||||||
// get the values we expect.
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
mergo.Merge(config, mapConfig)
|
|
||||||
mergo.Merge(config, nonMapConfig)
|
|
||||||
|
|
||||||
if rules.ResolvePaths() {
|
|
||||||
if err := ResolveLocalPaths(config); err != nil {
|
|
||||||
errlist = append(errlist, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return config, utilerrors.NewAggregate(errlist)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate uses the MigrationRules map. If a destination file is not present, then the source file is checked.
|
|
||||||
// If the source file is present, then it is copied to the destination file BEFORE any further loading happens.
|
|
||||||
func (rules *ClientConfigLoadingRules) Migrate() error {
|
|
||||||
if rules.MigrationRules == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for destination, source := range rules.MigrationRules {
|
|
||||||
if _, err := os.Stat(destination); err == nil {
|
|
||||||
// if the destination already exists, do nothing
|
|
||||||
continue
|
|
||||||
} else if os.IsPermission(err) {
|
|
||||||
// if we can't access the file, skip it
|
|
||||||
continue
|
|
||||||
} else if !os.IsNotExist(err) {
|
|
||||||
// if we had an error other than non-existence, fail
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if sourceInfo, err := os.Stat(source); err != nil {
|
|
||||||
if os.IsNotExist(err) || os.IsPermission(err) {
|
|
||||||
// if the source file doesn't exist or we can't access it, there's no work to do.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we had an error other than non-existence, fail
|
|
||||||
return err
|
|
||||||
} else if sourceInfo.IsDir() {
|
|
||||||
return fmt.Errorf("cannot migrate %v to %v because it is a directory", source, destination)
|
|
||||||
}
|
|
||||||
|
|
||||||
in, err := os.Open(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer in.Close()
|
|
||||||
out, err := os.Create(destination)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer out.Close()
|
|
||||||
|
|
||||||
if _, err = io.Copy(out, in); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLoadingPrecedence implements ConfigAccess
|
|
||||||
func (rules *ClientConfigLoadingRules) GetLoadingPrecedence() []string {
|
|
||||||
return rules.Precedence
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStartingConfig implements ConfigAccess
|
|
||||||
func (rules *ClientConfigLoadingRules) GetStartingConfig() (*clientcmdapi.Config, error) {
|
|
||||||
clientConfig := NewNonInteractiveDeferredLoadingClientConfig(rules, &ConfigOverrides{})
|
|
||||||
rawConfig, err := clientConfig.RawConfig()
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return clientcmdapi.NewConfig(), nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &rawConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDefaultFilename implements ConfigAccess
|
|
||||||
func (rules *ClientConfigLoadingRules) GetDefaultFilename() string {
|
|
||||||
// Explicit file if we have one.
|
|
||||||
if rules.IsExplicitFile() {
|
|
||||||
return rules.GetExplicitFile()
|
|
||||||
}
|
|
||||||
// Otherwise, first existing file from precedence.
|
|
||||||
for _, filename := range rules.GetLoadingPrecedence() {
|
|
||||||
if _, err := os.Stat(filename); err == nil {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If none exists, use the first from precedence.
|
|
||||||
if len(rules.Precedence) > 0 {
|
|
||||||
return rules.Precedence[0]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsExplicitFile implements ConfigAccess
|
|
||||||
func (rules *ClientConfigLoadingRules) IsExplicitFile() bool {
|
|
||||||
return len(rules.ExplicitPath) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExplicitFile implements ConfigAccess
|
|
||||||
func (rules *ClientConfigLoadingRules) GetExplicitFile() string {
|
|
||||||
return rules.ExplicitPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDefaultConfig returns true if the provided configuration matches the default
|
|
||||||
func (rules *ClientConfigLoadingRules) IsDefaultConfig(config *restclient.Config) bool {
|
|
||||||
if rules.DefaultClientConfig == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defaultConfig, err := rules.DefaultClientConfig.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return reflect.DeepEqual(config, defaultConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadFromFile takes a filename and deserializes the contents into Config object
|
|
||||||
func LoadFromFile(filename string) (*clientcmdapi.Config, error) {
|
|
||||||
kubeconfigBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config, err := Load(kubeconfigBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
glog.V(6).Infoln("Config loaded from file", filename)
|
|
||||||
|
|
||||||
// set LocationOfOrigin on every Cluster, User, and Context
|
|
||||||
for key, obj := range config.AuthInfos {
|
|
||||||
obj.LocationOfOrigin = filename
|
|
||||||
config.AuthInfos[key] = obj
|
|
||||||
}
|
|
||||||
for key, obj := range config.Clusters {
|
|
||||||
obj.LocationOfOrigin = filename
|
|
||||||
config.Clusters[key] = obj
|
|
||||||
}
|
|
||||||
for key, obj := range config.Contexts {
|
|
||||||
obj.LocationOfOrigin = filename
|
|
||||||
config.Contexts[key] = obj
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.AuthInfos == nil {
|
|
||||||
config.AuthInfos = map[string]*clientcmdapi.AuthInfo{}
|
|
||||||
}
|
|
||||||
if config.Clusters == nil {
|
|
||||||
config.Clusters = map[string]*clientcmdapi.Cluster{}
|
|
||||||
}
|
|
||||||
if config.Contexts == nil {
|
|
||||||
config.Contexts = map[string]*clientcmdapi.Context{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load takes a byte slice and deserializes the contents into Config object.
|
|
||||||
// Encapsulates deserialization without assuming the source is a file.
|
|
||||||
func Load(data []byte) (*clientcmdapi.Config, error) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
// if there's no data in a file, return the default object instead of failing (DecodeInto reject empty input)
|
|
||||||
if len(data) == 0 {
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
decoded, _, err := clientcmdlatest.Codec.Decode(data, &schema.GroupVersionKind{Version: clientcmdlatest.Version, Kind: "Config"}, config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return decoded.(*clientcmdapi.Config), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteToFile serializes the config to yaml and writes it out to a file. If not present, it creates the file with the mode 0600. If it is present
|
|
||||||
// it stomps the contents
|
|
||||||
func WriteToFile(config clientcmdapi.Config, filename string) error {
|
|
||||||
content, err := Write(config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
||||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filename, content, 0600); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lockFile(filename string) error {
|
|
||||||
// TODO: find a way to do this with actual file locks. Will
|
|
||||||
// probably need seperate solution for windows and linux.
|
|
||||||
|
|
||||||
// Make sure the dir exists before we try to create a lock file.
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
||||||
if err = os.MkdirAll(dir, 0755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(lockName(filename), os.O_CREATE|os.O_EXCL, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unlockFile(filename string) error {
|
|
||||||
return os.Remove(lockName(filename))
|
|
||||||
}
|
|
||||||
|
|
||||||
func lockName(filename string) string {
|
|
||||||
return filename + ".lock"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write serializes the config to yaml.
|
|
||||||
// Encapsulates serialization without assuming the destination is a file.
|
|
||||||
func Write(config clientcmdapi.Config) ([]byte, error) {
|
|
||||||
return runtime.Encode(clientcmdlatest.Codec, &config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rules ClientConfigLoadingRules) ResolvePaths() bool {
|
|
||||||
return !rules.DoNotResolvePaths
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveLocalPaths resolves all relative paths in the config object with respect to the stanza's LocationOfOrigin
|
|
||||||
// this cannot be done directly inside of LoadFromFile because doing so there would make it impossible to load a file without
|
|
||||||
// modification of its contents.
|
|
||||||
func ResolveLocalPaths(config *clientcmdapi.Config) error {
|
|
||||||
for _, cluster := range config.Clusters {
|
|
||||||
if len(cluster.LocationOfOrigin) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
base, err := filepath.Abs(filepath.Dir(cluster.LocationOfOrigin))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Could not determine the absolute path of config file %s: %v", cluster.LocationOfOrigin, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ResolvePaths(GetClusterFileReferences(cluster), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, authInfo := range config.AuthInfos {
|
|
||||||
if len(authInfo.LocationOfOrigin) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
base, err := filepath.Abs(filepath.Dir(authInfo.LocationOfOrigin))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Could not determine the absolute path of config file %s: %v", authInfo.LocationOfOrigin, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ResolvePaths(GetAuthInfoFileReferences(authInfo), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RelativizeClusterLocalPaths first absolutizes the paths by calling ResolveLocalPaths. This assumes that any NEW path is already
|
|
||||||
// absolute, but any existing path will be resolved relative to LocationOfOrigin
|
|
||||||
func RelativizeClusterLocalPaths(cluster *clientcmdapi.Cluster) error {
|
|
||||||
if len(cluster.LocationOfOrigin) == 0 {
|
|
||||||
return fmt.Errorf("no location of origin for %s", cluster.Server)
|
|
||||||
}
|
|
||||||
base, err := filepath.Abs(filepath.Dir(cluster.LocationOfOrigin))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not determine the absolute path of config file %s: %v", cluster.LocationOfOrigin, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ResolvePaths(GetClusterFileReferences(cluster), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := RelativizePathWithNoBacksteps(GetClusterFileReferences(cluster), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RelativizeAuthInfoLocalPaths first absolutizes the paths by calling ResolveLocalPaths. This assumes that any NEW path is already
|
|
||||||
// absolute, but any existing path will be resolved relative to LocationOfOrigin
|
|
||||||
func RelativizeAuthInfoLocalPaths(authInfo *clientcmdapi.AuthInfo) error {
|
|
||||||
if len(authInfo.LocationOfOrigin) == 0 {
|
|
||||||
return fmt.Errorf("no location of origin for %v", authInfo)
|
|
||||||
}
|
|
||||||
base, err := filepath.Abs(filepath.Dir(authInfo.LocationOfOrigin))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not determine the absolute path of config file %s: %v", authInfo.LocationOfOrigin, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ResolvePaths(GetAuthInfoFileReferences(authInfo), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := RelativizePathWithNoBacksteps(GetAuthInfoFileReferences(authInfo), base); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RelativizeConfigPaths(config *clientcmdapi.Config, base string) error {
|
|
||||||
return RelativizePathWithNoBacksteps(GetConfigFileReferences(config), base)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolveConfigPaths(config *clientcmdapi.Config, base string) error {
|
|
||||||
return ResolvePaths(GetConfigFileReferences(config), base)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfigFileReferences(config *clientcmdapi.Config) []*string {
|
|
||||||
refs := []*string{}
|
|
||||||
|
|
||||||
for _, cluster := range config.Clusters {
|
|
||||||
refs = append(refs, GetClusterFileReferences(cluster)...)
|
|
||||||
}
|
|
||||||
for _, authInfo := range config.AuthInfos {
|
|
||||||
refs = append(refs, GetAuthInfoFileReferences(authInfo)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return refs
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetClusterFileReferences(cluster *clientcmdapi.Cluster) []*string {
|
|
||||||
return []*string{&cluster.CertificateAuthority}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAuthInfoFileReferences(authInfo *clientcmdapi.AuthInfo) []*string {
|
|
||||||
return []*string{&authInfo.ClientCertificate, &authInfo.ClientKey, &authInfo.TokenFile}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolvePaths updates the given refs to be absolute paths, relative to the given base directory
|
|
||||||
func ResolvePaths(refs []*string, base string) error {
|
|
||||||
for _, ref := range refs {
|
|
||||||
// Don't resolve empty paths
|
|
||||||
if len(*ref) > 0 {
|
|
||||||
// Don't resolve absolute paths
|
|
||||||
if !filepath.IsAbs(*ref) {
|
|
||||||
*ref = filepath.Join(base, *ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RelativizePathWithNoBacksteps updates the given refs to be relative paths, relative to the given base directory as long as they do not require backsteps.
|
|
||||||
// Any path requiring a backstep is left as-is as long it is absolute. Any non-absolute path that can't be relativized produces an error
|
|
||||||
func RelativizePathWithNoBacksteps(refs []*string, base string) error {
|
|
||||||
for _, ref := range refs {
|
|
||||||
// Don't relativize empty paths
|
|
||||||
if len(*ref) > 0 {
|
|
||||||
rel, err := MakeRelative(*ref, base)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have a backstep, don't mess with the path
|
|
||||||
if strings.HasPrefix(rel, "../") {
|
|
||||||
if filepath.IsAbs(*ref) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("%v requires backsteps and is not absolute", *ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
*ref = rel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeRelative(path, base string) (string, error) {
|
|
||||||
if len(path) > 0 {
|
|
||||||
rel, err := filepath.Rel(base, path)
|
|
||||||
if err != nil {
|
|
||||||
return path, err
|
|
||||||
}
|
|
||||||
return rel, nil
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
|
@ -1,579 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
testConfigAlfa = clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"red-user": {Token: "red-token"}},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"cow-cluster": {Server: "http://cow.org:8080"}},
|
|
||||||
Contexts: map[string]*clientcmdapi.Context{
|
|
||||||
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"}},
|
|
||||||
}
|
|
||||||
testConfigBravo = clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"black-user": {Token: "black-token"}},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"pig-cluster": {Server: "http://pig.org:8080"}},
|
|
||||||
Contexts: map[string]*clientcmdapi.Context{
|
|
||||||
"queen-anne-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"}},
|
|
||||||
}
|
|
||||||
testConfigCharlie = clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"green-user": {Token: "green-token"}},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"horse-cluster": {Server: "http://horse.org:8080"}},
|
|
||||||
Contexts: map[string]*clientcmdapi.Context{
|
|
||||||
"shaker-context": {AuthInfo: "green-user", Cluster: "horse-cluster", Namespace: "chisel-ns"}},
|
|
||||||
}
|
|
||||||
testConfigDelta = clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"blue-user": {Token: "blue-token"}},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"chicken-cluster": {Server: "http://chicken.org:8080"}},
|
|
||||||
Contexts: map[string]*clientcmdapi.Context{
|
|
||||||
"gothic-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster", Namespace: "plane-ns"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
testConfigConflictAlfa = clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"red-user": {Token: "a-different-red-token"},
|
|
||||||
"yellow-user": {Token: "yellow-token"}},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"cow-cluster": {Server: "http://a-different-cow.org:8080", InsecureSkipTLSVerify: true},
|
|
||||||
"donkey-cluster": {Server: "http://donkey.org:8080", InsecureSkipTLSVerify: true}},
|
|
||||||
CurrentContext: "federal-context",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNonExistentCommandLineFile(t *testing.T) {
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
ExplicitPath: "bogus_file",
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected error for missing command-line file, got none")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "bogus_file") {
|
|
||||||
t.Fatalf("Expected error about 'bogus_file', got %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToleratingMissingFiles(t *testing.T) {
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
Precedence: []string{"bogus1", "bogus2", "bogus3"},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorReadingFile(t *testing.T) {
|
|
||||||
commandLineFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(commandLineFile.Name())
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(commandLineFile.Name(), []byte("bogus value"), 0644); err != nil {
|
|
||||||
t.Fatalf("Error creating tempfile: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
ExplicitPath: commandLineFile.Name(),
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := loadingRules.Load()
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected error for unloadable file, got none")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), commandLineFile.Name()) {
|
|
||||||
t.Fatalf("Expected error about '%s', got %s", commandLineFile.Name(), err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorReadingNonFile(t *testing.T) {
|
|
||||||
tmpdir, err := ioutil.TempDir("", "")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Couldn't create tmpdir")
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tmpdir)
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
ExplicitPath: tmpdir,
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = loadingRules.Load()
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected error for non-file, got none")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), tmpdir) {
|
|
||||||
t.Fatalf("Expected error about '%s', got %s", tmpdir, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConflictingCurrentContext(t *testing.T) {
|
|
||||||
commandLineFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(commandLineFile.Name())
|
|
||||||
envVarFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(envVarFile.Name())
|
|
||||||
|
|
||||||
mockCommandLineConfig := clientcmdapi.Config{
|
|
||||||
CurrentContext: "any-context-value",
|
|
||||||
}
|
|
||||||
mockEnvVarConfig := clientcmdapi.Config{
|
|
||||||
CurrentContext: "a-different-context",
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteToFile(mockCommandLineConfig, commandLineFile.Name())
|
|
||||||
WriteToFile(mockEnvVarConfig, envVarFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
ExplicitPath: commandLineFile.Name(),
|
|
||||||
Precedence: []string{envVarFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if mergedConfig.CurrentContext != mockCommandLineConfig.CurrentContext {
|
|
||||||
t.Errorf("expected %v, got %v", mockCommandLineConfig.CurrentContext, mergedConfig.CurrentContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoadingEmptyMaps(t *testing.T) {
|
|
||||||
configFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(configFile.Name())
|
|
||||||
|
|
||||||
mockConfig := clientcmdapi.Config{
|
|
||||||
CurrentContext: "any-context-value",
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteToFile(mockConfig, configFile.Name())
|
|
||||||
|
|
||||||
config, err := LoadFromFile(configFile.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Clusters == nil {
|
|
||||||
t.Error("expected config.Clusters to be non-nil")
|
|
||||||
}
|
|
||||||
if config.AuthInfos == nil {
|
|
||||||
t.Error("expected config.AuthInfos to be non-nil")
|
|
||||||
}
|
|
||||||
if config.Contexts == nil {
|
|
||||||
t.Error("expected config.Contexts to be non-nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResolveRelativePaths(t *testing.T) {
|
|
||||||
pathResolutionConfig1 := clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"relative-user-1": {ClientCertificate: "relative/client/cert", ClientKey: "../relative/client/key"},
|
|
||||||
"absolute-user-1": {ClientCertificate: "/absolute/client/cert", ClientKey: "/absolute/client/key"},
|
|
||||||
},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"relative-server-1": {CertificateAuthority: "../relative/ca"},
|
|
||||||
"absolute-server-1": {CertificateAuthority: "/absolute/ca"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
pathResolutionConfig2 := clientcmdapi.Config{
|
|
||||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
||||||
"relative-user-2": {ClientCertificate: "relative/client/cert2", ClientKey: "../relative/client/key2"},
|
|
||||||
"absolute-user-2": {ClientCertificate: "/absolute/client/cert2", ClientKey: "/absolute/client/key2"},
|
|
||||||
},
|
|
||||||
Clusters: map[string]*clientcmdapi.Cluster{
|
|
||||||
"relative-server-2": {CertificateAuthority: "../relative/ca2"},
|
|
||||||
"absolute-server-2": {CertificateAuthority: "/absolute/ca2"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
configDir1, _ := ioutil.TempDir("", "")
|
|
||||||
defer os.RemoveAll(configDir1)
|
|
||||||
configFile1 := path.Join(configDir1, ".kubeconfig")
|
|
||||||
configDir1, _ = filepath.Abs(configDir1)
|
|
||||||
|
|
||||||
configDir2, _ := ioutil.TempDir("", "")
|
|
||||||
defer os.RemoveAll(configDir2)
|
|
||||||
configDir2, _ = ioutil.TempDir(configDir2, "")
|
|
||||||
configFile2 := path.Join(configDir2, ".kubeconfig")
|
|
||||||
configDir2, _ = filepath.Abs(configDir2)
|
|
||||||
|
|
||||||
WriteToFile(pathResolutionConfig1, configFile1)
|
|
||||||
WriteToFile(pathResolutionConfig2, configFile2)
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
Precedence: []string{configFile1, configFile2},
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
foundClusterCount := 0
|
|
||||||
for key, cluster := range mergedConfig.Clusters {
|
|
||||||
if key == "relative-server-1" {
|
|
||||||
foundClusterCount++
|
|
||||||
matchStringArg(path.Join(configDir1, pathResolutionConfig1.Clusters["relative-server-1"].CertificateAuthority), cluster.CertificateAuthority, t)
|
|
||||||
}
|
|
||||||
if key == "relative-server-2" {
|
|
||||||
foundClusterCount++
|
|
||||||
matchStringArg(path.Join(configDir2, pathResolutionConfig2.Clusters["relative-server-2"].CertificateAuthority), cluster.CertificateAuthority, t)
|
|
||||||
}
|
|
||||||
if key == "absolute-server-1" {
|
|
||||||
foundClusterCount++
|
|
||||||
matchStringArg(pathResolutionConfig1.Clusters["absolute-server-1"].CertificateAuthority, cluster.CertificateAuthority, t)
|
|
||||||
}
|
|
||||||
if key == "absolute-server-2" {
|
|
||||||
foundClusterCount++
|
|
||||||
matchStringArg(pathResolutionConfig2.Clusters["absolute-server-2"].CertificateAuthority, cluster.CertificateAuthority, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if foundClusterCount != 4 {
|
|
||||||
t.Errorf("Expected 4 clusters, found %v: %v", foundClusterCount, mergedConfig.Clusters)
|
|
||||||
}
|
|
||||||
|
|
||||||
foundAuthInfoCount := 0
|
|
||||||
for key, authInfo := range mergedConfig.AuthInfos {
|
|
||||||
if key == "relative-user-1" {
|
|
||||||
foundAuthInfoCount++
|
|
||||||
matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientCertificate), authInfo.ClientCertificate, t)
|
|
||||||
matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientKey), authInfo.ClientKey, t)
|
|
||||||
}
|
|
||||||
if key == "relative-user-2" {
|
|
||||||
foundAuthInfoCount++
|
|
||||||
matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientCertificate), authInfo.ClientCertificate, t)
|
|
||||||
matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientKey), authInfo.ClientKey, t)
|
|
||||||
}
|
|
||||||
if key == "absolute-user-1" {
|
|
||||||
foundAuthInfoCount++
|
|
||||||
matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientCertificate, authInfo.ClientCertificate, t)
|
|
||||||
matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientKey, authInfo.ClientKey, t)
|
|
||||||
}
|
|
||||||
if key == "absolute-user-2" {
|
|
||||||
foundAuthInfoCount++
|
|
||||||
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientCertificate, authInfo.ClientCertificate, t)
|
|
||||||
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientKey, authInfo.ClientKey, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if foundAuthInfoCount != 4 {
|
|
||||||
t.Errorf("Expected 4 users, found %v: %v", foundAuthInfoCount, mergedConfig.AuthInfos)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigratingFile(t *testing.T) {
|
|
||||||
sourceFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(sourceFile.Name())
|
|
||||||
destinationFile, _ := ioutil.TempFile("", "")
|
|
||||||
// delete the file so that we'll write to it
|
|
||||||
os.Remove(destinationFile.Name())
|
|
||||||
|
|
||||||
WriteToFile(testConfigAlfa, sourceFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := loadingRules.Load(); err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the load should have recreated this file
|
|
||||||
defer os.Remove(destinationFile.Name())
|
|
||||||
|
|
||||||
sourceContent, err := ioutil.ReadFile(sourceFile.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(sourceContent, destinationContent) {
|
|
||||||
t.Errorf("source and destination do not match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigratingFileLeaveExistingFileAlone(t *testing.T) {
|
|
||||||
sourceFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(sourceFile.Name())
|
|
||||||
destinationFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(destinationFile.Name())
|
|
||||||
|
|
||||||
WriteToFile(testConfigAlfa, sourceFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := loadingRules.Load(); err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(destinationContent) > 0 {
|
|
||||||
t.Errorf("destination should not have been touched")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigratingFileSourceMissingSkip(t *testing.T) {
|
|
||||||
sourceFilename := "some-missing-file"
|
|
||||||
destinationFile, _ := ioutil.TempFile("", "")
|
|
||||||
// delete the file so that we'll write to it
|
|
||||||
os.Remove(destinationFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
MigrationRules: map[string]string{destinationFile.Name(): sourceFilename},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := loadingRules.Load(); err != nil {
|
|
||||||
t.Errorf("unexpected error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(destinationFile.Name()); !os.IsNotExist(err) {
|
|
||||||
t.Errorf("destination should not exist")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFileLocking(t *testing.T) {
|
|
||||||
f, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(f.Name())
|
|
||||||
|
|
||||||
err := lockFile(f.Name())
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error while locking file: %v", err)
|
|
||||||
}
|
|
||||||
defer unlockFile(f.Name())
|
|
||||||
|
|
||||||
err = lockFile(f.Name())
|
|
||||||
if err == nil {
|
|
||||||
t.Error("expected error while locking file.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_noMergingOnExplicitPaths() {
|
|
||||||
commandLineFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(commandLineFile.Name())
|
|
||||||
envVarFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(envVarFile.Name())
|
|
||||||
|
|
||||||
WriteToFile(testConfigAlfa, commandLineFile.Name())
|
|
||||||
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
ExplicitPath: commandLineFile.Name(),
|
|
||||||
Precedence: []string{envVarFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
|
||||||
|
|
||||||
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
output, err := yaml.JSONToYAML(json)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%v", string(output))
|
|
||||||
// Output:
|
|
||||||
// apiVersion: v1
|
|
||||||
// clusters:
|
|
||||||
// - cluster:
|
|
||||||
// server: http://cow.org:8080
|
|
||||||
// name: cow-cluster
|
|
||||||
// contexts:
|
|
||||||
// - context:
|
|
||||||
// cluster: cow-cluster
|
|
||||||
// namespace: hammer-ns
|
|
||||||
// user: red-user
|
|
||||||
// name: federal-context
|
|
||||||
// current-context: ""
|
|
||||||
// kind: Config
|
|
||||||
// preferences: {}
|
|
||||||
// users:
|
|
||||||
// - name: red-user
|
|
||||||
// user:
|
|
||||||
// token: red-token
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_mergingSomeWithConflict() {
|
|
||||||
commandLineFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(commandLineFile.Name())
|
|
||||||
envVarFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(envVarFile.Name())
|
|
||||||
|
|
||||||
WriteToFile(testConfigAlfa, commandLineFile.Name())
|
|
||||||
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
Precedence: []string{commandLineFile.Name(), envVarFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
|
||||||
|
|
||||||
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
output, err := yaml.JSONToYAML(json)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%v", string(output))
|
|
||||||
// Output:
|
|
||||||
// apiVersion: v1
|
|
||||||
// clusters:
|
|
||||||
// - cluster:
|
|
||||||
// server: http://cow.org:8080
|
|
||||||
// name: cow-cluster
|
|
||||||
// - cluster:
|
|
||||||
// insecure-skip-tls-verify: true
|
|
||||||
// server: http://donkey.org:8080
|
|
||||||
// name: donkey-cluster
|
|
||||||
// contexts:
|
|
||||||
// - context:
|
|
||||||
// cluster: cow-cluster
|
|
||||||
// namespace: hammer-ns
|
|
||||||
// user: red-user
|
|
||||||
// name: federal-context
|
|
||||||
// current-context: federal-context
|
|
||||||
// kind: Config
|
|
||||||
// preferences: {}
|
|
||||||
// users:
|
|
||||||
// - name: red-user
|
|
||||||
// user:
|
|
||||||
// token: red-token
|
|
||||||
// - name: yellow-user
|
|
||||||
// user:
|
|
||||||
// token: yellow-token
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_mergingEverythingNoConflicts() {
|
|
||||||
commandLineFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(commandLineFile.Name())
|
|
||||||
envVarFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(envVarFile.Name())
|
|
||||||
currentDirFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(currentDirFile.Name())
|
|
||||||
homeDirFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(homeDirFile.Name())
|
|
||||||
|
|
||||||
WriteToFile(testConfigAlfa, commandLineFile.Name())
|
|
||||||
WriteToFile(testConfigBravo, envVarFile.Name())
|
|
||||||
WriteToFile(testConfigCharlie, currentDirFile.Name())
|
|
||||||
WriteToFile(testConfigDelta, homeDirFile.Name())
|
|
||||||
|
|
||||||
loadingRules := ClientConfigLoadingRules{
|
|
||||||
Precedence: []string{commandLineFile.Name(), envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()},
|
|
||||||
}
|
|
||||||
|
|
||||||
mergedConfig, err := loadingRules.Load()
|
|
||||||
|
|
||||||
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
output, err := yaml.JSONToYAML(json)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%v", string(output))
|
|
||||||
// Output:
|
|
||||||
// apiVersion: v1
|
|
||||||
// clusters:
|
|
||||||
// - cluster:
|
|
||||||
// server: http://chicken.org:8080
|
|
||||||
// name: chicken-cluster
|
|
||||||
// - cluster:
|
|
||||||
// server: http://cow.org:8080
|
|
||||||
// name: cow-cluster
|
|
||||||
// - cluster:
|
|
||||||
// server: http://horse.org:8080
|
|
||||||
// name: horse-cluster
|
|
||||||
// - cluster:
|
|
||||||
// server: http://pig.org:8080
|
|
||||||
// name: pig-cluster
|
|
||||||
// contexts:
|
|
||||||
// - context:
|
|
||||||
// cluster: cow-cluster
|
|
||||||
// namespace: hammer-ns
|
|
||||||
// user: red-user
|
|
||||||
// name: federal-context
|
|
||||||
// - context:
|
|
||||||
// cluster: chicken-cluster
|
|
||||||
// namespace: plane-ns
|
|
||||||
// user: blue-user
|
|
||||||
// name: gothic-context
|
|
||||||
// - context:
|
|
||||||
// cluster: pig-cluster
|
|
||||||
// namespace: saw-ns
|
|
||||||
// user: black-user
|
|
||||||
// name: queen-anne-context
|
|
||||||
// - context:
|
|
||||||
// cluster: horse-cluster
|
|
||||||
// namespace: chisel-ns
|
|
||||||
// user: green-user
|
|
||||||
// name: shaker-context
|
|
||||||
// current-context: ""
|
|
||||||
// kind: Config
|
|
||||||
// preferences: {}
|
|
||||||
// users:
|
|
||||||
// - name: black-user
|
|
||||||
// user:
|
|
||||||
// token: black-token
|
|
||||||
// - name: blue-user
|
|
||||||
// user:
|
|
||||||
// token: blue-token
|
|
||||||
// - name: green-user
|
|
||||||
// user:
|
|
||||||
// token: green-token
|
|
||||||
// - name: red-user
|
|
||||||
// user:
|
|
||||||
// token: red-token
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DeferredLoadingClientConfig is a ClientConfig interface that is backed by a client config loader.
|
|
||||||
// It is used in cases where the loading rules may change after you've instantiated them and you want to be sure that
|
|
||||||
// the most recent rules are used. This is useful in cases where you bind flags to loading rule parameters before
|
|
||||||
// the parse happens and you want your calling code to be ignorant of how the values are being mutated to avoid
|
|
||||||
// passing extraneous information down a call stack
|
|
||||||
type DeferredLoadingClientConfig struct {
|
|
||||||
loader ClientConfigLoader
|
|
||||||
overrides *ConfigOverrides
|
|
||||||
fallbackReader io.Reader
|
|
||||||
|
|
||||||
clientConfig ClientConfig
|
|
||||||
loadingLock sync.Mutex
|
|
||||||
|
|
||||||
// provided for testing
|
|
||||||
icc InClusterConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// InClusterConfig abstracts details of whether the client is running in a cluster for testing.
|
|
||||||
type InClusterConfig interface {
|
|
||||||
ClientConfig
|
|
||||||
Possible() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNonInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name
|
|
||||||
func NewNonInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides) ClientConfig {
|
|
||||||
return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInteractiveDeferredLoadingClientConfig creates a ConfigClientClientConfig using the passed context name and the fallback auth reader
|
|
||||||
func NewInteractiveDeferredLoadingClientConfig(loader ClientConfigLoader, overrides *ConfigOverrides, fallbackReader io.Reader) ClientConfig {
|
|
||||||
return &DeferredLoadingClientConfig{loader: loader, overrides: overrides, icc: &inClusterClientConfig{overrides: overrides}, fallbackReader: fallbackReader}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *DeferredLoadingClientConfig) createClientConfig() (ClientConfig, error) {
|
|
||||||
if config.clientConfig == nil {
|
|
||||||
config.loadingLock.Lock()
|
|
||||||
defer config.loadingLock.Unlock()
|
|
||||||
|
|
||||||
if config.clientConfig == nil {
|
|
||||||
mergedConfig, err := config.loader.Load()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mergedClientConfig ClientConfig
|
|
||||||
if config.fallbackReader != nil {
|
|
||||||
mergedClientConfig = NewInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.fallbackReader, config.loader)
|
|
||||||
} else {
|
|
||||||
mergedClientConfig = NewNonInteractiveClientConfig(*mergedConfig, config.overrides.CurrentContext, config.overrides, config.loader)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.clientConfig = mergedClientConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config.clientConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
|
||||||
mergedConfig, err := config.createClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
return clientcmdapi.Config{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mergedConfig.RawConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientConfig implements ClientConfig
|
|
||||||
func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) {
|
|
||||||
mergedClientConfig, err := config.createClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the configuration and return on non-empty errors and if the
|
|
||||||
// content differs from the default config
|
|
||||||
mergedConfig, err := mergedClientConfig.ClientConfig()
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
if !IsEmptyConfig(err) {
|
|
||||||
// return on any error except empty config
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case mergedConfig != nil:
|
|
||||||
// the configuration is valid, but if this is equal to the defaults we should try
|
|
||||||
// in-cluster configuration
|
|
||||||
if !config.loader.IsDefaultConfig(mergedConfig) {
|
|
||||||
return mergedConfig, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for in-cluster configuration and use it
|
|
||||||
if config.icc.Possible() {
|
|
||||||
glog.V(4).Infof("Using in-cluster configuration")
|
|
||||||
return config.icc.ClientConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the result of the merged client config
|
|
||||||
return mergedConfig, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Namespace implements KubeConfig
|
|
||||||
func (config *DeferredLoadingClientConfig) Namespace() (string, bool, error) {
|
|
||||||
mergedKubeConfig, err := config.createClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
return "", false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ns, ok, err := mergedKubeConfig.Namespace()
|
|
||||||
// if we get an error and it is not empty config, or if the merged config defined an explicit namespace, or
|
|
||||||
// if in-cluster config is not possible, return immediately
|
|
||||||
if (err != nil && !IsEmptyConfig(err)) || ok || !config.icc.Possible() {
|
|
||||||
// return on any error except empty config
|
|
||||||
return ns, ok, err
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(4).Infof("Using in-cluster namespace")
|
|
||||||
|
|
||||||
// allow the namespace from the service account token directory to be used.
|
|
||||||
return config.icc.Namespace()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigAccess implements ClientConfig
|
|
||||||
func (config *DeferredLoadingClientConfig) ConfigAccess() ConfigAccess {
|
|
||||||
return config.loader
|
|
||||||
}
|
|
|
@ -1,328 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testLoader struct {
|
|
||||||
ClientConfigLoader
|
|
||||||
|
|
||||||
called bool
|
|
||||||
config *clientcmdapi.Config
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *testLoader) Load() (*clientcmdapi.Config, error) {
|
|
||||||
l.called = true
|
|
||||||
return l.config, l.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type testClientConfig struct {
|
|
||||||
config *restclient.Config
|
|
||||||
namespace string
|
|
||||||
namespaceSpecified bool
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) {
|
|
||||||
return clientcmdapi.Config{}, fmt.Errorf("unexpected call")
|
|
||||||
}
|
|
||||||
func (c *testClientConfig) ClientConfig() (*restclient.Config, error) {
|
|
||||||
return c.config, c.err
|
|
||||||
}
|
|
||||||
func (c *testClientConfig) Namespace() (string, bool, error) {
|
|
||||||
return c.namespace, c.namespaceSpecified, c.err
|
|
||||||
}
|
|
||||||
func (c *testClientConfig) ConfigAccess() ConfigAccess {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type testICC struct {
|
|
||||||
testClientConfig
|
|
||||||
|
|
||||||
possible bool
|
|
||||||
called bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (icc *testICC) Possible() bool {
|
|
||||||
icc.called = true
|
|
||||||
return icc.possible
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInClusterConfig(t *testing.T) {
|
|
||||||
default1 := &DirectClientConfig{
|
|
||||||
config: *createValidTestConfig(),
|
|
||||||
contextName: "clean",
|
|
||||||
overrides: &ConfigOverrides{},
|
|
||||||
}
|
|
||||||
invalidDefaultConfig := clientcmdapi.NewConfig()
|
|
||||||
invalidDefaultConfig.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "http://localhost:8080",
|
|
||||||
}
|
|
||||||
invalidDefaultConfig.Contexts["other"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
}
|
|
||||||
invalidDefaultConfig.CurrentContext = "clean"
|
|
||||||
|
|
||||||
defaultInvalid := &DirectClientConfig{
|
|
||||||
config: *invalidDefaultConfig,
|
|
||||||
overrides: &ConfigOverrides{},
|
|
||||||
}
|
|
||||||
if _, err := defaultInvalid.ClientConfig(); err == nil || !IsConfigurationInvalid(err) {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
config1, err := default1.ClientConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
config2 := &restclient.Config{Host: "config2"}
|
|
||||||
err1 := fmt.Errorf("unique error")
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
clientConfig *testClientConfig
|
|
||||||
icc *testICC
|
|
||||||
defaultConfig *DirectClientConfig
|
|
||||||
|
|
||||||
checkedICC bool
|
|
||||||
result *restclient.Config
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
"in-cluster checked on other error": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: nil,
|
|
||||||
err: ErrEmptyConfig,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked on non-empty error": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyCluster},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: false,
|
|
||||||
result: nil,
|
|
||||||
err: ErrEmptyCluster,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster checked when config is default": {
|
|
||||||
defaultConfig: default1,
|
|
||||||
clientConfig: &testClientConfig{config: config1},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: config1,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked when default config is invalid": {
|
|
||||||
defaultConfig: defaultInvalid,
|
|
||||||
clientConfig: &testClientConfig{config: config1},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: false,
|
|
||||||
result: config1,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked when config is not equal to default": {
|
|
||||||
defaultConfig: default1,
|
|
||||||
clientConfig: &testClientConfig{config: config2},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: false,
|
|
||||||
result: config2,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster checked when config is not equal to default and error is empty": {
|
|
||||||
clientConfig: &testClientConfig{config: config2, err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: config2,
|
|
||||||
err: ErrEmptyConfig,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster error returned when config is empty": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{
|
|
||||||
possible: true,
|
|
||||||
testClientConfig: testClientConfig{
|
|
||||||
err: err1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: nil,
|
|
||||||
err: err1,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster config returned when config is empty": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{
|
|
||||||
possible: true,
|
|
||||||
testClientConfig: testClientConfig{
|
|
||||||
config: config2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: config2,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked when standard default is invalid": {
|
|
||||||
defaultConfig: &DefaultClientConfig,
|
|
||||||
clientConfig: &testClientConfig{config: config2},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: false,
|
|
||||||
result: config2,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, test := range testCases {
|
|
||||||
c := &DeferredLoadingClientConfig{icc: test.icc}
|
|
||||||
c.loader = &ClientConfigLoadingRules{DefaultClientConfig: test.defaultConfig}
|
|
||||||
c.clientConfig = test.clientConfig
|
|
||||||
|
|
||||||
cfg, err := c.ClientConfig()
|
|
||||||
if test.icc.called != test.checkedICC {
|
|
||||||
t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called)
|
|
||||||
}
|
|
||||||
if err != test.err || cfg != test.result {
|
|
||||||
t.Errorf("%s: unexpected result: %v %#v", name, err, cfg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInClusterConfigNamespace(t *testing.T) {
|
|
||||||
err1 := fmt.Errorf("unique error")
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
clientConfig *testClientConfig
|
|
||||||
icc *testICC
|
|
||||||
|
|
||||||
checkedICC bool
|
|
||||||
result string
|
|
||||||
ok bool
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
"in-cluster checked on empty error": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
err: ErrEmptyConfig,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked on non-empty error": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyCluster},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
err: ErrEmptyCluster,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster checked when config is default": {
|
|
||||||
clientConfig: &testClientConfig{},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster not checked when config is not equal to default": {
|
|
||||||
clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: true},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
result: "test",
|
|
||||||
ok: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster checked when namespace is not specified, but is defaulted": {
|
|
||||||
clientConfig: &testClientConfig{namespace: "test", namespaceSpecified: false},
|
|
||||||
icc: &testICC{},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: "test",
|
|
||||||
ok: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster error returned when config is empty": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{
|
|
||||||
possible: true,
|
|
||||||
testClientConfig: testClientConfig{
|
|
||||||
err: err1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
err: err1,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster config returned when config is empty": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{
|
|
||||||
possible: true,
|
|
||||||
testClientConfig: testClientConfig{
|
|
||||||
namespace: "test",
|
|
||||||
namespaceSpecified: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: "test",
|
|
||||||
ok: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"in-cluster config returned when config is empty and namespace is defaulted but not explicitly set": {
|
|
||||||
clientConfig: &testClientConfig{err: ErrEmptyConfig},
|
|
||||||
icc: &testICC{
|
|
||||||
possible: true,
|
|
||||||
testClientConfig: testClientConfig{
|
|
||||||
namespace: "test",
|
|
||||||
namespaceSpecified: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
checkedICC: true,
|
|
||||||
result: "test",
|
|
||||||
ok: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, test := range testCases {
|
|
||||||
c := &DeferredLoadingClientConfig{icc: test.icc}
|
|
||||||
c.clientConfig = test.clientConfig
|
|
||||||
|
|
||||||
ns, ok, err := c.Namespace()
|
|
||||||
if test.icc.called != test.checkedICC {
|
|
||||||
t.Errorf("%s: unexpected in-cluster-config call %t", name, test.icc.called)
|
|
||||||
}
|
|
||||||
if err != test.err || ns != test.result || ok != test.ok {
|
|
||||||
t.Errorf("%s: unexpected result: %v %s %t", name, err, ns, ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,206 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfigOverrides holds values that should override whatever information is pulled from the actual Config object. You can't
|
|
||||||
// simply use an actual Config object, because Configs hold maps, but overrides are restricted to "at most one"
|
|
||||||
type ConfigOverrides struct {
|
|
||||||
AuthInfo clientcmdapi.AuthInfo
|
|
||||||
// ClusterDefaults are applied before the configured cluster info is loaded.
|
|
||||||
ClusterDefaults clientcmdapi.Cluster
|
|
||||||
ClusterInfo clientcmdapi.Cluster
|
|
||||||
Context clientcmdapi.Context
|
|
||||||
CurrentContext string
|
|
||||||
Timeout 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
|
|
||||||
ContextOverrideFlags ContextOverrideFlags
|
|
||||||
CurrentContext FlagInfo
|
|
||||||
Timeout FlagInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthOverrideFlags holds the flag names to be used for binding command line flags for AuthInfo objects
|
|
||||||
type AuthOverrideFlags struct {
|
|
||||||
ClientCertificate FlagInfo
|
|
||||||
ClientKey FlagInfo
|
|
||||||
Token FlagInfo
|
|
||||||
Impersonate FlagInfo
|
|
||||||
Username FlagInfo
|
|
||||||
Password FlagInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContextOverrideFlags holds the flag names to be used for binding command line flags for Cluster objects
|
|
||||||
type ContextOverrideFlags struct {
|
|
||||||
ClusterName FlagInfo
|
|
||||||
AuthInfoName FlagInfo
|
|
||||||
Namespace FlagInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClusterOverride holds the flag names to be used for binding command line flags for Cluster objects
|
|
||||||
type ClusterOverrideFlags struct {
|
|
||||||
APIServer FlagInfo
|
|
||||||
APIVersion FlagInfo
|
|
||||||
CertificateAuthority FlagInfo
|
|
||||||
InsecureSkipTLSVerify FlagInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlagInfo contains information about how to register a flag. This struct is useful if you want to provide a way for an extender to
|
|
||||||
// get back a set of recommended flag names, descriptions, and defaults, but allow for customization by an extender. This makes for
|
|
||||||
// coherent extension, without full prescription
|
|
||||||
type FlagInfo struct {
|
|
||||||
// LongName is the long string for a flag. If this is empty, then the flag will not be bound
|
|
||||||
LongName string
|
|
||||||
// ShortName is the single character for a flag. If this is empty, then there will be no short flag
|
|
||||||
ShortName string
|
|
||||||
// Default is the default value for the flag
|
|
||||||
Default string
|
|
||||||
// Description is the description for the flag
|
|
||||||
Description string
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindStringFlag binds the flag based on the provided info. If LongName == "", nothing is registered
|
|
||||||
func (f FlagInfo) BindStringFlag(flags *pflag.FlagSet, target *string) {
|
|
||||||
// you can't register a flag without a long name
|
|
||||||
if len(f.LongName) > 0 {
|
|
||||||
flags.StringVarP(target, f.LongName, f.ShortName, f.Default, f.Description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindBoolFlag binds the flag based on the provided info. If LongName == "", nothing is registered
|
|
||||||
func (f FlagInfo) BindBoolFlag(flags *pflag.FlagSet, target *bool) {
|
|
||||||
// you can't register a flag without a long name
|
|
||||||
if len(f.LongName) > 0 {
|
|
||||||
// try to parse Default as a bool. If it fails, assume false
|
|
||||||
boolVal, err := strconv.ParseBool(f.Default)
|
|
||||||
if err != nil {
|
|
||||||
boolVal = false
|
|
||||||
}
|
|
||||||
|
|
||||||
flags.BoolVarP(target, f.LongName, f.ShortName, boolVal, f.Description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
FlagClusterName = "cluster"
|
|
||||||
FlagAuthInfoName = "user"
|
|
||||||
FlagContext = "context"
|
|
||||||
FlagNamespace = "namespace"
|
|
||||||
FlagAPIServer = "server"
|
|
||||||
FlagAPIVersion = "api-version"
|
|
||||||
FlagInsecure = "insecure-skip-tls-verify"
|
|
||||||
FlagCertFile = "client-certificate"
|
|
||||||
FlagKeyFile = "client-key"
|
|
||||||
FlagCAFile = "certificate-authority"
|
|
||||||
FlagEmbedCerts = "embed-certs"
|
|
||||||
FlagBearerToken = "token"
|
|
||||||
FlagImpersonate = "as"
|
|
||||||
FlagUsername = "username"
|
|
||||||
FlagPassword = "password"
|
|
||||||
FlagTimeout = "request-timeout"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RecommendedConfigOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing
|
|
||||||
func RecommendedConfigOverrideFlags(prefix string) ConfigOverrideFlags {
|
|
||||||
return ConfigOverrideFlags{
|
|
||||||
AuthOverrideFlags: RecommendedAuthOverrideFlags(prefix),
|
|
||||||
ClusterOverrideFlags: RecommendedClusterOverrideFlags(prefix),
|
|
||||||
ContextOverrideFlags: RecommendedContextOverrideFlags(prefix),
|
|
||||||
|
|
||||||
CurrentContext: FlagInfo{prefix + FlagContext, "", "", "The name of the kubeconfig context to use"},
|
|
||||||
Timeout: FlagInfo{prefix + FlagTimeout, "", "0", "The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests."},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecommendedAuthOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing
|
|
||||||
func RecommendedAuthOverrideFlags(prefix string) AuthOverrideFlags {
|
|
||||||
return AuthOverrideFlags{
|
|
||||||
ClientCertificate: FlagInfo{prefix + FlagCertFile, "", "", "Path to a client certificate file for TLS"},
|
|
||||||
ClientKey: FlagInfo{prefix + FlagKeyFile, "", "", "Path to a client key file for TLS"},
|
|
||||||
Token: FlagInfo{prefix + FlagBearerToken, "", "", "Bearer token for authentication to the API server"},
|
|
||||||
Impersonate: FlagInfo{prefix + FlagImpersonate, "", "", "Username to impersonate for the operation"},
|
|
||||||
Username: FlagInfo{prefix + FlagUsername, "", "", "Username for basic authentication to the API server"},
|
|
||||||
Password: FlagInfo{prefix + FlagPassword, "", "", "Password for basic authentication to the API server"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecommendedClusterOverrideFlags is a convenience method to return recommended flag names prefixed with a string of your choosing
|
|
||||||
func RecommendedClusterOverrideFlags(prefix string) ClusterOverrideFlags {
|
|
||||||
return ClusterOverrideFlags{
|
|
||||||
APIServer: FlagInfo{prefix + FlagAPIServer, "", "", "The address and port of the Kubernetes API server"},
|
|
||||||
APIVersion: FlagInfo{prefix + FlagAPIVersion, "", "", "DEPRECATED: The API version to use when talking to the server"},
|
|
||||||
CertificateAuthority: FlagInfo{prefix + FlagCAFile, "", "", "Path to a cert. file for the certificate authority"},
|
|
||||||
InsecureSkipTLSVerify: FlagInfo{prefix + FlagInsecure, "", "false", "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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: FlagInfo{prefix + FlagClusterName, "", "", "The name of the kubeconfig cluster to use"},
|
|
||||||
AuthInfoName: FlagInfo{prefix + FlagAuthInfoName, "", "", "The name of the kubeconfig user to use"},
|
|
||||||
Namespace: FlagInfo{prefix + FlagNamespace, "n", "", "If present, the namespace scope for this CLI request"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindOverrideFlags is a convenience method to bind the specified flags to their associated variables
|
|
||||||
func BindOverrideFlags(overrides *ConfigOverrides, flags *pflag.FlagSet, flagNames ConfigOverrideFlags) {
|
|
||||||
BindAuthInfoFlags(&overrides.AuthInfo, flags, flagNames.AuthOverrideFlags)
|
|
||||||
BindClusterFlags(&overrides.ClusterInfo, flags, flagNames.ClusterOverrideFlags)
|
|
||||||
BindContextFlags(&overrides.Context, flags, flagNames.ContextOverrideFlags)
|
|
||||||
flagNames.CurrentContext.BindStringFlag(flags, &overrides.CurrentContext)
|
|
||||||
flagNames.Timeout.BindStringFlag(flags, &overrides.Timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindAuthInfoFlags is a convenience method to bind the specified flags to their associated variables
|
|
||||||
func BindAuthInfoFlags(authInfo *clientcmdapi.AuthInfo, flags *pflag.FlagSet, flagNames AuthOverrideFlags) {
|
|
||||||
flagNames.ClientCertificate.BindStringFlag(flags, &authInfo.ClientCertificate)
|
|
||||||
flagNames.ClientKey.BindStringFlag(flags, &authInfo.ClientKey)
|
|
||||||
flagNames.Token.BindStringFlag(flags, &authInfo.Token)
|
|
||||||
flagNames.Impersonate.BindStringFlag(flags, &authInfo.Impersonate)
|
|
||||||
flagNames.Username.BindStringFlag(flags, &authInfo.Username)
|
|
||||||
flagNames.Password.BindStringFlag(flags, &authInfo.Password)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindClusterFlags is a convenience method to bind the specified flags to their associated variables
|
|
||||||
func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, flagNames ClusterOverrideFlags) {
|
|
||||||
flagNames.APIServer.BindStringFlag(flags, &clusterInfo.Server)
|
|
||||||
// TODO: remove --api-version flag in 1.3.
|
|
||||||
flagNames.APIVersion.BindStringFlag(flags, &clusterInfo.APIVersion)
|
|
||||||
flags.MarkDeprecated(FlagAPIVersion, "flag is no longer respected and will be deleted in the next release")
|
|
||||||
flagNames.CertificateAuthority.BindStringFlag(flags, &clusterInfo.CertificateAuthority)
|
|
||||||
flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindFlags is a convenience method to bind the specified flags to their associated variables
|
|
||||||
func BindContextFlags(contextInfo *clientcmdapi.Context, flags *pflag.FlagSet, flagNames ContextOverrideFlags) {
|
|
||||||
flagNames.ClusterName.BindStringFlag(flags, &contextInfo.Cluster)
|
|
||||||
flagNames.AuthInfoName.BindStringFlag(flags, &contextInfo.AuthInfo)
|
|
||||||
flagNames.Namespace.BindStringFlag(flags, &contextInfo.Namespace)
|
|
||||||
}
|
|
|
@ -1,270 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrNoContext = errors.New("no context chosen")
|
|
||||||
ErrEmptyConfig = errors.New("no configuration has been provided")
|
|
||||||
// message is for consistency with old behavior
|
|
||||||
ErrEmptyCluster = errors.New("cluster has no server defined")
|
|
||||||
)
|
|
||||||
|
|
||||||
type errContextNotFound struct {
|
|
||||||
ContextName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errContextNotFound) Error() string {
|
|
||||||
return fmt.Sprintf("context was not found for specified context: %v", e.ContextName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsContextNotFound returns a boolean indicating whether the error is known to
|
|
||||||
// report that a context was not found
|
|
||||||
func IsContextNotFound(err error) bool {
|
|
||||||
if err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, ok := err.(*errContextNotFound); ok || err == ErrNoContext {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return strings.Contains(err.Error(), "context was not found for specified context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEmptyConfig returns true if the provided error indicates the provided configuration
|
|
||||||
// is empty.
|
|
||||||
func IsEmptyConfig(err error) bool {
|
|
||||||
switch t := err.(type) {
|
|
||||||
case errConfigurationInvalid:
|
|
||||||
return len(t) == 1 && t[0] == ErrEmptyConfig
|
|
||||||
}
|
|
||||||
return err == ErrEmptyConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// errConfigurationInvalid is a set of errors indicating the configuration is invalid.
|
|
||||||
type errConfigurationInvalid []error
|
|
||||||
|
|
||||||
// errConfigurationInvalid implements error and Aggregate
|
|
||||||
var _ error = errConfigurationInvalid{}
|
|
||||||
var _ utilerrors.Aggregate = errConfigurationInvalid{}
|
|
||||||
|
|
||||||
func newErrConfigurationInvalid(errs []error) error {
|
|
||||||
switch len(errs) {
|
|
||||||
case 0:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return errConfigurationInvalid(errs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface
|
|
||||||
func (e errConfigurationInvalid) Error() string {
|
|
||||||
return fmt.Sprintf("invalid configuration: %v", utilerrors.NewAggregate(e).Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errors implements the AggregateError interface
|
|
||||||
func (e errConfigurationInvalid) Errors() []error {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsConfigurationInvalid returns true if the provided error indicates the configuration is invalid.
|
|
||||||
func IsConfigurationInvalid(err error) bool {
|
|
||||||
switch err.(type) {
|
|
||||||
case *errContextNotFound, errConfigurationInvalid:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return IsContextNotFound(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks for errors in the Config. It does not return early so that it can find as many errors as possible.
|
|
||||||
func Validate(config clientcmdapi.Config) error {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
if clientcmdapi.IsConfigEmpty(&config) {
|
|
||||||
return newErrConfigurationInvalid([]error{ErrEmptyConfig})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(config.CurrentContext) != 0 {
|
|
||||||
if _, exists := config.Contexts[config.CurrentContext]; !exists {
|
|
||||||
validationErrors = append(validationErrors, &errContextNotFound{config.CurrentContext})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for contextName, context := range config.Contexts {
|
|
||||||
validationErrors = append(validationErrors, validateContext(contextName, *context, config)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for authInfoName, authInfo := range config.AuthInfos {
|
|
||||||
validationErrors = append(validationErrors, validateAuthInfo(authInfoName, *authInfo)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for clusterName, clusterInfo := range config.Clusters {
|
|
||||||
validationErrors = append(validationErrors, validateClusterInfo(clusterName, *clusterInfo)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newErrConfigurationInvalid(validationErrors)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 ConfirmUsable(config clientcmdapi.Config, passedContextName string) error {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
if clientcmdapi.IsConfigEmpty(&config) {
|
|
||||||
return newErrConfigurationInvalid([]error{ErrEmptyConfig})
|
|
||||||
}
|
|
||||||
|
|
||||||
var contextName string
|
|
||||||
if len(passedContextName) != 0 {
|
|
||||||
contextName = passedContextName
|
|
||||||
} else {
|
|
||||||
contextName = config.CurrentContext
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(contextName) == 0 {
|
|
||||||
return ErrNoContext
|
|
||||||
}
|
|
||||||
|
|
||||||
context, exists := config.Contexts[contextName]
|
|
||||||
if !exists {
|
|
||||||
validationErrors = append(validationErrors, &errContextNotFound{contextName})
|
|
||||||
}
|
|
||||||
|
|
||||||
if exists {
|
|
||||||
validationErrors = append(validationErrors, validateContext(contextName, *context, config)...)
|
|
||||||
validationErrors = append(validationErrors, validateAuthInfo(context.AuthInfo, *config.AuthInfos[context.AuthInfo])...)
|
|
||||||
validationErrors = append(validationErrors, validateClusterInfo(context.Cluster, *config.Clusters[context.Cluster])...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newErrConfigurationInvalid(validationErrors)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateClusterInfo looks for conflicts and errors in the cluster info
|
|
||||||
func validateClusterInfo(clusterName string, clusterInfo clientcmdapi.Cluster) []error {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
if reflect.DeepEqual(clientcmdapi.Cluster{}, clusterInfo) {
|
|
||||||
return []error{ErrEmptyCluster}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(clusterInfo.Server) == 0 {
|
|
||||||
if len(clusterName) == 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("default cluster has no server defined"))
|
|
||||||
} else {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("no server found for cluster %q", clusterName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure CA data and CA file aren't both specified
|
|
||||||
if len(clusterInfo.CertificateAuthority) != 0 && len(clusterInfo.CertificateAuthorityData) != 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("certificate-authority-data and certificate-authority are both specified for %v. certificate-authority-data will override.", clusterName))
|
|
||||||
}
|
|
||||||
if len(clusterInfo.CertificateAuthority) != 0 {
|
|
||||||
clientCertCA, err := os.Open(clusterInfo.CertificateAuthority)
|
|
||||||
defer clientCertCA.Close()
|
|
||||||
if err != nil {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("unable to read certificate-authority %v for %v due to %v", clusterInfo.CertificateAuthority, clusterName, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validationErrors
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateAuthInfo looks for conflicts and errors in the auth info
|
|
||||||
func validateAuthInfo(authInfoName string, authInfo clientcmdapi.AuthInfo) []error {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
usingAuthPath := false
|
|
||||||
methods := make([]string, 0, 3)
|
|
||||||
if len(authInfo.Token) != 0 {
|
|
||||||
methods = append(methods, "token")
|
|
||||||
}
|
|
||||||
if len(authInfo.Username) != 0 || len(authInfo.Password) != 0 {
|
|
||||||
methods = append(methods, "basicAuth")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(authInfo.ClientCertificate) != 0 || len(authInfo.ClientCertificateData) != 0 {
|
|
||||||
// Make sure cert data and file aren't both specified
|
|
||||||
if len(authInfo.ClientCertificate) != 0 && len(authInfo.ClientCertificateData) != 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("client-cert-data and client-cert are both specified for %v. client-cert-data will override.", authInfoName))
|
|
||||||
}
|
|
||||||
// Make sure key data and file aren't both specified
|
|
||||||
if len(authInfo.ClientKey) != 0 && len(authInfo.ClientKeyData) != 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("client-key-data and client-key are both specified for %v; client-key-data will override", authInfoName))
|
|
||||||
}
|
|
||||||
// Make sure a key is specified
|
|
||||||
if len(authInfo.ClientKey) == 0 && len(authInfo.ClientKeyData) == 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("client-key-data or client-key must be specified for %v to use the clientCert authentication method.", authInfoName))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(authInfo.ClientCertificate) != 0 {
|
|
||||||
clientCertFile, err := os.Open(authInfo.ClientCertificate)
|
|
||||||
defer clientCertFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("unable to read client-cert %v for %v due to %v", authInfo.ClientCertificate, authInfoName, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(authInfo.ClientKey) != 0 {
|
|
||||||
clientKeyFile, err := os.Open(authInfo.ClientKey)
|
|
||||||
defer clientKeyFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("unable to read client-key %v for %v due to %v", authInfo.ClientKey, authInfoName, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// authPath also provides information for the client to identify the server, so allow multiple auth methods in that case
|
|
||||||
if (len(methods) > 1) && (!usingAuthPath) {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("more than one authentication method found for %v; found %v, only one is allowed", authInfoName, methods))
|
|
||||||
}
|
|
||||||
|
|
||||||
return validationErrors
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateContext looks for errors in the context. It is not transitive, so errors in the reference authInfo or cluster configs are not included in this return
|
|
||||||
func validateContext(contextName string, context clientcmdapi.Context, config clientcmdapi.Config) []error {
|
|
||||||
validationErrors := make([]error, 0)
|
|
||||||
|
|
||||||
if len(context.AuthInfo) == 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("user was not specified for context %q", contextName))
|
|
||||||
} else if _, exists := config.AuthInfos[context.AuthInfo]; !exists {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("user %q was not found for context %q", context.AuthInfo, contextName))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(context.Cluster) == 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("cluster was not specified for context %q", contextName))
|
|
||||||
} else if _, exists := config.Clusters[context.Cluster]; !exists {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("cluster %q was not found for context %q", context.Cluster, contextName))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(context.Namespace) != 0 {
|
|
||||||
if len(validation.IsDNS1123Label(context.Namespace)) != 0 {
|
|
||||||
validationErrors = append(validationErrors, fmt.Errorf("namespace %q for context %q does not conform to the kubernetes DNS_LABEL rules", context.Namespace, contextName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validationErrors
|
|
||||||
}
|
|
|
@ -1,432 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2014 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 clientcmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConfirmUsableBadInfoButOkConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
CertificateAuthority: "missing",
|
|
||||||
}
|
|
||||||
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
|
|
||||||
Username: "anything",
|
|
||||||
Token: "here",
|
|
||||||
}
|
|
||||||
config.Contexts["dirty"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "missing ca",
|
|
||||||
AuthInfo: "error",
|
|
||||||
}
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
}
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
Token: "here",
|
|
||||||
}
|
|
||||||
config.Contexts["clean"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "clean",
|
|
||||||
AuthInfo: "clean",
|
|
||||||
}
|
|
||||||
|
|
||||||
badValidation := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"unable to read certificate-authority"},
|
|
||||||
}
|
|
||||||
okTest := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
okTest.testConfirmUsable("clean", t)
|
|
||||||
badValidation.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestConfirmUsableBadInfoConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
CertificateAuthority: "missing",
|
|
||||||
}
|
|
||||||
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
|
|
||||||
Username: "anything",
|
|
||||||
Token: "here",
|
|
||||||
}
|
|
||||||
config.Contexts["first"] = &clientcmdapi.Context{
|
|
||||||
Cluster: "missing ca",
|
|
||||||
AuthInfo: "error",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"unable to read certificate-authority"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testConfirmUsable("first", t)
|
|
||||||
}
|
|
||||||
func TestConfirmUsableEmptyConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testConfirmUsable("", t)
|
|
||||||
}
|
|
||||||
func TestConfirmUsableMissingConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testConfirmUsable("not-here", t)
|
|
||||||
}
|
|
||||||
func TestValidateEmptyConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateMissingCurrentContextConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.CurrentContext = "anything"
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"context was not found for specified "},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestIsContextNotFound(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.CurrentContext = "anything"
|
|
||||||
|
|
||||||
err := Validate(*config)
|
|
||||||
if !IsContextNotFound(err) {
|
|
||||||
t.Errorf("Expected context not found, but got %v", err)
|
|
||||||
}
|
|
||||||
if !IsConfigurationInvalid(err) {
|
|
||||||
t.Errorf("Expected configuration invalid, but got %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsEmptyConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
|
|
||||||
err := Validate(*config)
|
|
||||||
if !IsEmptyConfig(err) {
|
|
||||||
t.Errorf("Expected context not found, but got %v", err)
|
|
||||||
}
|
|
||||||
if !IsConfigurationInvalid(err) {
|
|
||||||
t.Errorf("Expected configuration invalid, but got %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsConfigurationInvalid(t *testing.T) {
|
|
||||||
if newErrConfigurationInvalid([]error{}) != nil {
|
|
||||||
t.Errorf("unexpected error")
|
|
||||||
}
|
|
||||||
if newErrConfigurationInvalid([]error{ErrNoContext}) == ErrNoContext {
|
|
||||||
t.Errorf("unexpected error")
|
|
||||||
}
|
|
||||||
if newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext}) == nil {
|
|
||||||
t.Errorf("unexpected error")
|
|
||||||
}
|
|
||||||
if !IsConfigurationInvalid(newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext})) {
|
|
||||||
t.Errorf("unexpected error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateMissingReferencesConfig(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.CurrentContext = "anything"
|
|
||||||
config.Contexts["anything"] = &clientcmdapi.Context{Cluster: "missing", AuthInfo: "missing"}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"user \"missing\" was not found for context \"anything\"", "cluster \"missing\" was not found for context \"anything\""},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testContext("anything", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateEmptyContext(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.CurrentContext = "anything"
|
|
||||||
config.Contexts["anything"] = &clientcmdapi.Context{}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"user was not specified for context \"anything\"", "cluster was not specified for context \"anything\""},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testContext("anything", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateEmptyClusterInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["empty"] = &clientcmdapi.Cluster{}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"cluster has no server defined"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testCluster("empty", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateMissingCAFileClusterInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
CertificateAuthority: "missing",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"unable to read certificate-authority"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testCluster("missing ca", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCleanClusterInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testCluster("clean", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCleanWithCAClusterInfo(t *testing.T) {
|
|
||||||
tempFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.Clusters["clean"] = &clientcmdapi.Cluster{
|
|
||||||
Server: "anything",
|
|
||||||
CertificateAuthority: tempFile.Name(),
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testCluster("clean", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateEmptyAuthInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("error", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCertFilesNotFoundAuthInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
|
|
||||||
ClientCertificate: "missing",
|
|
||||||
ClientKey: "missing",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"unable to read client-cert", "unable to read client-key"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("error", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCertDataOverridesFiles(t *testing.T) {
|
|
||||||
tempFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
ClientCertificate: tempFile.Name(),
|
|
||||||
ClientCertificateData: []byte("certdata"),
|
|
||||||
ClientKey: tempFile.Name(),
|
|
||||||
ClientKeyData: []byte("keydata"),
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"client-cert-data and client-cert are both specified", "client-key-data and client-key are both specified"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("clean", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCleanCertFilesAuthInfo(t *testing.T) {
|
|
||||||
tempFile, _ := ioutil.TempFile("", "")
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
ClientCertificate: tempFile.Name(),
|
|
||||||
ClientKey: tempFile.Name(),
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("clean", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
func TestValidateCleanTokenAuthInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
|
|
||||||
Token: "any-value",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("clean", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateMultipleMethodsAuthInfo(t *testing.T) {
|
|
||||||
config := clientcmdapi.NewConfig()
|
|
||||||
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
|
|
||||||
Token: "token",
|
|
||||||
Username: "username",
|
|
||||||
}
|
|
||||||
test := configValidationTest{
|
|
||||||
config: config,
|
|
||||||
expectedErrorSubstring: []string{"more than one authentication method", "token", "basicAuth"},
|
|
||||||
}
|
|
||||||
|
|
||||||
test.testAuthInfo("error", t)
|
|
||||||
test.testConfig(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
type configValidationTest struct {
|
|
||||||
config *clientcmdapi.Config
|
|
||||||
expectedErrorSubstring []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c configValidationTest) testContext(contextName string, t *testing.T) {
|
|
||||||
errs := validateContext(contextName, *c.config.Contexts[contextName], *c.config)
|
|
||||||
|
|
||||||
if len(c.expectedErrorSubstring) != 0 {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
|
|
||||||
}
|
|
||||||
for _, curr := range c.expectedErrorSubstring {
|
|
||||||
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
|
|
||||||
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if len(errs) != 0 {
|
|
||||||
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (c configValidationTest) testConfirmUsable(contextName string, t *testing.T) {
|
|
||||||
err := ConfirmUsable(*c.config, contextName)
|
|
||||||
|
|
||||||
if len(c.expectedErrorSubstring) != 0 {
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
|
|
||||||
} else {
|
|
||||||
for _, curr := range c.expectedErrorSubstring {
|
|
||||||
if err != nil && !strings.Contains(err.Error(), curr) {
|
|
||||||
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (c configValidationTest) testConfig(t *testing.T) {
|
|
||||||
err := Validate(*c.config)
|
|
||||||
|
|
||||||
if len(c.expectedErrorSubstring) != 0 {
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
|
|
||||||
} else {
|
|
||||||
for _, curr := range c.expectedErrorSubstring {
|
|
||||||
if err != nil && !strings.Contains(err.Error(), curr) {
|
|
||||||
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !IsConfigurationInvalid(err) {
|
|
||||||
t.Errorf("all errors should be configuration invalid: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (c configValidationTest) testCluster(clusterName string, t *testing.T) {
|
|
||||||
errs := validateClusterInfo(clusterName, *c.config.Clusters[clusterName])
|
|
||||||
|
|
||||||
if len(c.expectedErrorSubstring) != 0 {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
|
|
||||||
}
|
|
||||||
for _, curr := range c.expectedErrorSubstring {
|
|
||||||
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
|
|
||||||
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if len(errs) != 0 {
|
|
||||||
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c configValidationTest) testAuthInfo(authInfoName string, t *testing.T) {
|
|
||||||
errs := validateAuthInfo(authInfoName, *c.config.AuthInfos[authInfoName])
|
|
||||||
|
|
||||||
if len(c.expectedErrorSubstring) != 0 {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
|
|
||||||
}
|
|
||||||
for _, curr := range c.expectedErrorSubstring {
|
|
||||||
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
|
|
||||||
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if len(errs) != 0 {
|
|
||||||
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -74,7 +74,6 @@ go_library(
|
||||||
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/unversioned:go_default_library",
|
"//pkg/client/unversioned:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/client/unversioned/portforward:go_default_library",
|
"//pkg/client/unversioned/portforward:go_default_library",
|
||||||
"//pkg/client/unversioned/remotecommand:go_default_library",
|
"//pkg/client/unversioned/remotecommand:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
|
@ -124,6 +123,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
|
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
|
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
|
||||||
|
|
|
@ -28,7 +28,6 @@ go_library(
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
|
@ -36,6 +35,7 @@ go_library(
|
||||||
"//vendor:github.com/spf13/cobra",
|
"//vendor:github.com/spf13/cobra",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
"//vendor:k8s.io/apimachinery/pkg/util/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api/latest",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api/latest",
|
||||||
],
|
],
|
||||||
|
@ -57,10 +57,10 @@ go_test(
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
"//pkg/util/flag:go_default_library",
|
"//pkg/util/flag:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,9 +27,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,8 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
|
|
|
@ -25,8 +25,8 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type currentContextTest struct {
|
type currentContextTest struct {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,8 +24,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type deleteClusterTest struct {
|
type deleteClusterTest struct {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,8 +24,8 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type deleteContextTest struct {
|
type deleteContextTest struct {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,8 +22,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type getClustersTest struct {
|
type getClustersTest struct {
|
||||||
|
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
|
|
@ -22,8 +22,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type getContextsTest struct {
|
type getContextsTest struct {
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/util/flag"
|
"k8s.io/kubernetes/pkg/util/flag"
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,9 +23,9 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/client-go/tools/clientcmd/api/latest"
|
"k8s.io/client-go/tools/clientcmd/api/latest"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
|
|
@ -37,14 +37,12 @@ go_library(
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/typed/dynamic:go_default_library",
|
"//pkg/client/typed/dynamic:go_default_library",
|
||||||
"//pkg/client/unversioned:go_default_library",
|
"//pkg/client/unversioned:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/resource:go_default_library",
|
"//pkg/kubectl/resource:go_default_library",
|
||||||
"//pkg/registry/extensions/thirdpartyresourcedata:go_default_library",
|
"//pkg/registry/extensions/thirdpartyresourcedata:go_default_library",
|
||||||
"//pkg/util/exec:go_default_library",
|
"//pkg/util/exec:go_default_library",
|
||||||
"//pkg/util/flag:go_default_library",
|
"//pkg/util/flag:go_default_library",
|
||||||
"//pkg/util/homedir:go_default_library",
|
|
||||||
"//pkg/util/strategicpatch:go_default_library",
|
"//pkg/util/strategicpatch:go_default_library",
|
||||||
"//vendor:github.com/emicklei/go-restful/swagger",
|
"//vendor:github.com/emicklei/go-restful/swagger",
|
||||||
"//vendor:github.com/evanphx/json-patch",
|
"//vendor:github.com/evanphx/json-patch",
|
||||||
|
@ -63,7 +61,9 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
|
"//vendor:k8s.io/client-go/pkg/util/homedir",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,7 +91,6 @@ go_test(
|
||||||
"//pkg/client/restclient/fake:go_default_library",
|
"//pkg/client/restclient/fake:go_default_library",
|
||||||
"//pkg/client/testing/core:go_default_library",
|
"//pkg/client/testing/core:go_default_library",
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/resource:go_default_library",
|
"//pkg/kubectl/resource:go_default_library",
|
||||||
|
@ -109,6 +108,7 @@ go_test(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/version",
|
"//vendor:k8s.io/apimachinery/pkg/version",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,12 +21,12 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
oldclient "k8s.io/kubernetes/pkg/client/unversioned"
|
oldclient "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewClientCache(loader clientcmd.ClientConfig, discoveryClientFactory DiscoveryClientFactory) *ClientCache {
|
func NewClientCache(loader clientcmd.ClientConfig, discoveryClientFactory DiscoveryClientFactory) *ClientCache {
|
||||||
|
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
@ -47,7 +48,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"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/registry/extensions/thirdpartyresourcedata"
|
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
|
||||||
|
|
|
@ -35,7 +35,9 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/client-go/pkg/util/homedir"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/service"
|
"k8s.io/kubernetes/pkg/api/service"
|
||||||
|
@ -44,12 +46,10 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"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/registry/extensions/thirdpartyresourcedata"
|
"k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresourcedata"
|
||||||
utilflag "k8s.io/kubernetes/pkg/util/flag"
|
utilflag "k8s.io/kubernetes/pkg/util/flag"
|
||||||
"k8s.io/kubernetes/pkg/util/homedir"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ring0Factory struct {
|
type ring0Factory struct {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
|
@ -46,7 +47,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||||
manualfake "k8s.io/kubernetes/pkg/client/restclient/fake"
|
manualfake "k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||||
testcore "k8s.io/kubernetes/pkg/client/testing/core"
|
testcore "k8s.io/kubernetes/pkg/client/testing/core"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
|
|
|
@ -40,9 +40,9 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||||
|
|
|
@ -64,7 +64,6 @@ filegroup(
|
||||||
"//pkg/util/framer:all-srcs",
|
"//pkg/util/framer:all-srcs",
|
||||||
"//pkg/util/goroutinemap:all-srcs",
|
"//pkg/util/goroutinemap:all-srcs",
|
||||||
"//pkg/util/hash:all-srcs",
|
"//pkg/util/hash:all-srcs",
|
||||||
"//pkg/util/homedir:all-srcs",
|
|
||||||
"//pkg/util/httpstream:all-srcs",
|
"//pkg/util/httpstream:all-srcs",
|
||||||
"//pkg/util/i18n:all-srcs",
|
"//pkg/util/i18n:all-srcs",
|
||||||
"//pkg/util/initsystem:all-srcs",
|
"//pkg/util/initsystem:all-srcs",
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package(default_visibility = ["//visibility:public"])
|
|
||||||
|
|
||||||
licenses(["notice"])
|
|
||||||
|
|
||||||
load(
|
|
||||||
"@io_bazel_rules_go//go:def.bzl",
|
|
||||||
"go_library",
|
|
||||||
)
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = ["homedir.go"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "package-srcs",
|
|
||||||
srcs = glob(["**"]),
|
|
||||||
tags = ["automanaged"],
|
|
||||||
visibility = ["//visibility:private"],
|
|
||||||
)
|
|
||||||
|
|
||||||
filegroup(
|
|
||||||
name = "all-srcs",
|
|
||||||
srcs = [":package-srcs"],
|
|
||||||
tags = ["automanaged"],
|
|
||||||
)
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2016 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 homedir
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HomeDir returns the home directory for the current user
|
|
||||||
func HomeDir() string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
|
|
||||||
// First prefer the HOME environmental variable
|
|
||||||
if home := os.Getenv("HOME"); len(home) > 0 {
|
|
||||||
if _, err := os.Stat(home); err == nil {
|
|
||||||
return home
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"); len(homeDrive) > 0 && len(homePath) > 0 {
|
|
||||||
homeDir := homeDrive + homePath
|
|
||||||
if _, err := os.Stat(homeDir); err == nil {
|
|
||||||
return homeDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if userProfile := os.Getenv("USERPROFILE"); len(userProfile) > 0 {
|
|
||||||
if _, err := os.Stat(userProfile); err == nil {
|
|
||||||
return userProfile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return os.Getenv("HOME")
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ go_library(
|
||||||
"//pkg/client/leaderelection:go_default_library",
|
"//pkg/client/leaderelection:go_default_library",
|
||||||
"//pkg/client/leaderelection/resourcelock:go_default_library",
|
"//pkg/client/leaderelection/resourcelock:go_default_library",
|
||||||
"//pkg/client/record:go_default_library",
|
"//pkg/client/record:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/util/configz:go_default_library",
|
"//pkg/util/configz:go_default_library",
|
||||||
"//plugin/cmd/kube-scheduler/app/options:go_default_library",
|
"//plugin/cmd/kube-scheduler/app/options:go_default_library",
|
||||||
"//plugin/pkg/scheduler:go_default_library",
|
"//plugin/pkg/scheduler:go_default_library",
|
||||||
|
@ -34,6 +33,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
"//vendor:k8s.io/apiserver/pkg/server/healthz",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,13 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/server/healthz"
|
"k8s.io/apiserver/pkg/server/healthz"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1"
|
v1core "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection"
|
"k8s.io/kubernetes/pkg/client/leaderelection"
|
||||||
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
|
||||||
"k8s.io/kubernetes/pkg/client/record"
|
"k8s.io/kubernetes/pkg/client/record"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/util/configz"
|
"k8s.io/kubernetes/pkg/util/configz"
|
||||||
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
|
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
|
||||||
"k8s.io/kubernetes/plugin/pkg/scheduler"
|
"k8s.io/kubernetes/plugin/pkg/scheduler"
|
||||||
|
|
|
@ -21,7 +21,6 @@ go_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/api/resource:go_default_library",
|
"//pkg/api/resource:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//vendor:cloud.google.com/go/compute/metadata",
|
"//vendor:cloud.google.com/go/compute/metadata",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:github.com/hawkular/hawkular-client-go/metrics",
|
"//vendor:github.com/hawkular/hawkular-client-go/metrics",
|
||||||
|
@ -32,6 +31,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apiserver/pkg/admission",
|
"//vendor:k8s.io/apiserver/pkg/admission",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type hawkularSource struct {
|
type hawkularSource struct {
|
||||||
|
|
|
@ -52,7 +52,6 @@ go_library(
|
||||||
"//pkg/client/conditions:go_default_library",
|
"//pkg/client/conditions:go_default_library",
|
||||||
"//pkg/client/typed/discovery:go_default_library",
|
"//pkg/client/typed/discovery:go_default_library",
|
||||||
"//pkg/client/typed/dynamic:go_default_library",
|
"//pkg/client/typed/dynamic:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/client/unversioned/remotecommand:go_default_library",
|
"//pkg/client/unversioned/remotecommand:go_default_library",
|
||||||
"//pkg/cloudprovider:go_default_library",
|
"//pkg/cloudprovider:go_default_library",
|
||||||
"//pkg/cloudprovider/providers/gce:go_default_library",
|
"//pkg/cloudprovider/providers/gce:go_default_library",
|
||||||
|
@ -108,6 +107,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/watch",
|
"//vendor:k8s.io/apimachinery/pkg/watch",
|
||||||
"//vendor:k8s.io/client-go/kubernetes",
|
"//vendor:k8s.io/client-go/kubernetes",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/onsi/ginkgo/config"
|
"github.com/onsi/ginkgo/config"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
@ -76,7 +77,6 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/conditions"
|
"k8s.io/kubernetes/pkg/client/conditions"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
|
||||||
|
|
|
@ -32,7 +32,6 @@ go_library(
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
"//test/e2e/common:go_default_library",
|
"//test/e2e/common:go_default_library",
|
||||||
"//test/e2e/framework:go_default_library",
|
"//test/e2e/framework:go_default_library",
|
||||||
|
@ -43,6 +42,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
"//vendor:k8s.io/client-go/tools/clientcmd/api",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,9 +20,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
"k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
fedframework "k8s.io/kubernetes/test/e2e_federation/framework"
|
fedframework "k8s.io/kubernetes/test/e2e_federation/framework"
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,13 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/test/e2e/common"
|
"k8s.io/kubernetes/test/e2e/common"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
fedframework "k8s.io/kubernetes/test/e2e_federation/framework"
|
fedframework "k8s.io/kubernetes/test/e2e_federation/framework"
|
||||||
|
|
|
@ -21,7 +21,6 @@ go_library(
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/api/validation:go_default_library",
|
"//pkg/api/validation:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//test/e2e/framework:go_default_library",
|
"//test/e2e/framework:go_default_library",
|
||||||
"//vendor:github.com/onsi/ginkgo",
|
"//vendor:github.com/onsi/ginkgo",
|
||||||
"//vendor:github.com/onsi/gomega",
|
"//vendor:github.com/onsi/gomega",
|
||||||
|
@ -31,6 +30,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation",
|
"//vendor:k8s.io/apimachinery/pkg/util/validation",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,13 @@ import (
|
||||||
validationutil "k8s.io/apimachinery/pkg/util/validation"
|
validationutil "k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||||
"k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
"k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ package kubectl
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,7 +22,6 @@ go_library(
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/clientset:go_default_library",
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
|
||||||
"//pkg/util/intstr:go_default_library",
|
"//pkg/util/intstr:go_default_library",
|
||||||
"//test/e2e/framework:go_default_library",
|
"//test/e2e/framework:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
|
@ -30,6 +29,7 @@ go_library(
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
"//vendor:k8s.io/client-go/rest",
|
"//vendor:k8s.io/client-go/rest",
|
||||||
|
"//vendor:k8s.io/client-go/tools/clientcmd",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,10 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
|
||||||
"k8s.io/kubernetes/pkg/util/intstr"
|
"k8s.io/kubernetes/pkg/util/intstr"
|
||||||
e2e "k8s.io/kubernetes/test/e2e/framework"
|
e2e "k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue