Add kubeconfig interface
This will allow to use various sources for kubeconfig and provide utility to write, save, and clean kubeconfig files, as well as use kubeconfig interface for phase executors. Relates-To: #264 Change-Id: Ia5b5af00700a0adf55124e1dd335d570515ed804
This commit is contained in:
parent
f61953bcf5
commit
da12ae925d
23
pkg/k8s/kubeconfig/errors.go
Normal file
23
pkg/k8s/kubeconfig/errors.go
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
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 kubeconfig
|
||||
|
||||
// ErrKubeConfigPathEmpty returned when kubeconfig path is not specified
|
||||
type ErrKubeConfigPathEmpty struct {
|
||||
}
|
||||
|
||||
func (e *ErrKubeConfigPathEmpty) Error() string {
|
||||
return "kubeconfig path is not defined"
|
||||
}
|
@ -14,18 +14,167 @@
|
||||
|
||||
package kubeconfig
|
||||
|
||||
// File determines where kubeconfig is located on file system and which context to use
|
||||
type File struct {
|
||||
Path string
|
||||
Context string
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
)
|
||||
|
||||
// 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
|
||||
// if error is returned cleanup is not needed
|
||||
GetFile() (string, Cleanup, error)
|
||||
// Write will write kubeconfig to the provided writer
|
||||
Write(w io.Writer) error
|
||||
// WriteFile will write kubeconfig data to specified path
|
||||
WriteFile(path string) error
|
||||
// WriteTempFile writes a file a temporary file, returns path to it, cleanup function and error
|
||||
// it is responsibility of the caller to use the cleanup function to make sure that there are no leftovers
|
||||
WriteTempFile(dumpRoot string) (string, Cleanup, error)
|
||||
}
|
||||
|
||||
// Provider interface allows to get kubeconfig file path and context based on cluster type
|
||||
type Provider interface {
|
||||
// If clusterType is an empty string it means that caller is not aware then default cluster type will be used
|
||||
// default cluster type maybe different for different provider implementations, for example if we are providing
|
||||
// kubeconfig file for a phase then phase may be bound to ephemeral or target cluster type then defaults will be
|
||||
// ephemeral or target respectively.
|
||||
Get(clusterType string) (File, error)
|
||||
Cleanup() error
|
||||
var _ Interface = &kubeConfig{}
|
||||
|
||||
type kubeConfig struct {
|
||||
path string
|
||||
dumpRoot string
|
||||
|
||||
fileSystem document.FileSystem
|
||||
sourceFunc KubeSourceFunc
|
||||
}
|
||||
|
||||
// NewKubeConfig serves as a constructor for kubeconfig Interface
|
||||
// first argument is a function that should return bytes with kubeconfig and error
|
||||
// see FromByte() FromAPIalphaV1() FromFile() functions or extend with your own
|
||||
// second argument are options that can be used to inject various supported options into it
|
||||
// see InjectTempRoot(), InjectFileSystem(), InjectFilePath() functions for more info
|
||||
func NewKubeConfig(source KubeSourceFunc, options ...Option) Interface {
|
||||
kf := &kubeConfig{}
|
||||
for _, o := range options {
|
||||
o(kf)
|
||||
}
|
||||
kf.sourceFunc = source
|
||||
if kf.fileSystem == nil {
|
||||
kf.fileSystem = document.NewDocumentFs()
|
||||
}
|
||||
return kf
|
||||
}
|
||||
|
||||
// Option is a function that allows to modify kubeConfig object
|
||||
type Option func(*kubeConfig)
|
||||
|
||||
// KubeSourceFunc is a function which returns bytes array to construct new kubeConfig object
|
||||
type KubeSourceFunc func() ([]byte, error)
|
||||
|
||||
// Cleanup is a function which cleans up kubeconfig file from filesystem
|
||||
type Cleanup func()
|
||||
|
||||
// FromByte returns KubeSource type, uses plain bytes array as source to construct kubeconfig object
|
||||
func FromByte(b []byte) KubeSourceFunc {
|
||||
return func() ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
|
||||
// FromAPIalphaV1 returns KubeSource type, uses API Config array as source to construct kubeconfig object
|
||||
func FromAPIalphaV1(apiObj *v1alpha1.KubeConfig) KubeSourceFunc {
|
||||
return func() ([]byte, error) {
|
||||
return yaml.Marshal(apiObj.Config)
|
||||
}
|
||||
}
|
||||
|
||||
// FromFile returns KubeSource type, uses path to kubeconfig on FS as source to construct kubeconfig object
|
||||
func FromFile(path string, fs document.FileSystem) KubeSourceFunc {
|
||||
return func() ([]byte, error) {
|
||||
return fs.ReadFile(path)
|
||||
}
|
||||
}
|
||||
|
||||
// InjectFileSystem sets fileSystem to be used, mostly to be used for tests
|
||||
func InjectFileSystem(fs document.FileSystem) Option {
|
||||
return func(k *kubeConfig) {
|
||||
k.fileSystem = fs
|
||||
}
|
||||
}
|
||||
|
||||
// InjectTempRoot sets root for temporary file system, if not set default OS temp dir will be used
|
||||
func InjectTempRoot(dumpRoot string) Option {
|
||||
return func(k *kubeConfig) {
|
||||
k.dumpRoot = dumpRoot
|
||||
}
|
||||
}
|
||||
|
||||
// InjectFilePath enables setting kubeconfig path, useful when you have kubeconfig
|
||||
// from the actual filesystem, if this option is used, please also make sure that
|
||||
// FromFile option is also used as a first argument in NewKubeConfig function
|
||||
func InjectFilePath(path string, fs document.FileSystem) Option {
|
||||
return func(k *kubeConfig) {
|
||||
k.path = path
|
||||
k.fileSystem = fs
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kubeConfig) WriteFile(path string) (err error) {
|
||||
data, err := k.sourceFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return k.fileSystem.WriteFile(path, data)
|
||||
}
|
||||
|
||||
func (k *kubeConfig) Write(w io.Writer) (err error) {
|
||||
data, err := k.sourceFunc()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteTempFile implements kubeconfig Interface
|
||||
func (k *kubeConfig) WriteTempFile(root string) (string, Cleanup, error) {
|
||||
data, err := k.sourceFunc()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
file, err := k.fileSystem.TempFile(root, "kubeconfig-")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
fName := file.Name()
|
||||
_, err = file.Write(data)
|
||||
if err != nil {
|
||||
// delete the temp file that was created and return write error
|
||||
cleanup(fName, k.fileSystem)()
|
||||
return "", nil, err
|
||||
}
|
||||
return fName, cleanup(fName, k.fileSystem), nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// point to it and Cleanup() function will remove this file from the filesystem.
|
||||
func (k *kubeConfig) GetFile() (string, Cleanup, error) {
|
||||
if k.path != "" {
|
||||
return k.path, func() {}, nil
|
||||
}
|
||||
return k.WriteTempFile(k.dumpRoot)
|
||||
}
|
||||
|
||||
func cleanup(path string, fs document.FileSystem) Cleanup {
|
||||
if path == "" {
|
||||
return func() {}
|
||||
}
|
||||
return func() {
|
||||
if err := fs.RemoveAll(path); err != nil {
|
||||
log.Fatalf("Failed to cleanup kubeconfig file %s, error: %v", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
344
pkg/k8s/kubeconfig/kubeconfig_test.go
Normal file
344
pkg/k8s/kubeconfig/kubeconfig_test.go
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
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 kubeconfig_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||
kustfs "sigs.k8s.io/kustomize/api/filesys"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
||||
"opendev.org/airship/airshipctl/testutil/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
testValidKubeconfig = `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: ca-data
|
||||
server: https://10.0.1.7:6443
|
||||
name: kubernetes_target
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes_target
|
||||
user: kubernetes-admin
|
||||
name: kubernetes-admin@kubernetes
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kubernetes-admin
|
||||
user:
|
||||
client-certificate-data: cert-data
|
||||
client-key-data: client-keydata
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
errTempFile = fmt.Errorf("TempFile Error")
|
||||
errSourceFunc = fmt.Errorf("Source func error")
|
||||
errWriter = fmt.Errorf("Writer error")
|
||||
testValidKubeconfigAPI = &v1alpha1.KubeConfig{
|
||||
Config: v1.Config{
|
||||
CurrentContext: "test",
|
||||
Clusters: []v1.NamedCluster{
|
||||
{
|
||||
Name: "some-cluster",
|
||||
Cluster: v1.Cluster{
|
||||
CertificateAuthority: "ca",
|
||||
Server: "https://10.0.1.7:6443",
|
||||
},
|
||||
},
|
||||
},
|
||||
APIVersion: "v1",
|
||||
Contexts: []v1.NamedContext{
|
||||
{
|
||||
Name: "test",
|
||||
Context: v1.Context{
|
||||
Cluster: "some-cluster",
|
||||
AuthInfo: "some-user",
|
||||
},
|
||||
},
|
||||
},
|
||||
AuthInfos: []v1.NamedAuthInfo{
|
||||
{
|
||||
Name: "some-user",
|
||||
AuthInfo: v1.AuthInfo{
|
||||
ClientCertificate: "cert-data",
|
||||
ClientKey: "client-key",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestKubeconfigContent(t *testing.T) {
|
||||
expectedData := []byte(testValidKubeconfig)
|
||||
fs := document.NewDocumentFs()
|
||||
kubeconf := kubeconfig.NewKubeConfig(
|
||||
kubeconfig.FromByte(expectedData),
|
||||
kubeconfig.InjectFileSystem(fs),
|
||||
kubeconfig.InjectTempRoot("."))
|
||||
path, clean, err := kubeconf.GetFile()
|
||||
require.NoError(t, err)
|
||||
defer clean()
|
||||
actualData, err := fs.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedData, actualData)
|
||||
}
|
||||
|
||||
func TestNewKubeConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
shouldPanic bool
|
||||
name string
|
||||
expectedPathContains string
|
||||
expectedErrorContains string
|
||||
src kubeconfig.KubeSourceFunc
|
||||
options []kubeconfig.Option
|
||||
}{
|
||||
{
|
||||
name: "write to temp file",
|
||||
src: kubeconfig.FromByte([]byte(testValidKubeconfig)),
|
||||
options: []kubeconfig.Option{
|
||||
kubeconfig.InjectFileSystem(
|
||||
fs.MockFileSystem{
|
||||
MockTempFile: func(root, pattern string) (document.File, error) {
|
||||
return fs.TestFile{
|
||||
MockName: func() string { return "kubeconfig-142398" },
|
||||
MockWrite: func() (int, error) { return 0, nil },
|
||||
MockClose: func() error { return nil },
|
||||
}, nil
|
||||
},
|
||||
MockRemoveAll: func() error { return nil },
|
||||
},
|
||||
),
|
||||
},
|
||||
expectedPathContains: "kubeconfig-142398",
|
||||
},
|
||||
{
|
||||
name: "cleanup with dump root",
|
||||
expectedPathContains: "kubeconfig-142398",
|
||||
src: kubeconfig.FromByte([]byte(testValidKubeconfig)),
|
||||
options: []kubeconfig.Option{
|
||||
kubeconfig.InjectTempRoot("/my-unique-root"),
|
||||
kubeconfig.InjectFileSystem(
|
||||
fs.MockFileSystem{
|
||||
MockTempFile: func(root, _ string) (document.File, error) {
|
||||
// check if root path is passed to the TempFile interface
|
||||
if root != "/my-unique-root" {
|
||||
return nil, errTempFile
|
||||
}
|
||||
return fs.TestFile{
|
||||
MockName: func() string { return "kubeconfig-142398" },
|
||||
MockWrite: func() (int, error) { return 0, nil },
|
||||
MockClose: func() error { return nil },
|
||||
}, nil
|
||||
},
|
||||
MockRemoveAll: func() error { return nil },
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from file, and fs option",
|
||||
src: kubeconfig.FromFile("/my/kubeconfig", fsWithFile(t, "/my/kubeconfig")),
|
||||
options: []kubeconfig.Option{
|
||||
kubeconfig.InjectFilePath("/my/kubeconfig", fsWithFile(t, "/my/kubeconfig")),
|
||||
},
|
||||
expectedPathContains: "/my/kubeconfig",
|
||||
},
|
||||
{
|
||||
name: "write to real fs",
|
||||
src: kubeconfig.FromAPIalphaV1(testValidKubeconfigAPI),
|
||||
expectedPathContains: "kubeconfig-",
|
||||
},
|
||||
{
|
||||
name: "from file, use SourceFile",
|
||||
src: kubeconfig.FromFile("/my/kubeconfig", fsWithFile(t, "/my/kubeconfig")),
|
||||
expectedPathContains: "kubeconfig-",
|
||||
},
|
||||
{
|
||||
name: "temp file error",
|
||||
src: kubeconfig.FromAPIalphaV1(testValidKubeconfigAPI),
|
||||
expectedErrorContains: errTempFile.Error(),
|
||||
options: []kubeconfig.Option{
|
||||
kubeconfig.InjectFileSystem(
|
||||
fs.MockFileSystem{
|
||||
MockTempFile: func(string, string) (document.File, error) {
|
||||
return nil, errTempFile
|
||||
},
|
||||
MockRemoveAll: func() error { return nil },
|
||||
},
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source func error",
|
||||
src: func() ([]byte, error) { return nil, errSourceFunc },
|
||||
expectedPathContains: "kubeconfig-",
|
||||
expectedErrorContains: errSourceFunc.Error(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
kubeconf := kubeconfig.NewKubeConfig(tt.src, tt.options...)
|
||||
path, clean, err := kubeconf.GetFile()
|
||||
if tt.expectedErrorContains != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.expectedErrorContains)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
actualPath := path
|
||||
assert.Contains(t, actualPath, tt.expectedPathContains)
|
||||
clean()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKubeConfigWrite(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedContent string
|
||||
expectedErrorContains string
|
||||
|
||||
readWrite io.ReadWriter
|
||||
options []kubeconfig.Option
|
||||
src kubeconfig.KubeSourceFunc
|
||||
}{
|
||||
{
|
||||
name: "Basic write",
|
||||
src: kubeconfig.FromByte([]byte(testValidKubeconfig)),
|
||||
expectedContent: testValidKubeconfig,
|
||||
readWrite: bytes.NewBuffer([]byte{}),
|
||||
},
|
||||
{
|
||||
name: "Source error",
|
||||
src: func() ([]byte, error) { return nil, errSourceFunc },
|
||||
expectedErrorContains: errSourceFunc.Error(),
|
||||
},
|
||||
{
|
||||
name: "Writer error",
|
||||
src: kubeconfig.FromByte([]byte(testValidKubeconfig)),
|
||||
expectedErrorContains: errWriter.Error(),
|
||||
readWrite: fakeReaderWriter{writeErr: errWriter},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
kubeconf := kubeconfig.NewKubeConfig(tt.src, tt.options...)
|
||||
err := kubeconf.Write(tt.readWrite)
|
||||
if tt.expectedErrorContains != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.expectedErrorContains)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedContent, read(t, tt.readWrite))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKubeConfigWriteFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedContent string
|
||||
path string
|
||||
expectedErrorContains string
|
||||
|
||||
fs document.FileSystem
|
||||
src kubeconfig.KubeSourceFunc
|
||||
}{
|
||||
{
|
||||
name: "Basic write file",
|
||||
src: kubeconfig.FromByte([]byte(testValidKubeconfig)),
|
||||
expectedContent: testValidKubeconfig,
|
||||
fs: fsWithFile(t, "/test-path"),
|
||||
path: "/test-path",
|
||||
},
|
||||
{
|
||||
name: "Source error",
|
||||
src: func() ([]byte, error) { return nil, errSourceFunc },
|
||||
expectedErrorContains: errSourceFunc.Error(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
kubeconf := kubeconfig.NewKubeConfig(tt.src, kubeconfig.InjectFileSystem(tt.fs))
|
||||
err := kubeconf.WriteFile(tt.path)
|
||||
if tt.expectedErrorContains != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.expectedErrorContains)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedContent, readFile(t, tt.path, tt.fs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(t *testing.T, path string, fs document.FileSystem) string {
|
||||
b, err := fs.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func read(t *testing.T, r io.Reader) string {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
require.NoError(t, err)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func fsWithFile(t *testing.T, path string) document.FileSystem {
|
||||
fSys := fs.MockFileSystem{
|
||||
FileSystem: kustfs.MakeFsInMemory(),
|
||||
MockRemoveAll: func() error {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
err := fSys.WriteFile(path, []byte(testValidKubeconfig))
|
||||
require.NoError(t, err)
|
||||
return fSys
|
||||
}
|
||||
|
||||
type fakeReaderWriter struct {
|
||||
readErr error
|
||||
writeErr error
|
||||
}
|
||||
|
||||
var _ io.Reader = fakeReaderWriter{}
|
||||
var _ io.Writer = fakeReaderWriter{}
|
||||
|
||||
func (f fakeReaderWriter) Read(p []byte) (n int, err error) {
|
||||
return 0, f.readErr
|
||||
}
|
||||
|
||||
func (f fakeReaderWriter) Write(p []byte) (n int, err error) {
|
||||
return 0, f.writeErr
|
||||
}
|
@ -79,7 +79,7 @@ func TestApply(t *testing.T) {
|
||||
expectedErr: nil,
|
||||
fs: fs.MockFileSystem{
|
||||
MockRemoveAll: func() error { return nil },
|
||||
MockTempFile: func() (document.File, error) {
|
||||
MockTempFile: func(string, string) (document.File, error) {
|
||||
return fs.TestFile{
|
||||
MockName: func() string { return filenameRC },
|
||||
MockWrite: func() (int, error) { return 0, nil },
|
||||
@ -91,13 +91,13 @@ func TestApply(t *testing.T) {
|
||||
{
|
||||
expectedErr: ErrWriteOutError,
|
||||
fs: fs.MockFileSystem{
|
||||
MockTempFile: func() (document.File, error) { return nil, ErrWriteOutError }},
|
||||
MockTempFile: func(string, string) (document.File, error) { return nil, ErrWriteOutError }},
|
||||
},
|
||||
{
|
||||
expectedErr: ErrTempFileError,
|
||||
fs: fs.MockFileSystem{
|
||||
MockRemoveAll: func() error { return nil },
|
||||
MockTempFile: func() (document.File, error) {
|
||||
MockTempFile: func(string, string) (document.File, error) {
|
||||
return fs.TestFile{
|
||||
MockWrite: func() (int, error) { return 0, ErrTempFileError },
|
||||
MockName: func() string { return filenameRC },
|
||||
|
@ -25,9 +25,6 @@ import (
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"sigs.k8s.io/cli-utils/pkg/manifestreader"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
)
|
||||
|
||||
@ -99,27 +96,3 @@ func (mbr *ManifestBundleReader) Read() ([]*resource.Info, error) {
|
||||
}
|
||||
return mbr.StreamReader.Read()
|
||||
}
|
||||
|
||||
// DumpKubeConfig to temporary directory
|
||||
func DumpKubeConfig(kconf *airshipv1.KubeConfig, root string, fs document.FileSystem) (string, error) {
|
||||
data, err := yaml.Marshal(kconf.Config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
dir, err := fs.TempDir(root, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
file, err := fs.TempFile(dir, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = file.Write(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return file.Name(), nil
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
@ -24,12 +23,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||
|
||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/testutil/fs"
|
||||
)
|
||||
|
||||
func TestDefaultManifestFactory(t *testing.T) {
|
||||
@ -95,87 +89,6 @@ func TestManifestBundleReader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDumpKubeConfig(t *testing.T) {
|
||||
errTmpDir := errors.New("TmpDir error")
|
||||
errTmpFile := errors.New("TmpFile error")
|
||||
errWriteFile := errors.New("WriteFile error")
|
||||
|
||||
sampleKubeConfig := &airshipv1.KubeConfig{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "airshipit.org/v1alpha1",
|
||||
Kind: "KubeConfig",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "somename",
|
||||
},
|
||||
Config: clientcmdapi.Config{
|
||||
APIVersion: "v1",
|
||||
Kind: "Config",
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
fs document.FileSystem
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "Error temporary dir",
|
||||
fs: fs.MockFileSystem{
|
||||
MockTempDir: func() (string, error) {
|
||||
return "", errTmpDir
|
||||
},
|
||||
},
|
||||
expectedErr: errTmpDir,
|
||||
},
|
||||
{
|
||||
name: "Error temporary file",
|
||||
fs: fs.MockFileSystem{
|
||||
MockTempDir: func() (string, error) { return "someDir", nil },
|
||||
MockTempFile: func() (document.File, error) { return nil, errTmpFile },
|
||||
},
|
||||
expectedErr: errTmpFile,
|
||||
},
|
||||
{
|
||||
name: "Error write file",
|
||||
fs: fs.MockFileSystem{
|
||||
MockTempDir: func() (string, error) { return "someDir", nil },
|
||||
MockTempFile: func() (document.File, error) {
|
||||
return fs.TestFile{
|
||||
MockName: func() string { return "filename" },
|
||||
MockWrite: func() (int, error) { return 0, errWriteFile },
|
||||
MockClose: func() error { return nil },
|
||||
}, nil
|
||||
},
|
||||
MockRemoveAll: func() error { return nil },
|
||||
},
|
||||
expectedErr: errWriteFile,
|
||||
},
|
||||
{
|
||||
name: "Dump without errors",
|
||||
fs: fs.MockFileSystem{
|
||||
MockTempDir: func() (string, error) { return "someDir", nil },
|
||||
MockTempFile: func() (document.File, error) {
|
||||
return fs.TestFile{
|
||||
MockName: func() string { return "filename" },
|
||||
MockWrite: func() (int, error) { return 0, nil },
|
||||
MockClose: func() error { return nil },
|
||||
}, nil
|
||||
},
|
||||
MockRemoveAll: func() error { return nil },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
tt := test
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := DumpKubeConfig(sampleKubeConfig, "ttt", tt.fs)
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fakeReaderWriter struct {
|
||||
readErr error
|
||||
writeErr error
|
||||
|
@ -58,5 +58,5 @@ type ExecutorFactory func(
|
||||
document.Document,
|
||||
document.Bundle,
|
||||
*environment.AirshipCTLSettings,
|
||||
kubeconfig.Provider,
|
||||
kubeconfig.Interface,
|
||||
) (Executor, error)
|
||||
|
@ -15,23 +15,28 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
fs "sigs.k8s.io/kustomize/api/filesys"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
)
|
||||
|
||||
var _ document.FileSystem = MockFileSystem{}
|
||||
|
||||
// MockFileSystem implements Filesystem
|
||||
type MockFileSystem struct {
|
||||
MockRemoveAll func() error
|
||||
MockTempDir func() (string, error)
|
||||
MockTempFile func() (document.File, error)
|
||||
document.FileSystem
|
||||
// allow to check content of the incoming parameters, root and patter for temp file
|
||||
MockTempFile func(string, string) (document.File, error)
|
||||
fs.FileSystem
|
||||
}
|
||||
|
||||
// RemoveAll Filesystem interface imlementation
|
||||
func (fsys MockFileSystem) RemoveAll(string) error { return fsys.MockRemoveAll() }
|
||||
|
||||
// TempFile Filesystem interface imlementation
|
||||
func (fsys MockFileSystem) TempFile(string, string) (document.File, error) {
|
||||
return fsys.MockTempFile()
|
||||
func (fsys MockFileSystem) TempFile(root, pattern string) (document.File, error) {
|
||||
return fsys.MockTempFile(root, pattern)
|
||||
}
|
||||
|
||||
// TempDir Filesystem interface imlementation
|
||||
|
Loading…
Reference in New Issue
Block a user