Skip to content

Commit

Permalink
[chore] Refactoring of Codebase (#23)
Browse files Browse the repository at this point in the history
* [refact/chore] chaos-executor: Refactor critial areas for reusable code.

Signed-off-by: Rahul M Chheda <[email protected]>
  • Loading branch information
rahulchheda authored and Chandan Kumar committed Jan 7, 2020
1 parent 329363a commit ff7e395
Show file tree
Hide file tree
Showing 10 changed files with 389 additions and 291 deletions.
127 changes: 34 additions & 93 deletions bin/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/litmuschaos/chaos-executor/pkg/utils"
"github.com/litmuschaos/chaos-executor/pkg/utils/analytics"
"github.com/litmuschaos/chaos-operator/pkg/apis/litmuschaos/v1alpha1"
)

// getKubeConfig setup the config for access cluster resource
Expand All @@ -31,30 +30,17 @@ func getKubeConfig() (*rest.Config, error) {
return config, err
}

// checkStatusListForExp will loook for the Experiment in AppNamespace
func checkStatusListForExp(status []v1alpha1.ExperimentStatuses, jobName string) int {
for i := range status {
if status[i].Name == jobName {
return i
}
}
return -1
}

func main() {

engineDetails := utils.EngineDetails{}
clients := utils.ClientSets{}
// Getting the config
// Getting the kubeconfig
config, err := getKubeConfig()
if err != nil {
log.Fatalf("Error in fetching the config, error : %v", err)
}

// clientSet creation for further use.

err = clients.GenerateClientSets(config)
if err != nil {
if err = clients.GenerateClientSets(config); err != nil {
log.Fatalf("Unable to create ClientSets")
}

Expand All @@ -71,109 +57,64 @@ func main() {
}

experiment := utils.NewExperimentDetails()
experiment.Name = engineDetails.Experiments[i]
experiment.Namespace = engineDetails.AppNamespace
experiment.SvcAccount = engineDetails.SvcAccount
log.Infof("Printing experiment.Name: %v, experiment.Namespace : %v", experiment.Name, experiment.Namespace)
experiment.SetValueFromChaosEngine(engineDetails, i)
experiment.SetValueFromChaosExperiment(clients)
experiment.SetENV(engineDetails, clients)

log.Infoln("Going with the experiment Name: " + engineDetails.Experiments[i])
experimentStatus := utils.ExperimentStatus{}
experimentStatus.IntialExperimentStatus(experiment)
experimentStatus.InitialPatchEngine(engineDetails, clients)

log.Infof("Preparing to run Chaos Experiment: %v", experiment.Name)

// isFound will return the status of experiment in that namespace
// 1 -> found, 0 -> not-found
isFound := experiment.CheckExistence(clients)
isFound, err := experiment.CheckExistence(clients)
log.Infoln("Experiment Found Status : ", isFound)

// If not found in AppNamespace skip the further steps
if !isFound {
log.Infoln("Can't Find Experiment Name : "+engineDetails.Experiments[i], "In Namespace : "+engineDetails.AppNamespace)
log.Infoln("Not Executing the Experiment : " + engineDetails.Experiments[i])
engineDetails.ExperimentNotFoundPatchEngine(experiment, clients)
log.Infof("Unable to list Chaos Experiment: %v, in Namespace: %v, skipping execution, with error: %v", experiment.Name, experiment.Namespace, err)
break
}

log.Infoln("Getting the Default ENV Variables")

// Get the Default ENV's from ChaosExperiment
experiment.SetDefaultEnv(clients)

log.Info("Printing the Default Variables", experiment.Env)

// Get the ConfigMaps for patching them in the job creation
log.Infoln("Find the configMaps in the chaosExperiments")

experiment.SetConfigMaps(clients)

err := experiment.ValidateConfigMaps(clients)
if err != nil {
log.Infof("Aborting Execution")
return
// Patch ConfigMaps to ChaosExperiment Job
if err := experiment.PatchConfigMaps(clients); err != nil {
log.Infof("Unable to patch ConfigMaps, due to: %v", err)
break
}

experiment.SetSecrets(clients)
err = experiment.ValidateSecrets(clients)
if err != nil {
log.Infof("Aborting Execution")
return
// Patch Secrets to ChaosExperiment Job
if err = experiment.PatchSecrets(clients); err != nil {
log.Infof("Unable to patch Secrets, due to: %v", err)
break
}

log.Infof("Validated ConfigMaps: %v", experiment.ConfigMaps)
log.Infof("Validated Secrets: %v", experiment.Secrets)

// Adding VolumeBuilders, according to the ConfigMaps, and Secrets from ChaosEXperiment
experiment.VolumeOpts.VolumeBuilders = utils.CreateVolumeBuilder(experiment.ConfigMaps, experiment.Secrets)

// Adding VoulmeMounts, according to the configMaps, and Secrets from ChaosEXperiment
experiment.VolumeOpts.VolumeMounts = utils.CreateVolumeMounts(experiment.ConfigMaps, experiment.Secrets)

// OverWriting the Defaults Varibles from the ChaosEngine ENV
log.Infoln("Patching some required ENV's")
experiment.SetEnvFromEngine(engineDetails.Name, clients)

// Adding some addition necessary ENV's
experiment.Env["CHAOSENGINE"] = engineDetails.Name
experiment.Env["APP_LABEL"] = engineDetails.AppLabel
experiment.Env["APP_NAMESPACE"] = engineDetails.AppNamespace
experiment.Env["APP_KIND"] = engineDetails.AppKind

log.Info("Printing the Over-ridden Variables")
log.Infoln(experiment.Env)

log.Infoln("Getting all the details of the experiment Name : " + engineDetails.Experiments[i])

// Fetching more details from the ChaosExperiment needed for execution
experiment.SetImage(clients)
experiment.SetArgs(clients)
experiment.SetLabels(clients)
log.Infof("Variables for ChaosJob: Experiment Labels: %v, Experiment Image: %v, experiment.Args: %v", experiment.ExpLabels, experiment.ExpImage, experiment.ExpArgs)

// Generation of Random String for appending it into Job
randomString := utils.RandomString()

// Setting the JobName in Experiment Realted struct
experiment.JobName = engineDetails.Experiments[i] + "-" + randomString

log.Infof("JobName for this Experiment : %v", experiment.JobName)
experiment.VolumeOpts.VolumeOperations(experiment.ConfigMaps, experiment.Secrets)

// Creation of PodTemplateSpec, and Final Job
err = utils.DeployJob(experiment, clients)
if err != nil {
log.Infof("Error while building Job : %v", err)
if err = utils.BuildingAndLaunchJob(experiment, clients); err != nil {
log.Infof("Unable to construct chaos experiment job due to: %v", err)
break
}

time.Sleep(5 * time.Second)
// Getting the Experiment Result Name
resultName := utils.GetResultName(engineDetails, i)

// Watching the Job till Completion
err = utils.WatchingJobtillCompletion(experiment, engineDetails, clients)
if err != nil {
if err = engineDetails.WatchJobForCompletion(experiment, clients); err != nil {
log.Infof("Unable to Watch the Job, error: %v", err)
break
}

// Will Update the chaosEngine Status
if err = engineDetails.UpdateEngineWithResult(experiment, clients); err != nil {
log.Infof("Unable to Update ChaosEngine Status due to: %v", err)
}

// Will Update the result,
// Delete / retain the Job, using the jobCleanUpPolicy
err = utils.UpdateResultWithJobAndDeletingJob(engineDetails, resultName, experiment, clients)
if err != nil {
log.Infof("Unable to Update ChaosResult, error: %v", err)
if err = engineDetails.DeleteJobAccordingToJobCleanUpPolicy(experiment, clients); err != nil {
log.Infof("Unable to Delete chaosExperiment Job due to: %v", err)
}
}
}
52 changes: 23 additions & 29 deletions pkg/utils/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ func BuildContainerSpec(experiment *ExperimentDetails, envVar []corev1.EnvVar) *
WithEnvsNew(envVar)

if experiment.VolumeOpts.VolumeMounts != nil {
log.Info("Building Container with VolumeMounts")
//log.Info(volumeMounts)
log.Infof("Building ChaosExperiment Job with VolumeMounts from ConfigMaps, and Secrets provided.")
containerSpec.WithVolumeMountsNew(experiment.VolumeOpts.VolumeMounts)
}

Expand All @@ -61,55 +60,50 @@ func getEnvFromMap(env map[string]string) []corev1.EnvVar {
return envVar
}

// DeployJob the Job using all the details gathered
func DeployJob(experiment *ExperimentDetails, clients ClientSets) error {

// BuildingAndLaunchJob builds Job, and then launch it.
func BuildingAndLaunchJob(experiment *ExperimentDetails, clients ClientSets) error {
envVar := getEnvFromMap(experiment.Env)
// Will build a PodSpecTemplate
// For creating the spec.template of the Job
pod := BuildPodTemplateSpec(experiment)

//Build Container to add in the Pod
containerForPod := BuildContainerSpec(experiment, envVar)
pod.WithContainerBuildersNew(containerForPod)

// Will build a PodSpecTemplate
pod := BuildPodTemplateSpec(experiment, containerForPod)
// Build JobSpec Template
jobspec := BuildJobSpec(pod)

job, err := experiment.BuildJob(pod, jobspec)
if err != nil {
log.Info("Unable to build Job")
log.Infof("Unable to build ChaosExperiment Job, due to: %v", err)
return err
}

// Creating the Job
_, err = clients.KubeClient.BatchV1().Jobs(experiment.Namespace).Create(job)
if err = experiment.launchJob(job, clients); err != nil {
return err
}
return nil
}

// launchJob spawn a kubernetes Job using the job Object recieved.
func (experiment *ExperimentDetails) launchJob(job *batchv1.Job, clients ClientSets) error {
_, err := clients.KubeClient.BatchV1().Jobs(experiment.Namespace).Create(job)
if err != nil {
log.Info("Unable to create the Job with the clientSet : ", err)
}
return nil
}

// BuildPodTemplateSpec return a PodTempplateSpec
func BuildPodTemplateSpec(experiment *ExperimentDetails) *podtemplatespec.Builder {
func BuildPodTemplateSpec(experiment *ExperimentDetails, containerForPod *container.Builder) *podtemplatespec.Builder {
podtemplate := podtemplatespec.NewBuilder().
WithName(experiment.JobName).
WithNamespace(experiment.Namespace).
WithLabels(experiment.ExpLabels).
WithServiceAccountName(experiment.SvcAccount).
WithRestartPolicy(corev1.RestartPolicyOnFailure)

// Add VolumeBuilders, if exists
if experiment.VolumeOpts.VolumeBuilders != nil {
log.Info("Building Pod with VolumeBuilders")
//log.Info(volumeBuilders)
podtemplate.WithVolumeBuilders(experiment.VolumeOpts.VolumeBuilders)
}

_, err := podtemplate.Build()
WithRestartPolicy(corev1.RestartPolicyOnFailure).
WithVolumeBuilders(experiment.VolumeOpts.VolumeBuilders).
WithContainerBuildersNew(containerForPod)

if err != nil {
log.Info(err)
if _, err := podtemplate.Build(); err != nil {
log.Infof("Unable to build ChaosExperiment Job, due to: %v", err)
return nil
}
return podtemplate
}
Expand All @@ -126,7 +120,7 @@ func BuildJobSpec(pod *podtemplatespec.Builder) *jobspec.Builder {
}

// BuildJob will build the JobObject for creation
func (experiment ExperimentDetails) BuildJob(pod *podtemplatespec.Builder, jobspec *jobspec.Builder) (*batchv1.Job, error) {
func (experiment *ExperimentDetails) BuildJob(pod *podtemplatespec.Builder, jobspec *jobspec.Builder) (*batchv1.Job, error) {
//restartPolicy := corev1.RestartPolicyOnFailure
jobObj, err := job.NewBuilder().
WithJobSpecBuilder(jobspec).
Expand Down
43 changes: 43 additions & 0 deletions pkg/utils/configMapUtils.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
package utils

import (
"errors"
log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

//PatchConfigMaps patches configmaps in experimentDetails struct.
func (expDetails *ExperimentDetails) PatchConfigMaps(clients ClientSets) error {
expDetails.SetConfigMaps(clients)
log.Infof("Validating configmaps specified in the ChaosExperiment")
err := expDetails.ValidateConfigMaps(clients)
if err != nil {
log.Infof("Error Validating configMaps, skipping Execution")
return err
}
return nil
}

// ValidateConfigMap validates the configMap, before checking or creating them.
func (clientSets ClientSets) ValidateConfigMap(configMapName string, experiment *ExperimentDetails) error {

Expand All @@ -14,3 +28,32 @@ func (clientSets ClientSets) ValidateConfigMap(configMapName string, experiment
return nil

}

// SetConfigMaps sets the value of configMaps in Experiment Structure
func (expDetails *ExperimentDetails) SetConfigMaps(clients ClientSets) {

chaosExperimentObj, err := clients.LitmusClient.LitmuschaosV1alpha1().ChaosExperiments(expDetails.Namespace).Get(expDetails.Name, metav1.GetOptions{})
if err != nil {
log.Infof("Unable to get ChaosEXperiment Resource, wouldn't not be able to patch ConfigMaps")
}
configMaps := chaosExperimentObj.Spec.Definition.ConfigMaps
expDetails.ConfigMaps = configMaps
}

// ValidateConfigMaps checks for configMaps in the Application Namespace
func (expDetails *ExperimentDetails) ValidateConfigMaps(clients ClientSets) error {

for _, v := range expDetails.ConfigMaps {
if v.Name == "" || v.MountPath == "" {
//log.Infof("Incomplete Information in ConfigMap, will skip execution")
return errors.New("Incomplete Information in ConfigMap, will skip execution")
}
err := clients.ValidateConfigMap(v.Name, expDetails)
if err != nil {
log.Infof("Unable to get ConfigMap with Name: %v, in namespace: %v", v.Name, expDetails.Namespace)
} else {
log.Infof("Succesfully Validated ConfigMap: %v", v.Name)
}
}
return nil
}
20 changes: 7 additions & 13 deletions pkg/utils/expNotFoundPatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,14 @@ package utils

import (
log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NotFoundPatchEngine patches the chaosEngine when ChaosExperiment is not Found
func NotFoundPatchEngine(i int, engineDetails EngineDetails, clients ClientSets) {
expEngine, err := clients.LitmusClient.LitmuschaosV1alpha1().ChaosEngines(engineDetails.AppNamespace).Get(engineDetails.Name, metav1.GetOptions{})
if err != nil {
log.Infoln("Could'nt Get the Engine : ", err)
}
expEngine.Status.Experiments[i].Status = "Experiment not Found in this Namespace"
expEngine.Status.Experiments[i].Verdict = "Not Executed"
log.Info("Patching Engine")
_, updateErr := clients.LitmusClient.LitmuschaosV1alpha1().ChaosEngines(engineDetails.AppNamespace).Update(expEngine)
if updateErr != nil {
log.Infoln("Unable to Patch Engine, Update Error : ", updateErr)
// ExperimentNotFoundPatchEngine patches the chaosEngine when ChaosExperiment is not Found
func (engineDetails EngineDetails) ExperimentNotFoundPatchEngine(experiment *ExperimentDetails, clients ClientSets) {

var expStatus ExperimentStatus
expStatus.NotFoundExperimentStatus(experiment)
if err := expStatus.PatchChaosEngineStatus(engineDetails, clients); err != nil {
log.Infof("Unable to Patch ChaosEngine with Status, error: %v", err)
}
}
Loading

0 comments on commit ff7e395

Please sign in to comment.