1
1
package experiments
2
2
3
3
import (
4
+ "fmt"
4
5
"testing"
6
+ "time"
5
7
6
- "github.com/litmuschaos/chaos-ci-lib/pkg "
8
+ "github.com/google/uuid "
7
9
"github.com/litmuschaos/chaos-ci-lib/pkg/environment"
8
- engine "github.com/litmuschaos/chaos-ci-lib/pkg/generic/pod-delete/lib"
9
10
"github.com/litmuschaos/chaos-ci-lib/pkg/types"
10
- "github.com/litmuschaos/chaos-operator /pkg/apis/litmuschaos/v1alpha1 "
11
+ experiment "github.com/litmuschaos/litmus-go-sdk /pkg/apis/experiment "
11
12
models "github.com/litmuschaos/litmus/chaoscenter/graphql/server/graph/model"
12
13
. "github.com/onsi/ginkgo"
13
14
. "github.com/onsi/gomega"
14
15
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
15
16
"k8s.io/klog"
17
+ "sigs.k8s.io/yaml"
16
18
)
17
19
18
20
func TestPodDelete (t * testing.T ) {
@@ -23,145 +25,202 @@ func TestPodDelete(t *testing.T) {
23
25
//BDD for running pod-delete experiment
24
26
var _ = Describe ("BDD of running pod-delete experiment" , func () {
25
27
26
- Context ("Check for pod-delete experiment" , func () {
28
+ Context ("Check for pod-delete experiment via SDK " , func () {
27
29
// Define variables accessible to It and AfterEach
28
30
var (
29
31
experimentsDetails types.ExperimentDetails
30
32
clients environment.ClientSets
31
- chaosEngine v1alpha1.ChaosEngine
32
- err error
33
+ err error
33
34
)
34
35
35
- BeforeEach (func () {
36
+ BeforeEach (func () {
36
37
experimentsDetails = types.ExperimentDetails {}
37
38
clients = environment.ClientSets {}
38
- chaosEngine = v1alpha1.ChaosEngine {}
39
39
err = nil
40
40
41
41
//Getting kubeConfig and Generate ClientSets
42
- By ("[PreChaos]: Getting kubeconfig and generate clientset" )
42
+ By ("[PreChaos]: Getting kubeconfig and generate clientset" )
43
43
err = clients .GenerateClientSetFromKubeConfig ()
44
- Expect (err ).To (BeNil (), "Unable to Get the kubeconfig, due to {%v}" , err ) // Use BeNil directly
44
+ Expect (err ).To (BeNil (), "Unable to Get the kubeconfig, due to {%v}" , err )
45
45
46
46
//Fetching all the default ENV
47
47
By ("[PreChaos]: Fetching all default ENVs" )
48
48
klog .Infof ("[PreReq]: Getting the ENVs for the %v experiment" , experimentsDetails .ExperimentName )
49
49
environment .GetENV (& experimentsDetails , "pod-delete" , "pod-delete-engine" )
50
50
51
- // Connect to ChaosCenter Infrastructure if flag is set
52
- By ("[PreChaos]: Conditionally connecting Infra via SDK" )
53
- if experimentsDetails .ConnectInfraFlag {
54
- klog .Infof ("CONNECT_INFRA flag is set, attempting to connect infrastructure: %s" , experimentsDetails .InfraName )
55
- err = clients .GenerateClientSetFromSDK ()
56
- Expect (err ).To (BeNil (), "Unable to generate Litmus SDK client, due to {%v}" , err )
57
-
58
- sdkConfig := map [string ]interface {}{
59
- "namespace" : experimentsDetails .InfraNamespace ,
60
- "serviceAccount" : experimentsDetails .InfraSA ,
61
- "mode" : experimentsDetails .InfraScope ,
62
- "description" : experimentsDetails .InfraDescription ,
63
- "platformName" : experimentsDetails .InfraPlatformName ,
64
- "environmentID" : experimentsDetails .InfraEnvironmentID ,
65
- "nsExists" : experimentsDetails .InfraNsExists ,
66
- "saExists" : experimentsDetails .InfraSaExists ,
67
- "skipSSL" : experimentsDetails .InfraSkipSSL ,
68
- "nodeSelector" : experimentsDetails .InfraNodeSelector ,
69
- "tolerations" : experimentsDetails .InfraTolerations ,
70
- }
71
-
72
- infraData , errSdk := clients .SDKClient .Infrastructure ().Create (experimentsDetails .InfraName , sdkConfig )
73
- Expect (errSdk ).To (BeNil (), "Failed to create infrastructure via SDK, due to {%v}" , errSdk )
74
- if errSdk == nil { // Only proceed if connection was successful
75
- klog .Infof ("Successfully initiated infrastructure connection via SDK for: %v" , experimentsDetails .InfraName )
76
- // Attempt to extract the InfraID
77
- if infraData != nil {
78
- registerResponse , ok := infraData .(* models.RegisterInfraResponse )
79
- if ok && registerResponse != nil {
80
- experimentsDetails .ConnectedInfraID = registerResponse .InfraID
81
- klog .Infof ("Stored connected infra ID: %s" , experimentsDetails .ConnectedInfraID )
82
- } else {
83
- klog .Warningf ("Could not assert type '%T' to *models.RegisterInfraResponse or extract InfraID from SDK response for infra '%s'" , infraData , experimentsDetails .InfraName )
84
- }
85
- } else {
86
- klog .Warningf ("Infrastructure Create call returned nil data for infra '%s'" , experimentsDetails .InfraName )
87
- }
88
- }
89
- } else {
90
- klog .Info ("CONNECT_INFRA flag not set, skipping SDK infrastructure connection." )
51
+ // Connect to ChaosCenter Infrastructure via SDK (Mandatory)
52
+ By ("[PreChaos]: Connecting Infra via SDK" )
53
+ klog .Infof ("Attempting to connect infrastructure: %s" , experimentsDetails .InfraName )
54
+ err = clients .GenerateClientSetFromSDK ()
55
+ Expect (err ).To (BeNil (), "Unable to generate Litmus SDK client, due to {%v}" , err )
56
+
57
+ sdkConfig := map [string ]interface {}{
58
+ "namespace" : experimentsDetails .InfraNamespace ,
59
+ "serviceAccount" : experimentsDetails .InfraSA ,
60
+ "mode" : experimentsDetails .InfraScope ,
61
+ "description" : experimentsDetails .InfraDescription ,
62
+ "platformName" : experimentsDetails .InfraPlatformName ,
63
+ "environmentID" : experimentsDetails .InfraEnvironmentID ,
64
+ "nsExists" : experimentsDetails .InfraNsExists ,
65
+ "saExists" : experimentsDetails .InfraSaExists ,
66
+ "skipSSL" : experimentsDetails .InfraSkipSSL ,
67
+ "nodeSelector" : experimentsDetails .InfraNodeSelector ,
68
+ "tolerations" : experimentsDetails .InfraTolerations ,
91
69
}
70
+
71
+ infraData , errSdk := clients .SDKClient .Infrastructure ().Create (experimentsDetails .InfraName , sdkConfig )
72
+ Expect (errSdk ).To (BeNil (), "Failed to create infrastructure via SDK, due to {%v}" , errSdk )
73
+
74
+ Expect (infraData ).NotTo (BeNil (), "Infrastructure Create call returned nil data for infra '%s'" , experimentsDetails .InfraName )
75
+ registerResponse , ok := infraData .(* models.RegisterInfraResponse )
76
+ Expect (ok ).To (BeTrue (), "Could not assert type '%T' to *models.RegisterInfraResponse" , infraData )
77
+ Expect (registerResponse ).NotTo (BeNil (), "RegisterInfraResponse is nil after type assertion" )
78
+ Expect (registerResponse .InfraID ).NotTo (BeEmpty (), "Extracted InfraID is empty" )
79
+
80
+ experimentsDetails .ConnectedInfraID = registerResponse .InfraID
81
+ klog .Infof ("Successfully connected infrastructure via SDK. Stored ID: %s" , experimentsDetails .ConnectedInfraID )
82
+
83
+ // Fail setup explicitly if ID is empty after checks
84
+ Expect (experimentsDetails .ConnectedInfraID ).NotTo (BeEmpty (), "Setup failed: ConnectedInfraID is empty after connection attempt." )
92
85
})
93
86
94
- It ("Should check for the pod delete experiment" , func () { // Use It directly
87
+ It ("Should run the pod delete experiment via SDK " , func () {
95
88
96
89
// Ensure pre-checks passed from BeforeEach
97
90
Expect (err ).To (BeNil (), "Error during BeforeEach setup: %v" , err )
98
91
99
- // Install RBAC for experiment Execution
100
- By ("[Prepare]: Prepare and install RBAC" )
101
- err = pkg .InstallRbac (& experimentsDetails , experimentsDetails .ChaosNamespace )
102
- Expect (err ).To (BeNil (), "fail to install rbac for the experiment, due to {%v}" , err )
103
-
104
- // Install ChaosEngine for experiment Execution
105
- By ("[Prepare]: Prepare and install ChaosEngine" )
106
- err = engine .InstallPodDeleteEngine (& experimentsDetails , & chaosEngine , clients )
107
- Expect (err ).To (BeNil (), "fail to install chaosengine, due to {%v}" , err )
108
-
109
- //Checking runner pod running state
110
- By ("[Status]: Runner pod running status check" )
111
- err = pkg .RunnerPodStatus (& experimentsDetails , chaosEngine .Namespace , clients )
112
- if err != nil && chaosEngine .Namespace != experimentsDetails .AppNS {
113
- err = pkg .RunnerPodStatus (& experimentsDetails , experimentsDetails .AppNS , clients )
92
+ // V3 SDK PATH (Now the only path)
93
+ klog .Info ("Executing V3 SDK Path for Experiment" )
94
+
95
+ // 1. Construct Experiment Request
96
+ By ("[SDK Prepare]: Constructing Chaos Experiment Request" )
97
+ experimentName := experimentsDetails .EngineName
98
+ experimentID := experimentName + "-" + uuid .New ().String ()[:8 ]
99
+ experimentRequest , errConstruct := ConstructPodDeleteExperimentRequest (& experimentsDetails , experimentID )
100
+ Expect (errConstruct ).To (BeNil (), "Failed to construct experiment request: %v" , errConstruct )
101
+
102
+ // 2. Create and Run Experiment via SDK
103
+ By ("[SDK Prepare]: Creating and Running Chaos Experiment" )
104
+ creds := clients .GetSDKCredentials ()
105
+ runResponse , errRun := experiment .CreateExperiment (clients .LitmusProjectID , * experimentRequest , creds )
106
+ Expect (errRun ).To (BeNil (), "Failed to create/run experiment via SDK: %v" , errRun )
107
+ Expect (runResponse .Data .RunExperimentDetails .NotifyID ).NotTo (BeEmpty (), "Experiment Run ID (NotifyID) should not be empty" )
108
+ experimentsDetails .ExperimentRunID = runResponse .Data .RunExperimentDetails .NotifyID
109
+ klog .Infof ("Experiment Run successfully triggered via SDK. Run ID: %s" , experimentsDetails .ExperimentRunID )
110
+
111
+ // 3. Poll for Experiment Run Status
112
+ By ("[SDK Status]: Polling for Experiment Run Status" )
113
+ var finalStatus * experiment.ExperimentRunResponse
114
+ var pollError error
115
+ timeout := time .After (8 * time .Minute )
116
+ ticker := time .NewTicker (15 * time .Second )
117
+ defer ticker .Stop ()
118
+
119
+ pollLoop:
120
+ for {
121
+ select {
122
+ case <- timeout :
123
+ pollError = fmt .Errorf ("timed out waiting for experiment run %s to complete after 8 minutes" , experimentsDetails .ExperimentRunID )
124
+ klog .Error (pollError )
125
+ break pollLoop
126
+ case <- ticker .C :
127
+ runStatus , errStatus := experiment .GetExperimentRun (clients .LitmusProjectID , experimentsDetails .ExperimentRunID , creds )
128
+ if errStatus != nil {
129
+ klog .Errorf ("Error fetching experiment run status for %s: %v" , experimentsDetails .ExperimentRunID , errStatus )
130
+ continue
131
+ }
132
+ currentPhase := runStatus .Data .ExperimentRun .Phase
133
+ klog .Infof ("Experiment Run %s current phase: %s" , experimentsDetails .ExperimentRunID , currentPhase )
134
+ isFinalPhase := false
135
+ finalPhases := []string {"Completed" , "Failed" , "Error" , "Stopped" , "Skipped" , "Aborted" , "Timeout" }
136
+ for _ , phase := range finalPhases {
137
+ if currentPhase == phase {
138
+ isFinalPhase = true
139
+ break
140
+ }
141
+ }
142
+ if isFinalPhase {
143
+ finalStatus = & runStatus .Data .ExperimentRun
144
+ klog .Infof ("Experiment Run %s reached final phase: %s" , experimentsDetails .ExperimentRunID , currentPhase )
145
+ break pollLoop
146
+ }
147
+ }
114
148
}
115
- Expect (err ).To (BeNil (), "Runner pod status check failed, due to {%v}" , err )
116
-
117
- //Chaos pod running status check
118
- By ("[Status]: Chaos pod running status check" )
119
- err = pkg .ChaosPodStatus (& experimentsDetails , clients )
120
- Expect (err ).To (BeNil (), "Chaos pod status check failed, due to {%v}" , err )
121
-
122
- //Waiting for chaos pod to get completed
123
- //And Print the logs of the chaos pod
124
- By ("[Status]: Wait for chaos pod completion and then print logs" )
125
- err = pkg .ChaosPodLogs (& experimentsDetails , clients )
126
- Expect (err ).To (BeNil (), "Fail to get the experiment chaos pod logs, due to {%v}" , err )
127
-
128
- //Checking the chaosresult verdict
129
- By ("[Verdict]: Checking the chaosresult verdict" )
130
- err = pkg .ChaosResultVerdict (& experimentsDetails , clients )
131
- Expect (err ).To (BeNil (), "ChasoResult Verdict check failed, due to {%v}" , err )
132
-
133
- //Checking chaosengine verdict
134
- By ("Checking the Verdict of Chaos Engine" )
135
- err = pkg .ChaosEngineVerdict (& experimentsDetails , clients )
136
- Expect (err ).To (BeNil (), "ChaosEngine Verdict check failed, due to {%v}" , err )
149
+
150
+ // 4. Post Validation / Verdict Check
151
+ By ("[SDK Verdict]: Checking Experiment Run Verdict" )
152
+ Expect (pollError ).To (BeNil ())
153
+ Expect (finalStatus ).NotTo (BeNil (), "Final status should not be nil after polling" )
154
+ Expect (finalStatus .Phase ).To (Equal ("Completed" ), fmt .Sprintf ("Experiment Run phase should be Completed, but got %s" , finalStatus .Phase ))
155
+
137
156
})
138
157
139
158
// Cleanup using AfterEach
140
- AfterEach (func () { // Use AfterEach directly
141
- if experimentsDetails . ConnectInfraFlag && experimentsDetails . ConnectedInfraID != "" {
142
- // Only attempt disconnect if infra was potentially connected and ID was stored
159
+ AfterEach (func () {
160
+ // Disconnect only if Infra ID was successfully stored
161
+ if experimentsDetails . ConnectedInfraID != "" {
143
162
By ("[CleanUp]: Disconnecting Infra via SDK" )
144
163
klog .Infof ("Attempting to disconnect infrastructure with ID: %s" , experimentsDetails .ConnectedInfraID )
145
- // Need SDK client - ensure 'clients' is accessible or re-initialize if needed
146
164
if clients .SDKClient == nil {
147
- // Re-initialize SDK client if not available (e.g., if BeforeEach failed partially)
148
165
klog .Warning ("SDK client not initialized in AfterEach, attempting re-initialization for cleanup..." )
149
166
errSdkInit := clients .GenerateClientSetFromSDK ()
150
167
if errSdkInit != nil {
151
168
klog .Errorf ("Failed to re-initialize SDK client for cleanup: %v" , errSdkInit )
152
- // Skip disconnect if client cannot be initialized
153
- return
169
+ return
154
170
}
155
171
}
156
172
errDisconnect := clients .SDKClient .Infrastructure ().Disconnect (experimentsDetails .ConnectedInfraID )
157
- // Use Expect directly due to dot import for Gomega
158
173
Expect (errDisconnect ).To (BeNil (), "Failed to disconnect infra %s via SDK, due to {%v}" , experimentsDetails .ConnectedInfraID , errDisconnect )
159
174
if errDisconnect == nil {
160
175
klog .Infof ("Successfully disconnected infrastructure: %s" , experimentsDetails .ConnectedInfraID )
161
176
}
162
- } else if experimentsDetails . ConnectInfraFlag {
163
- klog .Info ("[CleanUp]: ConnectInfraFlag was set but no connected infra ID found, skipping SDK disconnection." )
177
+ } else {
178
+ klog .Info ("[CleanUp]: No connected infra ID found, skipping SDK disconnection." )
164
179
}
165
180
})
166
181
})
167
182
})
183
+
184
+ // Helper function to construct the experiment request
185
+ // FIXME: This needs a proper implementation to generate the correct manifest YAML
186
+ // based on experimentDetails for pod-delete.
187
+ func ConstructPodDeleteExperimentRequest (details * types.ExperimentDetails , experimentID string ) (* models.SaveChaosExperimentRequest , error ) {
188
+ klog .Infof ("Constructing experiment request for %s with ID %s" , details .ExperimentName , experimentID )
189
+
190
+ // Placeholder manifest definition - Attempting single line definition for linter
191
+ const manifestYAML = `apiVersion: litmuschaos.io/v1alpha1\nkind: ChaosExperiment\nmetadata:\n name: %s\n namespace: %s\nspec:\n steps:\n - name: delete-pods\n definition:\n chaos:\n fault: pod-delete\n mode: "" # FIXME: Determine mode\n selector:\n namespaces:\n - "%s"\n labelSelectors:\n "%s"\n # FIXME: Inject other pod-delete fields\n probes: [] # FIXME: Add probes\n`
192
+
193
+ // Basic formatting - NEEDS PROPER POPULATION FROM 'details'
194
+ formattedManifest := fmt .Sprintf (manifestYAML ,
195
+ details .ExperimentName , // metadata.name
196
+ details .ChaosNamespace , // metadata.namespace
197
+ details .AppNS ,
198
+ details .AppLabel ,
199
+ )
200
+
201
+ // Validate and clean up the YAML structure
202
+ var manifestInterface interface {}
203
+ errYaml := yaml .Unmarshal ([]byte (formattedManifest ), & manifestInterface )
204
+ if errYaml != nil {
205
+ klog .Errorf ("Error unmarshalling constructed manifest: %v" , errYaml )
206
+ return nil , fmt .Errorf ("failed to unmarshal constructed manifest: %w" , errYaml )
207
+ }
208
+ finalManifestBytes , errYamlMarshal := yaml .Marshal (manifestInterface )
209
+ if errYamlMarshal != nil {
210
+ klog .Errorf ("Error marshalling final manifest: %v" , errYamlMarshal )
211
+ return nil , fmt .Errorf ("failed to marshal final manifest: %w" , errYamlMarshal )
212
+ }
213
+ finalManifestString := string (finalManifestBytes )
214
+ klog .Infof ("Constructed Manifest: %s" , finalManifestString )
215
+
216
+ request := & models.SaveChaosExperimentRequest {
217
+ ID : experimentID ,
218
+ Name : details .ExperimentName ,
219
+ Description : fmt .Sprintf ("CI/CD Triggered Chaos Experiment: %s" , details .ExperimentName ),
220
+ Tags : []string {"chaos-ci-lib" , details .ExperimentName },
221
+ InfraID : details .ConnectedInfraID ,
222
+ Manifest : finalManifestString ,
223
+ }
224
+ return request , nil
225
+ }
226
+
0 commit comments