1
0
Fork 0
mirror of https://github.com/kastenhq/kubestr.git synced 2024-12-14 11:57:56 +00:00

Allow FIO test to use an input file (#32)

* Allow FIO test to use an input file

* lint ci errors
This commit is contained in:
Sirish Bathina 2020-11-30 15:37:56 -10:00 committed by GitHub
parent 50b02f177a
commit bc9dbcb6b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 306 additions and 611 deletions

View file

@ -20,6 +20,7 @@ import (
"fmt"
"time"
"github.com/kastenhq/kubestr/pkg/fio"
"github.com/kastenhq/kubestr/pkg/kubestr"
"github.com/spf13/cobra"
)
@ -40,7 +41,9 @@ var (
}
fioCheckerStorageClass string
fioCheckerConfigMap string
fioCheckerSize string
fioCheckerNamespace string
fioCheckerFilePath string
fioCheckerTestName string
fioCmd = &cobra.Command{
Use: "fio",
@ -49,7 +52,7 @@ var (
Run: func(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
Fio(ctx, output, fioCheckerStorageClass, fioCheckerConfigMap, fioCheckerTestName)
Fio(ctx, output, fioCheckerStorageClass, fioCheckerSize, fioCheckerNamespace, fioCheckerTestName, fioCheckerFilePath)
},
}
)
@ -58,9 +61,12 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&output, "output", "o", "", "Options(json)")
rootCmd.AddCommand(fioCmd)
fioCmd.Flags().StringVarP(&fioCheckerStorageClass, "storageclass", "s", "", "The Name of a storageclass")
fioCmd.Flags().StringVarP(&fioCheckerConfigMap, "configmap", "c", "", "The Name of a configmap in the current namespace")
fioCmd.Flags().StringVarP(&fioCheckerTestName, "testname", "t", "", "The Name of a predefined kubestr fio test")
fioCmd.Flags().StringVarP(&fioCheckerStorageClass, "storageclass", "c", "", "The name of a storageclass. (Required)")
_ = fioCmd.MarkFlagRequired("storageclass")
fioCmd.Flags().StringVarP(&fioCheckerSize, "size", "s", fio.DefaultPVCSize, "The size of the volume used to run FIO.")
fioCmd.Flags().StringVarP(&fioCheckerNamespace, "namespace", "n", fio.DefaultNS, "The namespace used to run FIO.")
fioCmd.Flags().StringVarP(&fioCheckerFilePath, "fiofile", "f", "", "The path to a an fio config file.")
fioCmd.Flags().StringVarP(&fioCheckerTestName, "testname", "t", "", "The Name of a predefined kubestr fio test. Options(default-fio)")
// //rootCmd.AddCommand(provCmd)
}
@ -110,13 +116,26 @@ func Baseline(ctx context.Context, output string) {
}
// Fio executes the FIO test.
func Fio(ctx context.Context, output, storageclass, configMapName, testName string) {
func Fio(ctx context.Context, output, storageclass, size, namespace, jobName, fioFilePath string) {
p, err := kubestr.NewKubestr()
if err != nil {
fmt.Println(err.Error())
return
}
result := p.FIO(ctx, storageclass, configMapName, testName)
testName := "FIO test results"
var result *kubestr.TestOutput
if fioResult, err := p.Fio.RunFio(ctx, &fio.RunFIOArgs{
StorageClass: storageclass,
Size: size,
Namespace: namespace,
FIOJobName: jobName,
FIOJobFilepath: fioFilePath,
}); err != nil {
result = kubestr.MakeTestOutput(testName, kubestr.StatusError, err.Error(), fioResult)
} else {
result = kubestr.MakeTestOutput(testName, kubestr.StatusOK, fmt.Sprintf("\n%s\n", fioResult.Result), fioResult)
}
if output == "json" {
jsonRes, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(jsonRes))

View file

@ -3,11 +3,13 @@ package fio
import (
"context"
"fmt"
"os"
"io/ioutil"
"path/filepath"
kankube "github.com/kanisterio/kanister/pkg/kube"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
sv1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
@ -22,10 +24,6 @@ const (
DefaultFIOJob = "default-fio"
// KubestrFIOJob describes the default FIO job
KubestrFIOJobGenName = "kubestr-fio"
// ConfigMapSCKey describes the storage class key in a config map
ConfigMapSCKey = "storageclass"
// ConfigMapSizeKey describes the size key in a config map
ConfigMapSizeKey = "pvcsize"
// ConfigMapJobKey is the default fio job key
ConfigMapJobKey = "fiojob"
// DefaultPVCSize is the default PVC size
@ -48,7 +46,7 @@ const (
// FIO is an interface that represents FIO related commands
type FIO interface {
RunFio(ctx context.Context, args *RunFIOArgs) (string, error) // , test config
RunFio(ctx context.Context, args *RunFIOArgs) (*RunFIOResult, error) // , test config
}
// FIOrunner implments FIO
@ -58,154 +56,155 @@ type FIOrunner struct {
}
type RunFIOArgs struct {
StorageClass string
ConfigMapName string
JobName string
StorageClass string
Size string
Namespace string
FIOJobFilepath string
FIOJobName string
}
func (f *FIOrunner) RunFio(ctx context.Context, args *RunFIOArgs) (string, error) {
func (a *RunFIOArgs) Validate() error {
if a.StorageClass == "" || a.Size == "" || a.Namespace == "" {
return fmt.Errorf("Require fields are missing. (StorageClass, Size, Namespace)")
}
return nil
}
type RunFIOResult struct {
Size string `json:"size,omitempty"`
StorageClass *sv1.StorageClass `json:"storageClass,omitempty"`
FioConfig string `json:"fioConfig,omitempty"`
Result string `json:"result,omitempty"`
}
func (f *FIOrunner) RunFio(ctx context.Context, args *RunFIOArgs) (*RunFIOResult, error) {
f.fioSteps = &fioStepper{
cli: f.Cli,
podReady: &podReadyChecker{cli: f.Cli},
podSpecMerger: &podSpecMerger{cli: f.Cli},
kubeExecutor: &kubeExecutor{cli: f.Cli},
cli: f.Cli,
podReady: &podReadyChecker{cli: f.Cli},
kubeExecutor: &kubeExecutor{cli: f.Cli},
}
return f.RunFioHelper(ctx, args)
}
func (f *FIOrunner) RunFioHelper(ctx context.Context, args *RunFIOArgs) (string, error) {
func (f *FIOrunner) RunFioHelper(ctx context.Context, args *RunFIOArgs) (*RunFIOResult, error) {
// create a configmap with test parameters
if f.Cli == nil { // for UT purposes
return "", fmt.Errorf("cli uninitialized")
return nil, fmt.Errorf("cli uninitialized")
}
if args == nil {
args = &RunFIOArgs{}
if err := args.Validate(); err != nil {
return nil, err
}
if err := f.fioSteps.validateNamespace(ctx, args.Namespace); err != nil {
return nil, errors.Wrapf(err, "Unable to find namespace (%s)", args.Namespace)
}
sc, err := f.fioSteps.storageClassExists(ctx, args.StorageClass)
if err != nil {
return nil, errors.Wrap(err, "Cannot find StorageClass")
}
configMap, err := f.fioSteps.loadConfigMap(ctx, args)
if err != nil {
return "", errors.Wrap(err, "Unable to create a ConfigMap")
return nil, errors.Wrap(err, "Unable to create a ConfigMap")
}
defer func() {
_ = f.fioSteps.deleteConfigMap(context.TODO(), configMap)
_ = f.fioSteps.deleteConfigMap(context.TODO(), configMap, args.Namespace)
}()
testFileName, err := fioTestFilename(configMap.Data)
if err != nil {
return "", errors.Wrap(err, "Failed to get test file name.")
return nil, errors.Wrap(err, "Failed to get test file name.")
}
size := configMap.Data[ConfigMapSizeKey]
if size == "" {
size = DefaultPVCSize
}
storageClass := configMap.Data[ConfigMapSCKey]
if storageClass == "" {
return "", fmt.Errorf("StorageClass must be provided")
}
if err := f.fioSteps.storageClassExists(ctx, storageClass); err != nil {
return "", errors.Wrap(err, "Cannot find StorageClass")
}
pvc, err := f.fioSteps.createPVC(ctx, storageClass, size)
pvc, err := f.fioSteps.createPVC(ctx, args.StorageClass, args.Size, args.Namespace)
if err != nil {
return "", errors.Wrap(err, "Failed to create PVC")
return nil, errors.Wrap(err, "Failed to create PVC")
}
defer func() {
_ = f.fioSteps.deletePVC(context.TODO(), pvc.Name)
_ = f.fioSteps.deletePVC(context.TODO(), pvc.Name, args.Namespace)
}()
fmt.Println("PVC created", pvc.Name)
pod, err := f.fioSteps.createPod(ctx, pvc.Name, configMap.Name, testFileName)
pod, err := f.fioSteps.createPod(ctx, pvc.Name, configMap.Name, testFileName, args.Namespace)
defer func() {
_ = f.fioSteps.deletePod(context.TODO(), pod.Name)
_ = f.fioSteps.deletePod(context.TODO(), pod.Name, args.Namespace)
}()
if err != nil {
return "", errors.Wrap(err, "Failed to create POD")
return nil, errors.Wrap(err, "Failed to create POD")
}
fmt.Println("Pod created", pod.Name)
fmt.Printf("Running FIO test (%s) on StorageClass (%s) with a PVC of Size (%s)\n", testFileName, storageClass, size)
return f.fioSteps.runFIOCommand(ctx, pod.Name, ContainerName, testFileName)
fmt.Printf("Running FIO test (%s) on StorageClass (%s) with a PVC of Size (%s)\n", testFileName, args.StorageClass, args.Size)
fioOutput, err := f.fioSteps.runFIOCommand(ctx, pod.Name, ContainerName, testFileName, args.Namespace)
if err != nil {
return nil, errors.Wrap(err, "Failed while running FIO test.")
}
return &RunFIOResult{
Size: args.Size,
StorageClass: sc,
FioConfig: "",
Result: fioOutput,
}, nil
}
type fioSteps interface {
storageClassExists(ctx context.Context, storageClass string) error
validateNamespace(ctx context.Context, namespace string) error
storageClassExists(ctx context.Context, storageClass string) (*sv1.StorageClass, error)
loadConfigMap(ctx context.Context, args *RunFIOArgs) (*v1.ConfigMap, error)
createPVC(ctx context.Context, storageclass, size string) (*v1.PersistentVolumeClaim, error)
deletePVC(ctx context.Context, pvcName string) error
createPod(ctx context.Context, pvcName, configMapName, testFileName string) (*v1.Pod, error)
deletePod(ctx context.Context, podName string) error
runFIOCommand(ctx context.Context, podName, containerName, testFileName string) (string, error)
deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap) error
createPVC(ctx context.Context, storageclass, size, namespace string) (*v1.PersistentVolumeClaim, error)
deletePVC(ctx context.Context, pvcName, namespace string) error
createPod(ctx context.Context, pvcName, configMapName, testFileName, namespace string) (*v1.Pod, error)
deletePod(ctx context.Context, podName, namespace string) error
runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error)
deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap, namespace string) error
}
type fioStepper struct {
cli kubernetes.Interface
podReady waitForPodReadyInterface
podSpecMerger podSpecMergeInterface
kubeExecutor kubeExecInterface
cli kubernetes.Interface
podReady waitForPodReadyInterface
kubeExecutor kubeExecInterface
}
func (s *fioStepper) storageClassExists(ctx context.Context, storageClass string) error {
if _, err := s.cli.StorageV1().StorageClasses().Get(ctx, storageClass, metav1.GetOptions{}); err != nil {
func (s *fioStepper) validateNamespace(ctx context.Context, namespace string) error {
if _, err := s.cli.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}); err != nil {
return err
}
return nil
}
func (s *fioStepper) loadConfigMap(ctx context.Context, args *RunFIOArgs) (*v1.ConfigMap, error) {
configMap := &v1.ConfigMap{}
var err error
if args.ConfigMapName != "" {
configMap, err = s.cli.CoreV1().ConfigMaps(GetPodNamespace()).Get(ctx, args.ConfigMapName, metav1.GetOptions{})
if err != nil {
return nil, errors.Wrapf(err, "Failed to load configMap (%s) in namespace (%s)", args.ConfigMapName, GetPodNamespace())
}
}
if configMap.Data == nil {
configMap.Data = map[string]string{}
}
if args.StorageClass != "" {
configMap.Data[ConfigMapSCKey] = args.StorageClass
}
if val, ok := configMap.Data[ConfigMapSizeKey]; !ok || val == "" {
configMap.Data[ConfigMapSizeKey] = DefaultPVCSize
}
switch {
case len(configMap.Data) > 3:
return nil, fmt.Errorf("Invalid configmap data- %v", configMap.Data)
case args.JobName != "": // replace existing job with provided one
fioJob, ok := fioJobs[args.JobName]
if !ok {
return nil, fmt.Errorf("Unable to find fio job (%s)", args.JobName)
}
configMapJobKey := ConfigMapJobKey
for key := range configMap.Data {
if key != ConfigMapSizeKey && key != ConfigMapSCKey {
configMapJobKey = key
}
}
configMap.Data[configMapJobKey] = fioJob
case len(configMap.Data) == 2: // if none provided use default
configMap.Data[ConfigMapJobKey] = fioJobs[DefaultFIOJob]
default:
}
// create
configMap.Name = ""
configMap.GenerateName = KubestrFIOJobGenName
configMap.Labels = map[string]string{CreatedByFIOLabel: "true"}
return s.cli.CoreV1().ConfigMaps(GetPodNamespace()).Create(ctx, configMap, metav1.CreateOptions{})
func (s *fioStepper) storageClassExists(ctx context.Context, storageClass string) (*sv1.StorageClass, error) {
return s.cli.StorageV1().StorageClasses().Get(ctx, storageClass, metav1.GetOptions{})
}
func (s *fioStepper) createPVC(ctx context.Context, storageclass, size string) (*v1.PersistentVolumeClaim, error) {
func (s *fioStepper) loadConfigMap(ctx context.Context, args *RunFIOArgs) (*v1.ConfigMap, error) {
configMap := &v1.ConfigMap{
Data: make(map[string]string),
}
switch {
case args.FIOJobFilepath != "":
data, err := ioutil.ReadFile(args.FIOJobFilepath)
if err != nil {
return nil, errors.Wrap(err, "File reading error")
}
configMap.Data[filepath.Base(args.FIOJobFilepath)] = string(data)
case args.FIOJobName != "":
if _, ok := fioJobs[args.FIOJobName]; !ok {
return nil, fmt.Errorf("FIO job not found")
}
configMap.Data[args.FIOJobName] = fioJobs[args.FIOJobName]
default:
configMap.Data[DefaultFIOJob] = fioJobs[DefaultFIOJob]
}
// create
configMap.GenerateName = KubestrFIOJobGenName
configMap.Labels = map[string]string{CreatedByFIOLabel: "true"}
return s.cli.CoreV1().ConfigMaps(args.Namespace).Create(ctx, configMap, metav1.CreateOptions{})
}
func (s *fioStepper) createPVC(ctx context.Context, storageclass, size, namespace string) (*v1.PersistentVolumeClaim, error) {
sizeResource, err := resource.ParseQuantity(size)
if err != nil {
return nil, errors.Wrapf(err, "Unable to parse PVC size (%s)", size)
@ -224,21 +223,21 @@ func (s *fioStepper) createPVC(ctx context.Context, storageclass, size string) (
},
},
}
return s.cli.CoreV1().PersistentVolumeClaims(GetPodNamespace()).Create(ctx, pvc, metav1.CreateOptions{})
return s.cli.CoreV1().PersistentVolumeClaims(namespace).Create(ctx, pvc, metav1.CreateOptions{})
}
func (s *fioStepper) deletePVC(ctx context.Context, pvcName string) error {
return s.cli.CoreV1().PersistentVolumeClaims(GetPodNamespace()).Delete(ctx, pvcName, metav1.DeleteOptions{})
func (s *fioStepper) deletePVC(ctx context.Context, pvcName, namespace string) error {
return s.cli.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, pvcName, metav1.DeleteOptions{})
}
func (s *fioStepper) createPod(ctx context.Context, pvcName, configMapName, testFileName string) (*v1.Pod, error) {
func (s *fioStepper) createPod(ctx context.Context, pvcName, configMapName, testFileName, namespace string) (*v1.Pod, error) {
if pvcName == "" || configMapName == "" || testFileName == "" {
return nil, fmt.Errorf("Create pod missing required arguments.")
}
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
GenerateName: PodGenerateName,
Namespace: GetPodNamespace(),
Namespace: namespace,
},
Spec: v1.PodSpec{
Containers: []v1.Container{{
@ -249,6 +248,7 @@ func (s *fioStepper) createPod(ctx context.Context, pvcName, configMapName, test
{Name: "persistent-storage", MountPath: VolumeMountPath},
{Name: "config-map", MountPath: ConfigMapMountPath},
},
Image: "ghcr.io/kastenhq/kubestr:latest",
}},
Volumes: []v1.Volume{
{
@ -270,24 +270,17 @@ func (s *fioStepper) createPod(ctx context.Context, pvcName, configMapName, test
},
},
}
mergedPodSpec, err := s.podSpecMerger.mergePodSpec(ctx, GetPodNamespace(), pod.Spec)
if err != nil {
return nil, errors.Wrap(err, "Failed to merge Pod Spec with parent pod.")
}
pod.Spec = mergedPodSpec
podRes, err := s.cli.CoreV1().Pods(GetPodNamespace()).Create(ctx, pod, metav1.CreateOptions{})
podRes, err := s.cli.CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
if err != nil {
return podRes, err
}
err = s.podReady.waitForPodReady(ctx, GetPodNamespace(), podRes.Name)
err = s.podReady.waitForPodReady(ctx, namespace, podRes.Name)
if err != nil {
return nil, err
}
podRes, err = s.cli.CoreV1().Pods(GetPodNamespace()).Get(ctx, podRes.Name, metav1.GetOptions{})
podRes, err = s.cli.CoreV1().Pods(namespace).Get(ctx, podRes.Name, metav1.GetOptions{})
if err != nil {
return podRes, err
}
@ -295,14 +288,14 @@ func (s *fioStepper) createPod(ctx context.Context, pvcName, configMapName, test
return podRes, nil
}
func (s *fioStepper) deletePod(ctx context.Context, podName string) error {
return s.cli.CoreV1().Pods(GetPodNamespace()).Delete(ctx, podName, metav1.DeleteOptions{})
func (s *fioStepper) deletePod(ctx context.Context, podName, namespace string) error {
return s.cli.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
}
func (s *fioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName string) (string, error) {
func (s *fioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error) {
jobFilePath := fmt.Sprintf("%s/%s", ConfigMapMountPath, testFileName)
command := []string{"fio", "--directory", VolumeMountPath, jobFilePath}
stdout, stderr, err := s.kubeExecutor.exec(GetPodNamespace(), podName, containerName, command)
stdout, stderr, err := s.kubeExecutor.exec(namespace, podName, containerName, command)
if err != nil || stderr != "" {
return stdout, errors.Wrapf(err, "Error running command:(%v), stderr:(%s)", command, stderr)
}
@ -310,32 +303,22 @@ func (s *fioStepper) runFIOCommand(ctx context.Context, podName, containerName,
}
// deleteConfigMap only deletes a config map if it has the label
func (s *fioStepper) deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap) error {
func (s *fioStepper) deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap, namespace string) error {
if val, ok := configMap.Labels[CreatedByFIOLabel]; ok && val == "true" {
return s.cli.CoreV1().ConfigMaps(GetPodNamespace()).Delete(ctx, configMap.Name, metav1.DeleteOptions{})
return s.cli.CoreV1().ConfigMaps(namespace).Delete(ctx, configMap.Name, metav1.DeleteOptions{})
}
return nil
}
// GetPodNamespace gets the pods namespace or returns default
func GetPodNamespace() string {
if val, ok := os.LookupEnv(PodNamespaceEnvKey); ok {
return val
}
return DefaultNS
}
func fioTestFilename(configMap map[string]string) (string, error) {
potentialFilenames := []string{}
for key := range configMap {
if key != ConfigMapSCKey && key != ConfigMapSizeKey {
potentialFilenames = append(potentialFilenames, key)
}
}
if len(potentialFilenames) != 1 {
if len(configMap) != 1 {
return "", fmt.Errorf("Unable to find fio file in configmap/more than one found %v", configMap)
}
return potentialFilenames[0], nil
var fileName string
for key := range configMap {
fileName = key
}
return fileName, nil
}
type waitForPodReadyInterface interface {
@ -361,30 +344,3 @@ type kubeExecutor struct {
func (k *kubeExecutor) exec(namespace, podName, containerName string, command []string) (string, string, error) {
return kankube.Exec(k.cli, namespace, podName, containerName, command, nil)
}
type podSpecMergeInterface interface {
mergePodSpec(ctx context.Context, namespace string, podSpec v1.PodSpec) (v1.PodSpec, error)
}
type podSpecMerger struct {
cli kubernetes.Interface
}
func (m *podSpecMerger) mergePodSpec(ctx context.Context, namespace string, podSpec v1.PodSpec) (v1.PodSpec, error) {
currentPodName := os.Getenv(PodNameEnvKey)
if currentPodName == "" {
return podSpec, fmt.Errorf("Unable to retrieve Pod name from environment variable (%s)", PodNameEnvKey)
}
currentPod, err := m.cli.CoreV1().Pods(namespace).Get(ctx, currentPodName, metav1.GetOptions{})
if err != nil {
return podSpec, fmt.Errorf("Failed to discover pod configuration for Pod (%s): (%s)\n", currentPodName, err.Error())
}
if len(podSpec.Containers) != 1 {
return podSpec, fmt.Errorf("FIO pod doesn't have exactly 1 container.")
}
podSpec.NodeSelector = currentPod.Spec.NodeSelector
podSpec.Tolerations = currentPod.Spec.Tolerations
podSpec.Containers[0].Image = currentPod.Spec.Containers[0].Image
podSpec.SecurityContext = currentPod.Spec.SecurityContext
return podSpec, nil
}

View file

@ -3,6 +3,7 @@ package fio
import (
"context"
"fmt"
"io/ioutil"
"os"
"testing"
@ -10,6 +11,7 @@ import (
. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
scv1 "k8s.io/api/storage/v1"
sv1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
@ -46,42 +48,56 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
expectedTFN string
expectedPVC string
}{
{ // invalid args (storageclass)
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{},
args: &RunFIOArgs{},
checker: NotNil,
},
{ // invalid args (size)
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{},
args: &RunFIOArgs{
StorageClass: "sc",
},
checker: NotNil,
},
{ // invalid args (namespace)
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{},
args: &RunFIOArgs{
StorageClass: "sc",
Size: "100Gi",
},
checker: NotNil,
},
{ // namespace doesn't exist
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
vnErr: fmt.Errorf("namespace Err"),
},
args: &RunFIOArgs{
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"VN"},
},
{ // storageclass not found
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
sceErr: fmt.Errorf("storageclass Err"),
},
args: &RunFIOArgs{
StorageClass: "sc",
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
expectedSC: "sc",
expectedSize: DefaultPVCSize,
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
expectedSteps: []string{"VN", "SCE"},
},
{ // storage class provided by config map
{ // success
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
@ -90,7 +106,6 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "sc",
},
},
cPVC: &v1.PersistentVolumeClaim{
@ -105,53 +120,18 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: IsNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSteps: []string{"VN", "SCE", "LCM", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "sc",
expectedSize: DefaultPVCSize,
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // use size provided by Configmap
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: IsNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "SC2",
expectedSize: "10Gi",
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // fio test error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
@ -160,9 +140,7 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "testfiledata",
},
},
cPVC: &v1.PersistentVolumeClaim{
@ -178,16 +156,12 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
rFIOErr: fmt.Errorf("run fio error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "SC2",
expectedSize: "10Gi",
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
expectedSteps: []string{"VN", "SCE", "LCM", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
},
{ // create pod error
cli: fake.NewSimpleClientset(),
@ -197,9 +171,7 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "testfiledata",
},
},
cPVC: &v1.PersistentVolumeClaim{
@ -215,11 +187,12 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
cPodErr: fmt.Errorf("pod create error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "DPOD", "DPVC", "DCM"},
expectedSteps: []string{"VN", "SCE", "LCM", "CPVC", "CPOD", "DPOD", "DPVC", "DCM"},
},
{ // create PVC error
cli: fake.NewSimpleClientset(),
@ -229,41 +202,18 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "testfiledata",
},
},
cPVCErr: fmt.Errorf("pvc create error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "DCM"},
},
{ // storageclass not found
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
sceErr: fmt.Errorf("storageclass not found error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "DCM"},
expectedSteps: []string{"VN", "SCE", "LCM", "CPVC", "DCM"},
},
{ // testfilename retrieval error, more than one provided
cli: fake.NewSimpleClientset(),
@ -273,53 +223,31 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
"testfile.fio2": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "testfiledata",
"testfile.fio2": "testfiledata",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
},
{ // storageclass not provided in args or configmap
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
expectedSteps: []string{"VN", "SCE", "LCM", "DCM"},
},
{ // load configmap error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmErr: fmt.Errorf("failed to load configmap"),
},
args: nil,
args: &RunFIOArgs{
StorageClass: "sc",
Size: "100Gi",
Namespace: "foo",
},
checker: NotNil,
expectedSteps: []string{"LCM"},
expectedSteps: []string{"VN", "SCE", "LCM"},
},
} {
c.Log(i)
@ -331,8 +259,6 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
c.Check(err, tc.checker)
c.Assert(tc.stepper.steps, DeepEquals, tc.expectedSteps)
if err == nil {
c.Assert(tc.expectedSC, Equals, tc.stepper.sceExpSC)
c.Assert(tc.expectedCM, Equals, tc.stepper.lcmExpCM)
c.Assert(tc.expectedSC, Equals, tc.stepper.cPVCExpSC)
c.Assert(tc.expectedSize, Equals, tc.stepper.cPVCExpSize)
c.Assert(tc.expectedTFN, Equals, tc.stepper.cPodExpFN)
@ -345,10 +271,11 @@ func (s *FIOTestSuite) TestRunFioHelper(c *C) {
type fakeFioStepper struct {
steps []string
sceExpSC string
sceErr error
vnErr error
sceSC *sv1.StorageClass
sceErr error
lcmExpCM string
lcmConfigMap *v1.ConfigMap
lcmErr error
@ -371,42 +298,44 @@ type fakeFioStepper struct {
rFIOErr error
}
func (f *fakeFioStepper) storageClassExists(ctx context.Context, storageClass string) error {
func (f *fakeFioStepper) validateNamespace(ctx context.Context, namespace string) error {
f.steps = append(f.steps, "VN")
return f.vnErr
}
func (f *fakeFioStepper) storageClassExists(ctx context.Context, storageClass string) (*sv1.StorageClass, error) {
f.steps = append(f.steps, "SCE")
f.sceExpSC = storageClass
return f.sceErr
return f.sceSC, f.sceErr
}
func (f *fakeFioStepper) loadConfigMap(ctx context.Context, args *RunFIOArgs) (*v1.ConfigMap, error) {
f.steps = append(f.steps, "LCM")
f.lcmExpCM = args.ConfigMapName
return f.lcmConfigMap, f.lcmErr
}
func (f *fakeFioStepper) createPVC(ctx context.Context, storageclass, size string) (*v1.PersistentVolumeClaim, error) {
func (f *fakeFioStepper) createPVC(ctx context.Context, storageclass, size, namespace string) (*v1.PersistentVolumeClaim, error) {
f.steps = append(f.steps, "CPVC")
f.cPVCExpSC = storageclass
f.cPVCExpSize = size
return f.cPVC, f.cPVCErr
}
func (f *fakeFioStepper) deletePVC(ctx context.Context, pvcName string) error {
func (f *fakeFioStepper) deletePVC(ctx context.Context, pvcName, namespace string) error {
f.steps = append(f.steps, "DPVC")
return f.dPVCErr
}
func (f *fakeFioStepper) createPod(ctx context.Context, pvcName, configMapName, testFileName string) (*v1.Pod, error) {
func (f *fakeFioStepper) createPod(ctx context.Context, pvcName, configMapName, testFileName, namespace string) (*v1.Pod, error) {
f.steps = append(f.steps, "CPOD")
f.cPodExpCM = configMapName
f.cPodExpFN = testFileName
f.cPodExpPVC = pvcName
return f.cPod, f.cPodErr
}
func (f *fakeFioStepper) deletePod(ctx context.Context, podName string) error {
func (f *fakeFioStepper) deletePod(ctx context.Context, podName, namespace string) error {
f.steps = append(f.steps, "DPOD")
return f.dPodErr
}
func (f *fakeFioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName string) (string, error) {
func (f *fakeFioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error) {
f.steps = append(f.steps, "RFIOC")
return f.rFIOout, f.rFIOErr
}
func (f *fakeFioStepper) deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap) error {
func (f *fakeFioStepper) deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap, namespace string) error {
f.steps = append(f.steps, "DCM")
return nil
}
@ -430,13 +359,30 @@ func (s *FIOTestSuite) TestStorageClassExists(c *C) {
},
} {
stepper := &fioStepper{cli: tc.cli}
err := stepper.storageClassExists(ctx, tc.storageClass)
_, err := stepper.storageClassExists(ctx, tc.storageClass)
c.Check(err, tc.checker)
}
}
func (s *FIOTestSuite) TestValidateNamespace(c *C) {
ctx := context.Background()
stepper := &fioStepper{cli: fake.NewSimpleClientset()}
err := stepper.validateNamespace(ctx, "ns")
c.Assert(err, NotNil)
stepper = &fioStepper{cli: fake.NewSimpleClientset(&v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "ns",
},
})}
err = stepper.validateNamespace(ctx, "ns")
c.Assert(err, IsNil)
}
func (s *FIOTestSuite) TestLoadConfigMap(c *C) {
ctx := context.Background()
file, err := ioutil.TempFile("", "tempTLCfile")
c.Check(err, IsNil)
defer os.Remove(file.Name())
for i, tc := range []struct {
cli kubernetes.Interface
configMapName string
@ -447,126 +393,46 @@ func (s *FIOTestSuite) TestLoadConfigMap(c *C) {
failCreates bool
hasLabel bool
}{
{ // provided cm name not found
{ // provided file name not found
cli: fake.NewSimpleClientset(),
args: &RunFIOArgs{
ConfigMapName: "nonexistantcm",
FIOJobFilepath: "nonexistantfile",
},
cmChecker: IsNil,
errChecker: NotNil,
},
{ // specified config map found
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{},
}),
cli: fake.NewSimpleClientset(),
args: &RunFIOArgs{
ConfigMapName: "CM1",
StorageClass: "sc",
FIOJobFilepath: file.Name(),
FIOJobName: "random", // won't use this case
},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // specified config map found, replace storage class
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{},
}),
{ // specified job name, not found
cli: fake.NewSimpleClientset(),
args: &RunFIOArgs{
ConfigMapName: "CM1",
StorageClass: "sc",
},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // specified config map found, invalid config map
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{
"fiojob": "data",
"baddata1": "baddata",
},
}),
args: &RunFIOArgs{
ConfigMapName: "CM1",
StorageClass: "sc",
FIOJobName: "random",
},
cmChecker: IsNil,
errChecker: NotNil,
},
{ // specified config map found, replace with job
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{
"job1": "jobdetails",
},
}),
{ // specified job name, found
cli: fake.NewSimpleClientset(),
args: &RunFIOArgs{
ConfigMapName: "CM1",
StorageClass: "sc",
JobName: DefaultFIOJob,
FIOJobName: DefaultFIOJob,
},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // specified config map found, replace with job
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{},
}),
args: &RunFIOArgs{
ConfigMapName: "CM1",
StorageClass: "sc",
JobName: DefaultFIOJob,
},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // specified config map not found in namespace
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "badns",
},
Data: map[string]string{},
}),
args: &RunFIOArgs{
ConfigMapName: "CM1",
},
cmChecker: IsNil,
errChecker: NotNil,
},
{ // creates the default job ConfigMap
{ // use default job
cli: fake.NewSimpleClientset(),
cmChecker: NotNil,
errChecker: IsNil,
args: &RunFIOArgs{},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // job doesn't exist.
cli: fake.NewSimpleClientset(),
cmChecker: IsNil,
errChecker: NotNil,
args: &RunFIOArgs{
JobName: "nonExistentJob",
},
jobName: "nonExistentJob",
},
{ // Fails to create default job
{ // Fails to create configMap
cli: fake.NewSimpleClientset(),
cmChecker: IsNil,
errChecker: NotNil,
@ -630,7 +496,7 @@ func (s *FIOTestSuite) TestCreatePVC(c *C) {
return true, nil, errors.New("Error creating object")
})
}
pvc, err := stepper.createPVC(ctx, tc.storageclass, tc.size)
pvc, err := stepper.createPVC(ctx, tc.storageclass, tc.size, DefaultNS)
c.Check(err, tc.errChecker)
c.Check(pvc, tc.pvcChecker)
if pvc != nil {
@ -648,24 +514,23 @@ func (s *FIOTestSuite) TestDeletePVC(c *C) {
stepper := &fioStepper{cli: fake.NewSimpleClientset(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
Namespace: GetPodNamespace(),
Namespace: DefaultNS,
}})}
err := stepper.deletePVC(ctx, "pvc")
err := stepper.deletePVC(ctx, "pvc", DefaultNS)
c.Assert(err, IsNil)
err = stepper.deletePVC(ctx, "pvc")
err = stepper.deletePVC(ctx, "pvc", DefaultNS)
c.Assert(err, NotNil)
}
func (s *FIOTestSuite) TestCreatPod(c *C) {
ctx := context.Background()
for _, tc := range []struct {
pvcName string
configMapName string
testFileName string
reactor []k8stesting.Reactor
podReadyErr error
podSpecMergerErr error
errChecker Checker
for i, tc := range []struct {
pvcName string
configMapName string
testFileName string
reactor []k8stesting.Reactor
podReadyErr error
errChecker Checker
}{
{
pvcName: "pvc",
@ -726,13 +591,6 @@ func (s *FIOTestSuite) TestCreatPod(c *C) {
},
},
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "sdf",
errChecker: NotNil,
podSpecMergerErr: fmt.Errorf("podspecmerger error"),
},
{
pvcName: "pvc",
configMapName: "cm",
@ -752,15 +610,15 @@ func (s *FIOTestSuite) TestCreatPod(c *C) {
errChecker: NotNil,
},
} {
fmt.Println(i)
stepper := &fioStepper{
cli: fake.NewSimpleClientset(),
podReady: &fakePodReadyChecker{prcErr: tc.podReadyErr},
podSpecMerger: &fakePodSpecMerger{psmErr: tc.podSpecMergerErr},
cli: fake.NewSimpleClientset(),
podReady: &fakePodReadyChecker{prcErr: tc.podReadyErr},
}
if tc.reactor != nil {
stepper.cli.(*fake.Clientset).Fake.ReactionChain = tc.reactor
}
pod, err := stepper.createPod(ctx, tc.pvcName, tc.configMapName, tc.testFileName)
pod, err := stepper.createPod(ctx, tc.pvcName, tc.configMapName, tc.testFileName, DefaultNS)
c.Check(err, tc.errChecker)
if err == nil {
c.Assert(pod.GenerateName, Equals, PodGenerateName)
@ -790,11 +648,11 @@ func (s *FIOTestSuite) TestDeletePod(c *C) {
stepper := &fioStepper{cli: fake.NewSimpleClientset(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: GetPodNamespace(),
Namespace: DefaultNS,
}})}
err := stepper.deletePod(ctx, "pod")
err := stepper.deletePod(ctx, "pod", DefaultNS)
c.Assert(err, IsNil)
err = stepper.deletePod(ctx, "pod")
err = stepper.deletePod(ctx, "pod", DefaultNS)
c.Assert(err, NotNil)
}
@ -806,19 +664,16 @@ func (s *FIOTestSuite) TestFioTestFileName(c *C) {
}{
{
configMap: map[string]string{
ConfigMapSCKey: "storageclass",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "some test data",
"testfile.fio": "some test data",
},
retVal: "testfile.fio",
errChecker: IsNil,
},
{
configMap: map[string]string{
ConfigMapSCKey: "storageclass",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "some test data",
"testfile2.fio": "some test data2", // only support one file
"ConfigMapSCKey": "storageclass",
"ConfigMapSizeKey": "10Gi",
"testfile.fio": "some test data",
},
retVal: "",
errChecker: NotNil,
@ -865,7 +720,7 @@ func (s *FIOTestSuite) TestRunFioCommand(c *C) {
stepper := &fioStepper{
kubeExecutor: tc.executor,
}
out, err := stepper.runFIOCommand(ctx, tc.podName, tc.containerName, tc.testFileName)
out, err := stepper.runFIOCommand(ctx, tc.podName, tc.containerName, tc.testFileName, DefaultNS)
c.Check(err, tc.errChecker)
c.Assert(out, Equals, tc.executor.keStdOut)
c.Assert(tc.executor.keInPodName, Equals, tc.podName)
@ -939,7 +794,7 @@ func (s *FIOTestSuite) TestDeleteConfigMap(c *C) {
},
} {
stepper := &fioStepper{cli: tc.cli}
err := stepper.deleteConfigMap(ctx, tc.cm)
err := stepper.deleteConfigMap(ctx, tc.cm, DefaultNS)
c.Check(err, tc.errChecker)
if err == nil {
list, err := stepper.cli.CoreV1().ConfigMaps(defaultNS).List(ctx, metav1.ListOptions{})
@ -968,112 +823,6 @@ func (s *FIOTestSuite) TestWaitForPodReady(c *C) {
})
}
func (s *FIOTestSuite) TestMergePodSpec(c *C) {
ctx := context.Background()
runAsUserInt64 := int64(1)
for _, tc := range []struct {
namespace string
inPodSpec v1.PodSpec
podName string
parentPod *v1.Pod
errChecker Checker
}{
{
parentPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podName",
Namespace: "ns",
},
Spec: v1.PodSpec{
NodeSelector: map[string]string{
"node": "selector",
},
Tolerations: []v1.Toleration{
{Value: "toleration"},
},
Containers: []v1.Container{
{Image: "Image"},
},
SecurityContext: &v1.PodSecurityContext{
RunAsUser: &runAsUserInt64,
},
},
},
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: IsNil,
},
{
parentPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podName",
Namespace: "ns",
},
Spec: v1.PodSpec{
NodeSelector: map[string]string{
"node": "selector",
},
Tolerations: []v1.Toleration{
{Value: "toleration"},
},
Containers: []v1.Container{
{Image: "Image"},
},
SecurityContext: &v1.PodSecurityContext{
RunAsUser: &runAsUserInt64,
},
},
},
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}, {Name: "container2"}}},
errChecker: NotNil,
},
{
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: NotNil,
},
{
namespace: "ns",
podName: "",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: NotNil,
},
} {
tempHostname := os.Getenv(PodNameEnvKey)
defer func() {
os.Setenv(PodNameEnvKey, tempHostname)
}()
os.Setenv(PodNameEnvKey, tc.podName)
cli := fake.NewSimpleClientset()
if tc.parentPod != nil {
cli = fake.NewSimpleClientset(tc.parentPod)
}
psm := podSpecMerger{cli}
outPodSpec, err := psm.mergePodSpec(ctx, tc.namespace, tc.inPodSpec)
c.Check(err, tc.errChecker)
if err == nil {
c.Assert(outPodSpec, Not(DeepEquals), tc.inPodSpec)
c.Assert(outPodSpec.NodeSelector, DeepEquals, tc.parentPod.Spec.NodeSelector)
c.Assert(outPodSpec.Tolerations, DeepEquals, tc.parentPod.Spec.Tolerations)
c.Assert(outPodSpec.Containers[0].Image, Equals, tc.parentPod.Spec.Containers[0].Image)
c.Assert(outPodSpec.SecurityContext, DeepEquals, tc.parentPod.Spec.SecurityContext)
}
os.Setenv(PodNameEnvKey, tempHostname)
}
}
func (s *FIOTestSuite) TestGetPodNamespace(c *C) {
os.Setenv(PodNamespaceEnvKey, "ns")
ns := GetPodNamespace()
c.Assert(ns, Equals, "ns")
os.Unsetenv(PodNamespaceEnvKey)
}
type fakePodReadyChecker struct {
prcErr error
}
@ -1082,14 +831,6 @@ func (f *fakePodReadyChecker) waitForPodReady(ctx context.Context, namespace, na
return f.prcErr
}
type fakePodSpecMerger struct {
psmErr error
}
func (fm *fakePodSpecMerger) mergePodSpec(ctx context.Context, namespace string, podSpec v1.PodSpec) (v1.PodSpec, error) {
return podSpec, fm.psmErr
}
type fakeKubeExecutor struct {
keErr error
keStdOut string

View file

@ -1,21 +0,0 @@
package kubestr
import (
"context"
"fmt"
"github.com/kastenhq/kubestr/pkg/fio"
)
func (p *Kubestr) FIO(ctx context.Context, storageClass, configMap, jobName string) *TestOutput {
testName := "FIO test results"
fioResult, err := p.fio.RunFio(ctx, &fio.RunFIOArgs{
StorageClass: storageClass,
ConfigMapName: configMap,
JobName: jobName,
})
if err != nil {
return makeTestOutput(testName, StatusError, err.Error(), nil)
}
return makeTestOutput(testName, StatusOK, fmt.Sprintf("\n%s\n", fioResult), fioResult)
}

View file

@ -34,9 +34,9 @@ func (p *Kubestr) validateK8sVersion() *TestOutput {
testName := "Kubernetes Version Check"
version, err := p.validateK8sVersionHelper()
if err != nil {
return makeTestOutput(testName, StatusError, err.Error(), nil)
return MakeTestOutput(testName, StatusError, err.Error(), nil)
}
return makeTestOutput(testName, StatusOK, fmt.Sprintf("Valid kubernetes version (%s)", version.String()), version)
return MakeTestOutput(testName, StatusOK, fmt.Sprintf("Valid kubernetes version (%s)", version.String()), version)
}
// getK8sVersion fetches the k8s vesion
@ -75,9 +75,9 @@ func (p *Kubestr) validateRBAC() *TestOutput {
//fmt.Println(" Checking if Kubernetes RBAC is enabled:")
group, err := p.validateRBACHelper()
if err != nil {
return makeTestOutput(testName, StatusError, err.Error(), nil)
return MakeTestOutput(testName, StatusError, err.Error(), nil)
}
return makeTestOutput(testName, StatusOK, "Kubernetes RBAC is enabled", *group)
return MakeTestOutput(testName, StatusOK, "Kubernetes RBAC is enabled", *group)
}
// getRBAC runs the Rbac test
@ -98,9 +98,9 @@ func (p *Kubestr) validateAggregatedLayer() *TestOutput {
testName := "Aggregated Layer Check"
resourceList, err := p.validateAggregatedLayerHelper()
if err != nil {
makeTestOutput(testName, StatusError, err.Error(), nil)
MakeTestOutput(testName, StatusError, err.Error(), nil)
}
return makeTestOutput(testName, StatusOK, "The Kubernetes Aggregated Layer is enabled", resourceList)
return MakeTestOutput(testName, StatusOK, "The Kubernetes Aggregated Layer is enabled", resourceList)
}
// getAggregatedLayer checks the aggregated API layer

View file

@ -18,7 +18,7 @@ type Kubestr struct {
sdsfgValidator snapshotDataSourceFG
storageClassList *sv1.StorageClassList
volumeSnapshotClassList *unstructured.UnstructuredList
fio fio.FIO
Fio fio.FIO
}
const Logo = `
@ -48,7 +48,7 @@ func NewKubestr() (*Kubestr, error) {
cli: cli,
dynCli: dynCli,
},
fio: &fio.FIOrunner{
Fio: &fio.FIOrunner{
Cli: cli,
},
}, nil

View file

@ -93,7 +93,7 @@ func (t *TestOutput) Print() {
}
}
func makeTestOutput(testname string, code StatusCode, mesg string, raw interface{}) *TestOutput {
func MakeTestOutput(testname string, code StatusCode, mesg string, raw interface{}) *TestOutput {
return &TestOutput{
TestName: testname,
Status: []Status{makeStatus(code, mesg, nil)},