Skip to content

Commit e3c0492

Browse files
authored
Response Body modification in HTTP Status code experiment (litmuschaos#556)
* added response body in status code; Added content encoding and type in body and status; Removed unnecessary logging Signed-off-by: Akash Shrivastava <akash.shrivastava@harness.io>
1 parent f82e035 commit e3c0492

File tree

5 files changed

+90
-37
lines changed

5 files changed

+90
-37
lines changed

chaoslib/litmus/http-chaos/helper/http-helper.go

+35-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package helper
22

33
import (
4+
"bytes"
45
"fmt"
56
"os"
67
"os/exec"
@@ -63,7 +64,7 @@ func Helper(clients clients.ClientSets) {
6364

6465
}
6566

66-
//prepareK8sHttpChaos contains the prepration steps before chaos injection
67+
// prepareK8sHttpChaos contains the prepration steps before chaos injection
6768
func prepareK8sHttpChaos(experimentsDetails *experimentTypes.ExperimentDetails, clients clients.ClientSets, eventsDetails *types.EventDetails, chaosDetails *types.ChaosDetails, resultDetails *types.ResultDetails) error {
6869

6970
containerID, err := common.GetRuntimeBasedContainerID(experimentsDetails.ContainerRuntime, experimentsDetails.SocketPath, experimentsDetails.TargetPods, experimentsDetails.AppNS, experimentsDetails.TargetContainer, clients)
@@ -163,16 +164,15 @@ func startProxy(experimentDetails *experimentTypes.ExperimentDetails, pid int) e
163164
createProxyCommand := fmt.Sprintf("(sudo nsenter -t %d -n toxiproxy-cli create -l 0.0.0.0:%d -u 0.0.0.0:%d proxy)", pid, experimentDetails.ProxyPort, experimentDetails.TargetServicePort)
164165
createToxicCommand := fmt.Sprintf("(sudo nsenter -t %d -n toxiproxy-cli toxic add %s --toxicity %f proxy)", pid, toxics, float32(experimentDetails.Toxicity)/100.0)
165166

166-
// sleep 10 is added for proxy-server to be ready for creating proxy and adding toxics
167-
chaosCommand := fmt.Sprintf("%s && sleep 10 && %s && %s", startProxyServerCommand, createProxyCommand, createToxicCommand)
167+
// sleep 2 is added for proxy-server to be ready for creating proxy and adding toxics
168+
chaosCommand := fmt.Sprintf("%s && sleep 2 && %s && %s", startProxyServerCommand, createProxyCommand, createToxicCommand)
168169

169-
cmd := exec.Command("/bin/bash", "-c", chaosCommand)
170-
log.Infof("[Chaos]: Starting proxy server: %s", cmd.String())
170+
log.Infof("[Chaos]: Starting proxy server")
171171

172-
_, err := cmd.CombinedOutput()
173-
if err != nil {
172+
if err := runCommand(chaosCommand); err != nil {
174173
return err
175174
}
175+
176176
log.Info("[Info]: Proxy started successfully")
177177
return nil
178178
}
@@ -182,11 +182,9 @@ func startProxy(experimentDetails *experimentTypes.ExperimentDetails, pid int) e
182182
// and execute the proxy related command inside it.
183183
func killProxy(experimentDetails *experimentTypes.ExperimentDetails, pid int) error {
184184
stopProxyServerCommand := fmt.Sprintf("sudo nsenter -t %d -n sudo kill -9 $(ps aux | grep [t]oxiproxy | awk 'FNR==1{print $1}')", pid)
185-
cmd := exec.Command("/bin/bash", "-c", stopProxyServerCommand)
186-
log.Infof("[Chaos]: Stopping proxy server: %s", cmd.String())
185+
log.Infof("[Chaos]: Stopping proxy server")
187186

188-
_, err := cmd.CombinedOutput()
189-
if err != nil {
187+
if err := runCommand(stopProxyServerCommand); err != nil {
190188
return err
191189
}
192190

@@ -199,13 +197,12 @@ func killProxy(experimentDetails *experimentTypes.ExperimentDetails, pid int) er
199197
// and execute the iptables related command inside it.
200198
func addIPRuleSet(experimentDetails *experimentTypes.ExperimentDetails, pid int) error {
201199
addIPRuleSetCommand := fmt.Sprintf("(sudo nsenter -t %d -n iptables -t nat -A PREROUTING -i %v -p tcp --dport %d -j REDIRECT --to-port %d)", pid, experimentDetails.NetworkInterface, experimentDetails.TargetServicePort, experimentDetails.ProxyPort)
202-
cmd := exec.Command("/bin/bash", "-c", addIPRuleSetCommand)
203-
log.Infof("[Chaos]: Adding IPtables ruleset: %s", cmd.String())
200+
log.Infof("[Chaos]: Adding IPtables ruleset")
204201

205-
_, err := cmd.CombinedOutput()
206-
if err != nil {
202+
if err := runCommand(addIPRuleSetCommand); err != nil {
207203
return err
208204
}
205+
209206
log.Info("[Info]: IP rule set added successfully")
210207
return nil
211208
}
@@ -215,18 +212,17 @@ func addIPRuleSet(experimentDetails *experimentTypes.ExperimentDetails, pid int)
215212
// and execute the iptables related command inside it.
216213
func removeIPRuleSet(experimentDetails *experimentTypes.ExperimentDetails, pid int) error {
217214
removeIPRuleSetCommand := fmt.Sprintf("sudo nsenter -t %d -n iptables -t nat -D PREROUTING -i %v -p tcp --dport %d -j REDIRECT --to-port %d", pid, experimentDetails.NetworkInterface, experimentDetails.TargetServicePort, experimentDetails.ProxyPort)
218-
cmd := exec.Command("/bin/bash", "-c", removeIPRuleSetCommand)
219-
log.Infof("[Chaos]: Removing IPtables ruleset: %s", cmd.String())
215+
log.Infof("[Chaos]: Removing IPtables ruleset")
220216

221-
_, err := cmd.CombinedOutput()
222-
if err != nil {
217+
if err := runCommand(removeIPRuleSetCommand); err != nil {
223218
return err
224219
}
220+
225221
log.Info("[Info]: IP rule set removed successfully")
226222
return nil
227223
}
228224

229-
//getENV fetches all the env variables from the runner pod
225+
// getENV fetches all the env variables from the runner pod
230226
func getENV(experimentDetails *experimentTypes.ExperimentDetails) {
231227
experimentDetails.ExperimentName = types.Getenv("EXPERIMENT_NAME", "")
232228
experimentDetails.InstanceID = types.Getenv("INSTANCE_ID", "")
@@ -247,6 +243,25 @@ func getENV(experimentDetails *experimentTypes.ExperimentDetails) {
247243
experimentDetails.Toxicity, _ = strconv.Atoi(types.Getenv("TOXICITY", "100"))
248244
}
249245

246+
func runCommand(chaosCommand string) error {
247+
var stdout, stderr bytes.Buffer
248+
249+
cmd := exec.Command("/bin/bash", "-c", chaosCommand)
250+
cmd.Stdout = &stdout
251+
cmd.Stderr = &stderr
252+
err = cmd.Run()
253+
errStr := stderr.String()
254+
if err != nil {
255+
// if we get standard error then, return the same
256+
if errStr != "" {
257+
return errors.New(errStr)
258+
}
259+
// if not standard error found, return error
260+
return err
261+
}
262+
return nil
263+
}
264+
250265
// abortWatcher continuously watch for the abort signals
251266
func abortWatcher(targetPID int, resultName, chaosNS string, experimentDetails *experimentTypes.ExperimentDetails) {
252267

chaoslib/litmus/http-chaos/lib/modify-body/modify-body.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package modifybody
22

33
import (
44
"fmt"
5+
"math"
6+
"strings"
57

68
http_chaos "github.com/litmuschaos/litmus-go/chaoslib/litmus/http-chaos/lib"
79
clients "github.com/litmuschaos/litmus-go/pkg/clients"
@@ -11,18 +13,33 @@ import (
1113
"github.com/sirupsen/logrus"
1214
)
1315

14-
//PodHttpModifyBodyChaos contains the steps to prepare and inject http modify body chaos
16+
// PodHttpModifyBodyChaos contains the steps to prepare and inject http modify body chaos
1517
func PodHttpModifyBodyChaos(experimentsDetails *experimentTypes.ExperimentDetails, clients clients.ClientSets, resultDetails *types.ResultDetails, eventsDetails *types.EventDetails, chaosDetails *types.ChaosDetails) error {
1618

19+
// responseBodyMaxLength defines the max length of response body string to be printed. It is taken as
20+
// the min of length of body and 120 characters to avoid printing large response body.
21+
responseBodyMaxLength := int(math.Min(float64(len(experimentsDetails.ResponseBody)), 120))
22+
1723
log.InfoWithValues("[Info]: The chaos tunables are:", logrus.Fields{
1824
"Target Port": experimentsDetails.TargetServicePort,
1925
"Listen Port": experimentsDetails.ProxyPort,
2026
"Sequence": experimentsDetails.Sequence,
2127
"PodsAffectedPerc": experimentsDetails.PodsAffectedPerc,
2228
"Toxicity": experimentsDetails.Toxicity,
23-
"ResponseBody": experimentsDetails.ResponseBody,
29+
"ResponseBody": experimentsDetails.ResponseBody[0:responseBodyMaxLength],
30+
"Content Type": experimentsDetails.ContentType,
31+
"Content Encoding": experimentsDetails.ContentEncoding,
2432
})
2533

26-
args := fmt.Sprintf("-t modify_body -a body=\"%v\"", experimentsDetails.ResponseBody)
34+
args := fmt.Sprintf(
35+
`-t modify_body -a body="%v" -a content_type=%v -a content_encoding=%v`,
36+
EscapeQuotes(experimentsDetails.ResponseBody), experimentsDetails.ContentType, experimentsDetails.ContentEncoding)
2737
return http_chaos.PrepareAndInjectChaos(experimentsDetails, clients, resultDetails, eventsDetails, chaosDetails, args)
2838
}
39+
40+
// EscapeQuotes escapes the quotes in the given string
41+
func EscapeQuotes(input string) string {
42+
output := strings.ReplaceAll(input, `\`, `\\`)
43+
output = strings.ReplaceAll(output, `"`, `\"`)
44+
return output
45+
}

chaoslib/litmus/http-chaos/lib/statuscode/status-code.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package statuscode
22

33
import (
44
"fmt"
5+
"math"
56
"math/rand"
67
"strconv"
78
"strings"
89
"time"
910

1011
http_chaos "github.com/litmuschaos/litmus-go/chaoslib/litmus/http-chaos/lib"
12+
body "github.com/litmuschaos/litmus-go/chaoslib/litmus/http-chaos/lib/modify-body"
1113
clients "github.com/litmuschaos/litmus-go/pkg/clients"
1214
experimentTypes "github.com/litmuschaos/litmus-go/pkg/generic/http-chaos/types"
1315
"github.com/litmuschaos/litmus-go/pkg/log"
@@ -23,9 +25,13 @@ var acceptedStatusCodes = []string{
2325
"500", "501", "502", "503", "504",
2426
}
2527

26-
//PodHttpStatusCodeChaos contains the steps to prepare and inject http status code chaos
28+
// PodHttpStatusCodeChaos contains the steps to prepare and inject http status code chaos
2729
func PodHttpStatusCodeChaos(experimentsDetails *experimentTypes.ExperimentDetails, clients clients.ClientSets, resultDetails *types.ResultDetails, eventsDetails *types.EventDetails, chaosDetails *types.ChaosDetails) error {
2830

31+
// responseBodyMaxLength defines the max length of response body string to be printed. It is taken as
32+
// the min of length of body and 120 characters to avoid printing large response body.
33+
responseBodyMaxLength := int(math.Min(float64(len(experimentsDetails.ResponseBody)), 120))
34+
2935
log.InfoWithValues("[Info]: The chaos tunables are:", logrus.Fields{
3036
"Target Port": experimentsDetails.TargetServicePort,
3137
"Listen Port": experimentsDetails.ProxyPort,
@@ -34,9 +40,15 @@ func PodHttpStatusCodeChaos(experimentsDetails *experimentTypes.ExperimentDetail
3440
"Toxicity": experimentsDetails.Toxicity,
3541
"StatusCode": experimentsDetails.StatusCode,
3642
"ModifyResponseBody": experimentsDetails.ModifyResponseBody,
43+
"ResponseBody": experimentsDetails.ResponseBody[0:responseBodyMaxLength],
44+
"Content Type": experimentsDetails.ContentType,
45+
"Content Encoding": experimentsDetails.ContentEncoding,
3746
})
3847

39-
args := fmt.Sprintf("-t status_code -a status_code=%s -a modify_response_body=%d", experimentsDetails.StatusCode, stringBoolToInt(experimentsDetails.ModifyResponseBody))
48+
args := fmt.Sprintf(
49+
`-t status_code -a status_code=%s -a modify_response_body=%d -a response_body="%v" -a content_type=%s -a content_encoding=%s`,
50+
experimentsDetails.StatusCode, stringBoolToInt(experimentsDetails.ModifyResponseBody), body.EscapeQuotes(experimentsDetails.ResponseBody),
51+
experimentsDetails.ContentType, experimentsDetails.ContentEncoding)
4052
return http_chaos.PrepareAndInjectChaos(experimentsDetails, clients, resultDetails, eventsDetails, chaosDetails, args)
4153
}
4254

pkg/generic/http-chaos/environment/environment.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
clientTypes "k8s.io/apimachinery/pkg/types"
99
)
1010

11-
//GetENV fetches all the env variables from the runner pod
11+
// GetENV fetches all the env variables from the runner pod
1212
func GetENV(experimentDetails *experimentTypes.ExperimentDetails, expName string) {
1313
experimentDetails.ExperimentName = types.Getenv("EXPERIMENT_NAME", "")
1414
experimentDetails.ChaosNamespace = types.Getenv("CHAOS_NAMESPACE", "litmus")
@@ -47,11 +47,16 @@ func GetENV(experimentDetails *experimentTypes.ExperimentDetails, expName string
4747
case "pod-http-status-code":
4848
experimentDetails.StatusCode = types.Getenv("STATUS_CODE", "")
4949
experimentDetails.ModifyResponseBody = types.Getenv("MODIFY_RESPONSE_BODY", "true")
50+
experimentDetails.ResponseBody = types.Getenv("RESPONSE_BODY", "")
51+
experimentDetails.ContentType = types.Getenv("CONTENT_TYPE", "text/plain")
52+
experimentDetails.ContentEncoding = types.Getenv("CONTENT_ENCODING", "")
5053
case "pod-http-modify-header":
5154
experimentDetails.HeadersMap = types.Getenv("HEADERS_MAP", "{}")
5255
experimentDetails.HeaderMode = types.Getenv("HEADER_MODE", "response")
5356
case "pod-http-modify-body":
5457
experimentDetails.ResponseBody = types.Getenv("RESPONSE_BODY", "")
58+
experimentDetails.ContentType = types.Getenv("CONTENT_TYPE", "text/plain")
59+
experimentDetails.ContentEncoding = types.Getenv("CONTENT_ENCODING", "")
5560
case "pod-http-reset-peer":
5661
experimentDetails.ResetTimeout, _ = strconv.Atoi(types.Getenv("RESET_TIMEOUT", "0"))
5762
}

pkg/generic/http-chaos/types/types.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,19 @@ type ExperimentDetails struct {
3434
SetHelperData string
3535
Sequence string
3636
NodeLabel string
37-
NetworkInterface string
38-
TargetServicePort int
39-
Toxicity int
40-
ProxyPort int
41-
Latency int
42-
StatusCode string
43-
ModifyResponseBody string
44-
HeadersMap string
45-
HeaderMode string
46-
ResponseBody string
47-
ResetTimeout int
37+
38+
NetworkInterface string
39+
TargetServicePort int
40+
Toxicity int
41+
ProxyPort int
42+
43+
Latency int
44+
ResetTimeout int
45+
StatusCode string
46+
ModifyResponseBody string
47+
HeadersMap string
48+
HeaderMode string
49+
ResponseBody string
50+
ContentType string
51+
ContentEncoding string
4852
}

0 commit comments

Comments
 (0)