Merge "Add kubeconfig interface"
This commit is contained in:
commit
efc46c2203
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…
x
Reference in New Issue
Block a user