forked from litmuschaos/litmus-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
orchestrate-experiment.go
153 lines (124 loc) · 4.37 KB
/
orchestrate-experiment.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package lib
import (
clients "github.com/litmuschaos/litmus-go/pkg/clients"
"github.com/litmuschaos/litmus-go/pkg/log"
"github.com/litmuschaos/litmus-go/pkg/types"
"github.com/litmuschaos/litmus-go/pkg/utils/common"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// we borrow pod-memory-hog's types package since it has almost everything we require
experimentTypes "github.com/litmuschaos/litmus-go/pkg/generic/pod-memory-hog/types"
)
// ExperimentOrchestrationDetails bundles together all details connected to the orchestration
// of and experiment.
type ExperimentOrchestrationDetails struct {
ExperimentDetails *experimentTypes.ExperimentDetails
Clients clients.ClientSets
ResultDetails *types.ResultDetails
EventDetails *types.EventDetails
ChaosDetails *types.ChaosDetails
TargetPodList corev1.PodList
}
// TargetContainer returns the targeted container in the targeted pod
func TargetContainer(exp ExperimentOrchestrationDetails, appName string) (string, error) {
pod, err := exp.Clients.KubeClient.CoreV1().
Pods(exp.ExperimentDetails.AppNS).
Get(appName, v1.GetOptions{})
targetContainer := ""
if err == nil {
targetContainer = pod.Spec.Containers[0].Name
}
return targetContainer, err
}
// ChaosInjector is and interface for abstracting all chaos injection mechanisms
type ChaosInjector interface {
InjectChaosInSerialMode(
exp ExperimentOrchestrationDetails) error
InjectChaosInParallelMode(
exp ExperimentOrchestrationDetails) error
}
// safeExperiment is an abstraction for lifting errors while orchestrating experiments
type safeExperiment struct {
experiment ExperimentOrchestrationDetails
err error
}
func (exp *safeExperiment) verifyAppLabelOrTargetPodSpecified() {
if exp.err != nil {
return
}
targetPods := exp.experiment.ExperimentDetails.TargetPods
appLabel := exp.experiment.ChaosDetails.AppDetail.Label
if targetPods == "" && appLabel == "" {
exp.err = errors.Errorf("Please provide one of appLabel or TARGET_PODS")
}
}
func (exp *safeExperiment) obtainTargetPods() {
if exp.err != nil {
return
}
exp.experiment.TargetPodList, exp.err = common.GetPodList(
exp.experiment.ExperimentDetails.TargetPods,
exp.experiment.ExperimentDetails.PodsAffectedPerc,
exp.experiment.Clients,
exp.experiment.ChaosDetails,
)
}
func (exp *safeExperiment) logTargetPodNames() {
if exp.err != nil {
return
}
podNames := []string{}
for _, pod := range exp.experiment.TargetPodList.Items {
podNames = append(podNames, pod.Name)
}
log.Infof("Target pods list for chaos, %v", podNames)
}
func (exp *safeExperiment) obtainTargetContainer() {
if exp.err != nil {
return
}
experimentDetails := exp.experiment.ExperimentDetails
if experimentDetails.TargetContainer != "" {
return
}
experimentDetails.TargetContainer, exp.err = TargetContainer(
exp.experiment, exp.experiment.TargetPodList.Items[0].Name)
if exp.err != nil {
exp.err = errors.Errorf(
"Unable to get the target container name, err: %v", exp.err)
}
}
func (exp *safeExperiment) injectChaos(chaosInjector ChaosInjector) {
if exp.err != nil {
return
}
switch exp.experiment.ExperimentDetails.Sequence {
case "serial":
exp.err = chaosInjector.InjectChaosInSerialMode(exp.experiment)
default:
exp.err = chaosInjector.InjectChaosInParallelMode(exp.experiment)
}
}
func (exp *safeExperiment) waitForRampTimeDuration(sequence string) {
rampTime := exp.experiment.ExperimentDetails.RampTime
if exp.err != nil || rampTime == 0 {
return
}
log.Infof("[Ramp]: Waiting for the %vs ramp time %s injecting chaos",
rampTime, sequence)
common.WaitForDuration(rampTime)
}
// OrchestrateExperiment orchestrates a new chaos experiment with the given experiment details
// and the ChaosInjector for the chaos injection mechanism.
func OrchestrateExperiment(exp ExperimentOrchestrationDetails, chaosInjector ChaosInjector) error {
safeExperimentOrchestrator := safeExperiment{experiment: exp}
safeExperimentOrchestrator.waitForRampTimeDuration("before")
safeExperimentOrchestrator.verifyAppLabelOrTargetPodSpecified()
safeExperimentOrchestrator.obtainTargetPods()
safeExperimentOrchestrator.logTargetPodNames()
safeExperimentOrchestrator.obtainTargetContainer()
safeExperimentOrchestrator.injectChaos(chaosInjector)
safeExperimentOrchestrator.waitForRampTimeDuration("after")
return safeExperimentOrchestrator.err
}