Extend kubeconfig builder
Change-Id: I6724112826a4cc59815b7524bd05af01a9a1d01b
This commit is contained in:
parent
77268cd1d0
commit
d9f54b4171
@ -116,7 +116,7 @@ func (cm clusterMap) ClusterKubeconfigContext(clusterName string) (string, error
|
||||
|
||||
kubeContext := cluster.KubeconfigContext
|
||||
// if kubeContext is still empty, set it to clusterName
|
||||
if kubeContext == "" {
|
||||
if cluster.KubeconfigContext == "" {
|
||||
kubeContext = clusterName
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,18 @@
|
||||
package kubeconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/errors"
|
||||
"opendev.org/airship/airshipctl/pkg/fs"
|
||||
"opendev.org/airship/airshipctl/pkg/log"
|
||||
"opendev.org/airship/airshipctl/pkg/util"
|
||||
)
|
||||
|
||||
@ -40,7 +46,9 @@ type Builder struct {
|
||||
clusterName string
|
||||
root string
|
||||
|
||||
clusterMap clustermap.ClusterMap
|
||||
clusterMap clustermap.ClusterMap
|
||||
clusterctlClient client.Interface
|
||||
fs fs.FileSystem
|
||||
}
|
||||
|
||||
// WithPath allows to set path to prexisting kubeconfig
|
||||
@ -73,25 +81,35 @@ func (b *Builder) WithTempRoot(root string) *Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
// WithClusterctClient this is used if u want to inject your own clusterctl
|
||||
// mostly needed for tests
|
||||
func (b *Builder) WithClusterctClient(c client.Interface) *Builder {
|
||||
b.clusterctlClient = c
|
||||
return b
|
||||
}
|
||||
|
||||
// WithFilesytem allows to set filesystem
|
||||
func (b *Builder) WithFilesytem(fs fs.FileSystem) *Builder {
|
||||
b.fs = fs
|
||||
return b
|
||||
}
|
||||
|
||||
// Build builds a kubeconfig interface to be used
|
||||
func (b *Builder) Build() Interface {
|
||||
switch {
|
||||
case b.path != "":
|
||||
fSys := fs.NewDocumentFs()
|
||||
return NewKubeConfig(FromFile(b.path, fSys), InjectFilePath(b.path, fSys), InjectTempRoot(b.root))
|
||||
return NewKubeConfig(FromFile(b.path, b.fs), InjectFilePath(b.path, b.fs), InjectTempRoot(b.root))
|
||||
case b.fromParent():
|
||||
// TODO add method that would get kubeconfig from parent cluster and glue it together
|
||||
// with parent kubeconfig if needed
|
||||
return NewKubeConfig(func() ([]byte, error) {
|
||||
return nil, errors.ErrNotImplemented{}
|
||||
})
|
||||
// TODO consider adding various drivers to source kubeconfig from
|
||||
// Also consider accumulating different kubeconfigs, and returning one single
|
||||
// large file, so that every executor has access to all parent clusters.
|
||||
return NewKubeConfig(b.buildClusterctlFromParent, InjectTempRoot(b.root), InjectFileSystem(b.fs))
|
||||
case b.bundlePath != "":
|
||||
return NewKubeConfig(FromBundle(b.bundlePath), InjectTempRoot(b.root))
|
||||
return NewKubeConfig(FromBundle(b.bundlePath), InjectTempRoot(b.root), InjectFileSystem(b.fs))
|
||||
default:
|
||||
fSys := fs.NewDocumentFs()
|
||||
// return default path to kubeconfig file in airship workdir
|
||||
path := filepath.Join(util.UserHomeDir(), config.AirshipConfigDir, KubeconfigDefaultFileName)
|
||||
return NewKubeConfig(FromFile(path, fSys), InjectFilePath(path, fSys), InjectTempRoot(b.root))
|
||||
return NewKubeConfig(FromFile(path, b.fs), InjectFilePath(path, b.fs), InjectTempRoot(b.root))
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,3 +120,103 @@ func (b *Builder) fromParent() bool {
|
||||
}
|
||||
return b.clusterMap.DynamicKubeConfig(b.clusterName)
|
||||
}
|
||||
|
||||
func (b *Builder) buildClusterctlFromParent() ([]byte, error) {
|
||||
currentCluster := b.clusterName
|
||||
log.Printf("current cluster name is '%s'",
|
||||
currentCluster)
|
||||
parentCluster, err := b.clusterMap.ParentCluster(currentCluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentKubeconfig := b.WithClusterName(parentCluster).Build()
|
||||
|
||||
f, cleanup, err := parentKubeconfig.GetFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
parentCtx, err := b.clusterMap.ClusterKubeconfigContext(parentCluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusterAPIRef, err := b.clusterMap.ClusterAPIRef(currentCluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.clusterctlClient == nil {
|
||||
b.clusterctlClient, err = client.NewClient("", log.DebugEnabled(), v1alpha1.DefaultClusterctl())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Getting child kubeconfig from parent, parent context '%s', parent kubeconfing '%s'",
|
||||
parentCtx, f)
|
||||
|
||||
stringChild, err := b.clusterctlClient.GetKubeconfig(&client.GetKubeconfigOptions{
|
||||
ParentKubeconfigPath: f,
|
||||
ParentKubeconfigContext: parentCtx,
|
||||
ManagedClusterNamespace: clusterAPIRef.Namespace,
|
||||
ManagedClusterName: clusterAPIRef.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
err = parentKubeconfig.Write(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentObj, err := clientcmd.Load(buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
childObj, err := clientcmd.Load([]byte(stringChild))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
childCtx, err := b.clusterMap.ClusterKubeconfigContext(currentCluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("Merging '%s' cluster kubeconfig into '%s' cluster kubeconfig",
|
||||
currentCluster, parentCluster)
|
||||
|
||||
return b.mergeOneContext(childCtx, parentObj, childObj)
|
||||
}
|
||||
|
||||
// merges two kubeconfigs,
|
||||
func (b *Builder) mergeOneContext(contextOverride string, dst, src *api.Config) ([]byte, error) {
|
||||
for key, content := range src.AuthInfos {
|
||||
dst.AuthInfos[key] = content
|
||||
}
|
||||
|
||||
for key, content := range src.Clusters {
|
||||
dst.Clusters[key] = content
|
||||
}
|
||||
|
||||
if len(src.Contexts) != 1 {
|
||||
return nil, &ErrClusterctlKubeconfigWrongContextsCount{
|
||||
ContextCount: len(src.Contexts),
|
||||
}
|
||||
}
|
||||
|
||||
for key, content := range src.Contexts {
|
||||
if contextOverride == "" {
|
||||
contextOverride = key
|
||||
}
|
||||
dst.Contexts[contextOverride] = content
|
||||
}
|
||||
|
||||
return clientcmd.Write(*dst)
|
||||
}
|
||||
|
@ -16,17 +16,65 @@ package kubeconfig_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/fs"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
||||
"opendev.org/airship/airshipctl/pkg/util"
|
||||
"opendev.org/airship/airshipctl/testutil/clusterctl"
|
||||
testfs "opendev.org/airship/airshipctl/testutil/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
testKubeconfigString = `apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: c29tZWNlcnQK
|
||||
server: https://10.23.25.101:6443
|
||||
name: child_cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: child_cluster
|
||||
user: child_user
|
||||
name: child
|
||||
current-context: dummy_cluster
|
||||
preferences: {}
|
||||
users:
|
||||
- name: child_user
|
||||
user:
|
||||
client-certificate-data: c29tZWNlcnQK
|
||||
client-key-data: c29tZWNlcnQK`
|
||||
testKubeconfigStringSecond = `apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: c29tZWNlcnQK
|
||||
server: https://10.23.25.101:6443
|
||||
name: parent_cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: parent_cluster
|
||||
user: parent_admin
|
||||
name: parent-context
|
||||
current-context: dummy_cluster
|
||||
preferences: {}
|
||||
users:
|
||||
- name: parent_admin
|
||||
user:
|
||||
client-certificate-data: c29tZWNlcnQK
|
||||
client-key-data: c29tZWNlcnQK`
|
||||
)
|
||||
|
||||
func TestBuilder(t *testing.T) {
|
||||
@ -38,7 +86,7 @@ func TestBuilder(t *testing.T) {
|
||||
err := kube.Write(buf)
|
||||
require.NoError(t, err)
|
||||
// check that kubeconfig contains expected cluster string
|
||||
assert.Contains(t, buf.String(), "dummycluster_ephemeral")
|
||||
assert.Contains(t, buf.String(), "parent_parent_context")
|
||||
})
|
||||
|
||||
t.Run("Only filepath", func(t *testing.T) {
|
||||
@ -52,33 +100,6 @@ func TestBuilder(t *testing.T) {
|
||||
assert.Contains(t, buf.String(), "dummycluster_ephemeral")
|
||||
})
|
||||
|
||||
t.Run("Only cluster map", func(t *testing.T) {
|
||||
childCluster := "child"
|
||||
parentCluster := "parent"
|
||||
clusterMap := &v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
Parent: parentCluster,
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
parentCluster: {
|
||||
DynamicKubeConfig: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
builder := kubeconfig.NewBuilder().
|
||||
WithClusterMap(clustermap.NewClusterMap(clusterMap)).
|
||||
WithClusterName(childCluster)
|
||||
kube := builder.Build()
|
||||
// This should not be implemented yet, and we need to check that we are getting there
|
||||
require.NotNil(t, kube)
|
||||
filePath, cleanup, err := kube.GetFile()
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "not implemented")
|
||||
assert.Equal(t, "", filePath)
|
||||
require.Nil(t, cleanup)
|
||||
})
|
||||
|
||||
t.Run("No current cluster, fall to default", func(t *testing.T) {
|
||||
clusterMap := &v1alpha1.ClusterMap{}
|
||||
builder := kubeconfig.NewBuilder().
|
||||
@ -93,27 +114,6 @@ func TestBuilder(t *testing.T) {
|
||||
assert.Equal(t, path, actualPath)
|
||||
})
|
||||
|
||||
t.Run("Dynamic, but no parent", func(t *testing.T) {
|
||||
childCluster := "child"
|
||||
clusterMap := &v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
builder := kubeconfig.NewBuilder().
|
||||
WithClusterMap(clustermap.NewClusterMap(clusterMap)).
|
||||
WithClusterName(childCluster)
|
||||
kube := builder.Build()
|
||||
// We should get a default value for cluster, as we can't find parent cluster
|
||||
filePath, cleanup, err := kube.GetFile()
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "not implemented")
|
||||
assert.Equal(t, "", filePath)
|
||||
require.Nil(t, cleanup)
|
||||
})
|
||||
|
||||
t.Run("Default source", func(t *testing.T) {
|
||||
builder := kubeconfig.NewBuilder()
|
||||
kube := builder.Build()
|
||||
@ -126,3 +126,158 @@ func TestBuilder(t *testing.T) {
|
||||
assert.Equal(t, path, actualPath)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderClusterctl(t *testing.T) {
|
||||
childCluster := "child"
|
||||
parentCluster := "parent"
|
||||
testBundlePath := "testdata"
|
||||
kubeconfigPath := filepath.Join(testBundlePath, "kubeconfig-12341234")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
errString string
|
||||
requestedClusterName string
|
||||
parentClusterName string
|
||||
tempRoot string
|
||||
clusterMap clustermap.ClusterMap
|
||||
clusterctlClient client.Interface
|
||||
fs fs.FileSystem
|
||||
}{
|
||||
{
|
||||
name: "error no parent context",
|
||||
errString: fmt.Sprintf("context \"%s\" does not exist", parentCluster),
|
||||
parentClusterName: parentCluster,
|
||||
requestedClusterName: childCluster,
|
||||
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
Parent: parentCluster,
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
parentCluster: {
|
||||
DynamicKubeConfig: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "error dynamic but no parrent",
|
||||
parentClusterName: parentCluster,
|
||||
requestedClusterName: childCluster,
|
||||
errString: "failed to find a parent",
|
||||
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "error write temp parent",
|
||||
parentClusterName: parentCluster,
|
||||
requestedClusterName: childCluster,
|
||||
tempRoot: "does not exist anywhere",
|
||||
errString: "no such file or directory",
|
||||
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
Parent: parentCluster,
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
parentCluster: {
|
||||
DynamicKubeConfig: false,
|
||||
KubeconfigContext: "dummy_cluster",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
parentClusterName: parentCluster,
|
||||
requestedClusterName: childCluster,
|
||||
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
|
||||
Map: map[string]*v1alpha1.Cluster{
|
||||
childCluster: {
|
||||
Parent: parentCluster,
|
||||
DynamicKubeConfig: true,
|
||||
},
|
||||
parentCluster: {
|
||||
DynamicKubeConfig: true,
|
||||
KubeconfigContext: "parent-custom",
|
||||
Parent: "parent-parent",
|
||||
},
|
||||
"parent-parent": {
|
||||
DynamicKubeConfig: false,
|
||||
KubeconfigContext: "parent_parent_context",
|
||||
},
|
||||
},
|
||||
}),
|
||||
tempRoot: "testdata",
|
||||
fs: testfs.MockFileSystem{
|
||||
MockRemoveAll: func() error { return nil },
|
||||
MockTempFile: func(s1, s2 string) (fs.File, error) {
|
||||
return testfs.TestFile{
|
||||
MockName: func() string { return kubeconfigPath },
|
||||
MockWrite: func() (int, error) { return 0, nil },
|
||||
MockClose: func() error { return nil },
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
clusterctlClient: func() client.Interface {
|
||||
c := &clusterctl.MockInterface{
|
||||
Mock: mock.Mock{},
|
||||
}
|
||||
c.On("GetKubeconfig", &client.GetKubeconfigOptions{
|
||||
ParentKubeconfigPath: kubeconfigPath,
|
||||
ParentKubeconfigContext: "parent-custom",
|
||||
ManagedClusterNamespace: clustermap.DefaultClusterAPIObjNamespace,
|
||||
ManagedClusterName: childCluster,
|
||||
}).Once().Return(testKubeconfigString, nil)
|
||||
c.On("GetKubeconfig", &client.GetKubeconfigOptions{
|
||||
ParentKubeconfigPath: kubeconfigPath,
|
||||
ParentKubeconfigContext: "parent_parent_context",
|
||||
ManagedClusterNamespace: clustermap.DefaultClusterAPIObjNamespace,
|
||||
ManagedClusterName: parentCluster,
|
||||
}).Once().Return(testKubeconfigStringSecond, nil)
|
||||
return c
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
kube := kubeconfig.NewBuilder().
|
||||
WithClusterMap(tt.clusterMap).
|
||||
WithClusterName(tt.requestedClusterName).
|
||||
WithBundle(testBundlePath).
|
||||
WithTempRoot(tt.tempRoot).
|
||||
WithClusterctClient(tt.clusterctlClient).
|
||||
WithFilesytem(tt.fs).
|
||||
Build()
|
||||
require.NotNil(t, kube)
|
||||
filePath, cleanup, err := kube.GetFile()
|
||||
// This is needed to avoid leftovers on test failures
|
||||
if cleanup != nil {
|
||||
defer cleanup()
|
||||
}
|
||||
|
||||
if tt.errString != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.errString)
|
||||
assert.Equal(t, "", filePath)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "", filePath)
|
||||
assert.NotNil(t, cleanup)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
err := kube.Write(buf)
|
||||
require.NoError(t, err)
|
||||
result, err := ioutil.ReadFile("testdata/result-kubeconf")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, result, buf.Bytes())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
package kubeconfig
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ErrKubeConfigPathEmpty returned when kubeconfig path is not specified
|
||||
type ErrKubeConfigPathEmpty struct {
|
||||
}
|
||||
@ -21,3 +23,14 @@ type ErrKubeConfigPathEmpty struct {
|
||||
func (e *ErrKubeConfigPathEmpty) Error() string {
|
||||
return "kubeconfig path is not defined"
|
||||
}
|
||||
|
||||
// ErrClusterctlKubeconfigWrongContextsCount is returned when clusterctl client returns
|
||||
// multiple or no contexts in kubeconfig for the child cluster
|
||||
type ErrClusterctlKubeconfigWrongContextsCount struct {
|
||||
ContextCount int
|
||||
}
|
||||
|
||||
func (e *ErrClusterctlKubeconfigWrongContextsCount) Error() string {
|
||||
return fmt.Sprintf("clusterctl client returned '%d' contexts in kubeconfig "+
|
||||
"context count must exactly one", e.ContextCount)
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ import (
|
||||
"opendev.org/airship/airshipctl/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
// KubeconfigPrefix is a prefix that is added when writing temporary kubeconfig files
|
||||
KubeconfigPrefix = "kubeconfig-"
|
||||
)
|
||||
|
||||
// Interface provides a uniform way to interact with kubeconfig file
|
||||
type Interface interface {
|
||||
// GetFile returns path to kubeconfig file and a function to remove it
|
||||
@ -43,8 +48,9 @@ type Interface interface {
|
||||
var _ Interface = &kubeConfig{}
|
||||
|
||||
type kubeConfig struct {
|
||||
path string
|
||||
dumpRoot string
|
||||
path string
|
||||
dumpRoot string
|
||||
savedByes []byte
|
||||
|
||||
fileSystem fs.FileSystem
|
||||
sourceFunc KubeSourceFunc
|
||||
@ -104,6 +110,9 @@ func FromSecret(c client.Interface, o *client.GetKubeconfigOptions) KubeSourceFu
|
||||
// FromFile returns KubeSource type, uses path to kubeconfig on FS as source to construct kubeconfig object
|
||||
func FromFile(path string, fSys fs.FileSystem) KubeSourceFunc {
|
||||
return func() ([]byte, error) {
|
||||
if fSys == nil {
|
||||
fSys = fs.NewDocumentFs()
|
||||
}
|
||||
return fSys.ReadFile(path)
|
||||
}
|
||||
}
|
||||
@ -160,7 +169,7 @@ func InjectFilePath(path string, fSys fs.FileSystem) Option {
|
||||
}
|
||||
|
||||
func (k *kubeConfig) WriteFile(path string) (err error) {
|
||||
data, err := k.sourceFunc()
|
||||
data, err := k.bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -168,7 +177,7 @@ func (k *kubeConfig) WriteFile(path string) (err error) {
|
||||
}
|
||||
|
||||
func (k *kubeConfig) Write(w io.Writer) (err error) {
|
||||
data, err := k.sourceFunc()
|
||||
data, err := k.bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -178,11 +187,11 @@ func (k *kubeConfig) Write(w io.Writer) (err error) {
|
||||
|
||||
// WriteTempFile implements kubeconfig Interface
|
||||
func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
||||
data, err := k.sourceFunc()
|
||||
data, err := k.bytes()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
file, err := k.fileSystem.TempFile(root, "kubeconfig-")
|
||||
file, err := k.fileSystem.TempFile(root, KubeconfigPrefix)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -197,6 +206,14 @@ func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
||||
return fName, cleanup(fName, k.fileSystem), nil
|
||||
}
|
||||
|
||||
func (k *kubeConfig) bytes() ([]byte, error) {
|
||||
var err error
|
||||
if len(k.savedByes) == 0 {
|
||||
k.savedByes, err = k.sourceFunc()
|
||||
}
|
||||
return k.savedByes, err
|
||||
}
|
||||
|
||||
// GetFile checks if path to kubeconfig is already set and returns it no cleanup is necessary,
|
||||
// and Cleanup() method will do nothing.
|
||||
// If path is not set kubeconfig will be written to temporary file system, returned path will
|
||||
|
@ -54,27 +54,6 @@ users:
|
||||
user:
|
||||
client-certificate-data: cert-data
|
||||
client-key-data: client-keydata
|
||||
`
|
||||
//nolint: lll
|
||||
testFullValidKubeconfig = `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://10.23.25.101:6443
|
||||
name: dummycluster_ephemeral
|
||||
contexts:
|
||||
- context:
|
||||
cluster: dummycluster_ephemeral
|
||||
user: kubernetes-admin
|
||||
name: dummy_cluster
|
||||
current-context: dummy_cluster
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kubernetes-admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
`
|
||||
)
|
||||
|
||||
@ -179,28 +158,26 @@ func TestFromSecret(t *testing.T) {
|
||||
|
||||
func TestFromBundle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rootPath string
|
||||
shouldFail bool
|
||||
expectedData []byte
|
||||
name string
|
||||
rootPath string
|
||||
expectedContains string
|
||||
shouldFail bool
|
||||
}{
|
||||
{
|
||||
name: "valid kubeconfig",
|
||||
rootPath: "testdata",
|
||||
shouldFail: false,
|
||||
expectedData: []byte(testFullValidKubeconfig),
|
||||
name: "valid kubeconfig",
|
||||
rootPath: "testdata",
|
||||
shouldFail: false,
|
||||
expectedContains: "parent_parent_context",
|
||||
},
|
||||
{
|
||||
name: "wrong path",
|
||||
rootPath: "wrong/path",
|
||||
shouldFail: true,
|
||||
expectedData: nil,
|
||||
name: "wrong path",
|
||||
rootPath: "wrong/path",
|
||||
shouldFail: true,
|
||||
},
|
||||
{
|
||||
name: "kubeconfig not found",
|
||||
rootPath: "testdata_fail",
|
||||
shouldFail: true,
|
||||
expectedData: nil,
|
||||
name: "kubeconfig not found",
|
||||
rootPath: "testdata_fail",
|
||||
shouldFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
@ -213,7 +190,7 @@ func TestFromBundle(t *testing.T) {
|
||||
assert.Nil(t, kubeconf)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedData, kubeconf)
|
||||
assert.Contains(t, string(kubeconf), tt.expectedContains)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
10
pkg/k8s/kubeconfig/testdata/kubeconfig.yaml
vendored
10
pkg/k8s/kubeconfig/testdata/kubeconfig.yaml
vendored
@ -9,16 +9,16 @@ config:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://10.23.25.101:6443
|
||||
name: dummycluster_ephemeral
|
||||
name: parent_parent_cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: dummycluster_ephemeral
|
||||
user: kubernetes-admin
|
||||
name: dummy_cluster
|
||||
cluster: parent_parent_cluster
|
||||
user: parent_parent_admin
|
||||
name: parent_parent_context
|
||||
current-context: dummy_cluster
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kubernetes-admin
|
||||
- name: parent_parent_admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
||||
|
43
pkg/k8s/kubeconfig/testdata/result-kubeconf
vendored
Normal file
43
pkg/k8s/kubeconfig/testdata/result-kubeconf
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: c29tZWNlcnQK
|
||||
server: https://10.23.25.101:6443
|
||||
name: child_cluster
|
||||
- cluster:
|
||||
certificate-authority-data: c29tZWNlcnQK
|
||||
server: https://10.23.25.101:6443
|
||||
name: parent_cluster
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://10.23.25.101:6443
|
||||
name: parent_parent_cluster
|
||||
contexts:
|
||||
- context:
|
||||
cluster: child_cluster
|
||||
user: child_user
|
||||
name: child
|
||||
- context:
|
||||
cluster: parent_cluster
|
||||
user: parent_admin
|
||||
name: parent-custom
|
||||
- context:
|
||||
cluster: parent_parent_cluster
|
||||
user: parent_parent_admin
|
||||
name: parent_parent_context
|
||||
current-context: dummy_cluster
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: child_user
|
||||
user:
|
||||
client-certificate-data: c29tZWNlcnQK
|
||||
client-key-data: c29tZWNlcnQK
|
||||
- name: parent_admin
|
||||
user:
|
||||
client-certificate-data: c29tZWNlcnQK
|
||||
client-key-data: c29tZWNlcnQK
|
||||
- name: parent_parent_admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
68
testutil/clusterctl/client.go
Normal file
68
testutil/clusterctl/client.go
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
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
|
||||
|
||||
https://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 clusterctl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||
)
|
||||
|
||||
var _ client.Interface = &MockInterface{}
|
||||
|
||||
// MockInterface provides mock interface for clusterctl
|
||||
type MockInterface struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Init to be implemented
|
||||
func (m *MockInterface) Init(kubeconfigPath, kubeconfigContext string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Move to be implemented
|
||||
func (m *MockInterface) Move(fkp, fkc, tkp, tkc, namespace string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Render to be implemented
|
||||
func (m *MockInterface) Render(client.RenderOptions) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetKubeconfig allows to control exepected input to the function and check expected output
|
||||
// example usage:
|
||||
// c := &clusterctl.MockInterface{
|
||||
// Mock: mock.Mock{},
|
||||
// }
|
||||
// c.On("GetKubeconfig").Once().Return(&client.GetKubeconfigOptions{
|
||||
// ParentKubeconfigPath: filepath.Join("testdata", kubeconfig.KubeconfigPrefix),
|
||||
// ParentKubeconfigContext: "dummy_cluster",
|
||||
// ManagedClusterNamespace: clustermap.DefaultClusterAPIObjNamespace,
|
||||
// ManagedClusterName: childCluster,
|
||||
// }, "kubeconfig data", nil)
|
||||
// first argument in return function is what you expect as input
|
||||
// second argument is resulting expected string
|
||||
// third is resulting error
|
||||
func (m *MockInterface) GetKubeconfig(options *client.GetKubeconfigOptions) (string, error) {
|
||||
args := m.Called(options)
|
||||
expectedResult, ok := args.Get(0).(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("wrong input")
|
||||
}
|
||||
return expectedResult, args.Error(1)
|
||||
}
|
Loading…
Reference in New Issue
Block a user