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
|
kubeContext := cluster.KubeconfigContext
|
||||||
// if kubeContext is still empty, set it to clusterName
|
// if kubeContext is still empty, set it to clusterName
|
||||||
if kubeContext == "" {
|
if cluster.KubeconfigContext == "" {
|
||||||
kubeContext = clusterName
|
kubeContext = clusterName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,18 @@
|
|||||||
package kubeconfig
|
package kubeconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"path/filepath"
|
"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/cluster/clustermap"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/errors"
|
|
||||||
"opendev.org/airship/airshipctl/pkg/fs"
|
"opendev.org/airship/airshipctl/pkg/fs"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/log"
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,6 +47,8 @@ type Builder struct {
|
|||||||
root string
|
root string
|
||||||
|
|
||||||
clusterMap clustermap.ClusterMap
|
clusterMap clustermap.ClusterMap
|
||||||
|
clusterctlClient client.Interface
|
||||||
|
fs fs.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPath allows to set path to prexisting kubeconfig
|
// WithPath allows to set path to prexisting kubeconfig
|
||||||
@ -73,25 +81,35 @@ func (b *Builder) WithTempRoot(root string) *Builder {
|
|||||||
return b
|
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
|
// Build builds a kubeconfig interface to be used
|
||||||
func (b *Builder) Build() Interface {
|
func (b *Builder) Build() Interface {
|
||||||
switch {
|
switch {
|
||||||
case b.path != "":
|
case b.path != "":
|
||||||
fSys := fs.NewDocumentFs()
|
return NewKubeConfig(FromFile(b.path, b.fs), InjectFilePath(b.path, b.fs), InjectTempRoot(b.root))
|
||||||
return NewKubeConfig(FromFile(b.path, fSys), InjectFilePath(b.path, fSys), InjectTempRoot(b.root))
|
|
||||||
case b.fromParent():
|
case b.fromParent():
|
||||||
// TODO add method that would get kubeconfig from parent cluster and glue it together
|
// TODO consider adding various drivers to source kubeconfig from
|
||||||
// with parent kubeconfig if needed
|
// Also consider accumulating different kubeconfigs, and returning one single
|
||||||
return NewKubeConfig(func() ([]byte, error) {
|
// large file, so that every executor has access to all parent clusters.
|
||||||
return nil, errors.ErrNotImplemented{}
|
return NewKubeConfig(b.buildClusterctlFromParent, InjectTempRoot(b.root), InjectFileSystem(b.fs))
|
||||||
})
|
|
||||||
case b.bundlePath != "":
|
case b.bundlePath != "":
|
||||||
return NewKubeConfig(FromBundle(b.bundlePath), InjectTempRoot(b.root))
|
return NewKubeConfig(FromBundle(b.bundlePath), InjectTempRoot(b.root), InjectFileSystem(b.fs))
|
||||||
default:
|
default:
|
||||||
fSys := fs.NewDocumentFs()
|
|
||||||
// return default path to kubeconfig file in airship workdir
|
// return default path to kubeconfig file in airship workdir
|
||||||
path := filepath.Join(util.UserHomeDir(), config.AirshipConfigDir, KubeconfigDefaultFileName)
|
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)
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
"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/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/fs"
|
||||||
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"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) {
|
func TestBuilder(t *testing.T) {
|
||||||
@ -38,7 +86,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
err := kube.Write(buf)
|
err := kube.Write(buf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// check that kubeconfig contains expected cluster string
|
// 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) {
|
t.Run("Only filepath", func(t *testing.T) {
|
||||||
@ -52,33 +100,6 @@ func TestBuilder(t *testing.T) {
|
|||||||
assert.Contains(t, buf.String(), "dummycluster_ephemeral")
|
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) {
|
t.Run("No current cluster, fall to default", func(t *testing.T) {
|
||||||
clusterMap := &v1alpha1.ClusterMap{}
|
clusterMap := &v1alpha1.ClusterMap{}
|
||||||
builder := kubeconfig.NewBuilder().
|
builder := kubeconfig.NewBuilder().
|
||||||
@ -93,27 +114,6 @@ func TestBuilder(t *testing.T) {
|
|||||||
assert.Equal(t, path, actualPath)
|
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) {
|
t.Run("Default source", func(t *testing.T) {
|
||||||
builder := kubeconfig.NewBuilder()
|
builder := kubeconfig.NewBuilder()
|
||||||
kube := builder.Build()
|
kube := builder.Build()
|
||||||
@ -126,3 +126,158 @@ func TestBuilder(t *testing.T) {
|
|||||||
assert.Equal(t, path, actualPath)
|
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
|
package kubeconfig
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// ErrKubeConfigPathEmpty returned when kubeconfig path is not specified
|
// ErrKubeConfigPathEmpty returned when kubeconfig path is not specified
|
||||||
type ErrKubeConfigPathEmpty struct {
|
type ErrKubeConfigPathEmpty struct {
|
||||||
}
|
}
|
||||||
@ -21,3 +23,14 @@ type ErrKubeConfigPathEmpty struct {
|
|||||||
func (e *ErrKubeConfigPathEmpty) Error() string {
|
func (e *ErrKubeConfigPathEmpty) Error() string {
|
||||||
return "kubeconfig path is not defined"
|
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"
|
"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
|
// Interface provides a uniform way to interact with kubeconfig file
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
// GetFile returns path to kubeconfig file and a function to remove it
|
// GetFile returns path to kubeconfig file and a function to remove it
|
||||||
@ -45,6 +50,7 @@ var _ Interface = &kubeConfig{}
|
|||||||
type kubeConfig struct {
|
type kubeConfig struct {
|
||||||
path string
|
path string
|
||||||
dumpRoot string
|
dumpRoot string
|
||||||
|
savedByes []byte
|
||||||
|
|
||||||
fileSystem fs.FileSystem
|
fileSystem fs.FileSystem
|
||||||
sourceFunc KubeSourceFunc
|
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
|
// FromFile returns KubeSource type, uses path to kubeconfig on FS as source to construct kubeconfig object
|
||||||
func FromFile(path string, fSys fs.FileSystem) KubeSourceFunc {
|
func FromFile(path string, fSys fs.FileSystem) KubeSourceFunc {
|
||||||
return func() ([]byte, error) {
|
return func() ([]byte, error) {
|
||||||
|
if fSys == nil {
|
||||||
|
fSys = fs.NewDocumentFs()
|
||||||
|
}
|
||||||
return fSys.ReadFile(path)
|
return fSys.ReadFile(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +169,7 @@ func InjectFilePath(path string, fSys fs.FileSystem) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *kubeConfig) WriteFile(path string) (err error) {
|
func (k *kubeConfig) WriteFile(path string) (err error) {
|
||||||
data, err := k.sourceFunc()
|
data, err := k.bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -168,7 +177,7 @@ func (k *kubeConfig) WriteFile(path string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *kubeConfig) Write(w io.Writer) (err error) {
|
func (k *kubeConfig) Write(w io.Writer) (err error) {
|
||||||
data, err := k.sourceFunc()
|
data, err := k.bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -178,11 +187,11 @@ func (k *kubeConfig) Write(w io.Writer) (err error) {
|
|||||||
|
|
||||||
// WriteTempFile implements kubeconfig Interface
|
// WriteTempFile implements kubeconfig Interface
|
||||||
func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
||||||
data, err := k.sourceFunc()
|
data, err := k.bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
file, err := k.fileSystem.TempFile(root, "kubeconfig-")
|
file, err := k.fileSystem.TempFile(root, KubeconfigPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
@ -197,6 +206,14 @@ func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
|||||||
return fName, cleanup(fName, k.fileSystem), nil
|
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,
|
// GetFile checks if path to kubeconfig is already set and returns it no cleanup is necessary,
|
||||||
// and Cleanup() method will do nothing.
|
// and Cleanup() method will do nothing.
|
||||||
// If path is not set kubeconfig will be written to temporary file system, returned path will
|
// If path is not set kubeconfig will be written to temporary file system, returned path will
|
||||||
|
@ -54,27 +54,6 @@ users:
|
|||||||
user:
|
user:
|
||||||
client-certificate-data: cert-data
|
client-certificate-data: cert-data
|
||||||
client-key-data: client-keydata
|
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=
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -181,26 +160,24 @@ func TestFromBundle(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
rootPath string
|
rootPath string
|
||||||
|
expectedContains string
|
||||||
shouldFail bool
|
shouldFail bool
|
||||||
expectedData []byte
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid kubeconfig",
|
name: "valid kubeconfig",
|
||||||
rootPath: "testdata",
|
rootPath: "testdata",
|
||||||
shouldFail: false,
|
shouldFail: false,
|
||||||
expectedData: []byte(testFullValidKubeconfig),
|
expectedContains: "parent_parent_context",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "wrong path",
|
name: "wrong path",
|
||||||
rootPath: "wrong/path",
|
rootPath: "wrong/path",
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
expectedData: nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "kubeconfig not found",
|
name: "kubeconfig not found",
|
||||||
rootPath: "testdata_fail",
|
rootPath: "testdata_fail",
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
expectedData: nil,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +190,7 @@ func TestFromBundle(t *testing.T) {
|
|||||||
assert.Nil(t, kubeconf)
|
assert.Nil(t, kubeconf)
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
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:
|
- cluster:
|
||||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||||
server: https://10.23.25.101:6443
|
server: https://10.23.25.101:6443
|
||||||
name: dummycluster_ephemeral
|
name: parent_parent_cluster
|
||||||
contexts:
|
contexts:
|
||||||
- context:
|
- context:
|
||||||
cluster: dummycluster_ephemeral
|
cluster: parent_parent_cluster
|
||||||
user: kubernetes-admin
|
user: parent_parent_admin
|
||||||
name: dummy_cluster
|
name: parent_parent_context
|
||||||
current-context: dummy_cluster
|
current-context: dummy_cluster
|
||||||
preferences: {}
|
preferences: {}
|
||||||
users:
|
users:
|
||||||
- name: kubernetes-admin
|
- name: parent_parent_admin
|
||||||
user:
|
user:
|
||||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwRENDQXJnQ0ZFdFBveEZYSjVrVFNWTXQ0OVlqcHBQL3hCYnlNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1CVXgKRXpBUkJnTlZCQU1UQ210MVltVnlibVYwWlhNd0hoY05NakF3TVRJME1Ua3hOVEV3V2hjTk1qa3hNakF5TVRreApOVEV3V2pBME1Sa3dGd1lEVlFRRERCQnJkV0psY201bGRHVnpMV0ZrYldsdU1SY3dGUVlEVlFRS0RBNXplWE4wClpXMDZiV0Z6ZEdWeWN6Q0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQU1iaFhUUmsKVjZiZXdsUjBhZlpBdTBGYWVsOXRtRThaSFEvaGtaSHhuTjc2bDZUUFltcGJvaDRvRjNGMFFqbzROS1o5NVRuWgo0OWNoV240eFJiZVlPU25EcDBpV0Qzd0pXUlZ5aVFvVUFyYTlNcHVPNkVFU1FpbFVGNXNxc0VXUVdVMjBETStBCkdxK1k0Z2c3eDJ1Q0hTdk1GUmkrNEw5RWlXR2xnRDIvb1hXUm5NWEswNExQajZPb3Vkb2Zid2RmT3J6dTBPVkUKUzR0eGtuS1BCY1BUU3YxMWVaWVhja0JEVjNPbExENEZ3dTB3NTcwcnczNzAraEpYdlZxd3Zjb2RjZjZEL1BXWQowamlnd2ppeUJuZ2dXYW04UVFjd1Nud3o0d05sV3hKOVMyWUJFb1ptdWxVUlFaWVk5ZXRBcEpBdFMzTjlUNlQ2ClovSlJRdEdhZDJmTldTYkxEck5qdU1OTGhBYWRMQnhJUHpBNXZWWk5aalJkdEMwU25pMlFUMTVpSFp4d1RxcjQKakRQQ0pYRXU3KytxcWpQVldUaUZLK3JqcVNhS1pqVWZVaUpHQkJWcm5RZkJENHNtRnNkTjB5cm9tYTZOYzRMNQpKS21RV1NHdmd1aG0zbW5sYjFRaVRZanVyZFJQRFNmdmwrQ0NHbnA1QkkvZ1pwMkF1SHMvNUpKVTJlc1ZvL0xsCkVPdHdSOXdXd3dXcTAvZjhXS3R4bVRrMTUyOUp2dFBGQXQweW1CVjhQbHZlYnVwYmJqeW5pL2xWbTJOYmV6dWUKeCtlMEpNbGtWWnFmYkRSS243SjZZSnJHWW1CUFV0QldoSVkzb1pJVTFEUXI4SUlIbkdmYlZoWlR5ME1IMkFCQQp1dlVQcUtSVk80UGkxRTF4OEE2eWVPeVRDcnB4L0pBazVyR2RBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBSWNFM1BxZHZDTVBIMnJzMXJESk9ESHY3QWk4S01PVXZPRi90RjlqR2EvSFBJbkh3RlVFNEltbldQeDYKVUdBMlE1bjFsRDFGQlU0T0M4eElZc3VvS1VQVHk1T0t6SVNMNEZnL0lEcG54STlrTXlmNStMR043aG8rblJmawpCZkpJblVYb0tERW1neHZzSWFGd1h6bGtSTDJzL1lKYUZRRzE1Uis1YzFyckJmd2dJOFA5Tkd6aEM1cXhnSmovCm04K3hPMGhXUmJIYklrQ21NekRib2pCSWhaL00rb3VYR1doei9TakpodXhZTVBnek5MZkFGcy9PMTVaSjd3YXcKZ3ZoSGc3L2E5UzRvUCtEYytPa3VrMkV1MUZjL0E5WHpWMzc5aWhNWW5ub3RQMldWeFZ3b0ZZQUg0NUdQcDZsUApCQmwyNnkxc2JMbjl6aGZYUUJIMVpFN0EwZVE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
|
||||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
|
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