Skip to content

Commit

Permalink
fix(time chaos): timechaos not injected to the child process (chaos-m…
Browse files Browse the repository at this point in the history
…esh#3725)

* fix(time chaos): timechaos not injected to the child process

Signed-off-by: STRRL <[email protected]>

* chore: update CHANGELOG

Signed-off-by: STRRL <[email protected]>

* test(e2e): testcases for inject timechaos for child process

Signed-off-by: STRRL <[email protected]>

Signed-off-by: STRRL <[email protected]>
Co-authored-by: Ti Chi Robot <[email protected]>
  • Loading branch information
STRRL and ti-chi-bot authored Oct 26, 2022
1 parent 99c6581 commit f45d612
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ For more information and how-to, see [RFC: Keep A Changelog](https://github.com/
- Remove the explicit use of pingcap/log [#3674](https://github.com/chaos-mesh/chaos-mesh/pull/3674)
- Fix typo in controller error message [#3704](https://github.com/chaos-mesh/chaos-mesh/pull/3704)
- Fix panic when logging, log kvs as pair [#3716](https://github.com/chaos-mesh/chaos-mesh/pull/3716)
- Fix timechaos not injected into the child process [#3725](https://github.com/chaos-mesh/chaos-mesh/pull/3725)

### Security

Expand Down
6 changes: 2 additions & 4 deletions e2e-test/cmd/e2e_helper/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ FROM golang:1.18-alpine3.15

WORKDIR /src

COPY main.go /src
COPY go.mod /src
COPY go.sum /src
COPY . /src

RUN go build -o test main.go
RUN go build -o test .

FROM alpine:3.15

Expand Down
63 changes: 63 additions & 0 deletions e2e-test/cmd/e2e_helper/child_process_time_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2021 Chaos Mesh Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
"context"
"io/ioutil"
"net/http"
"os"
"os/exec"
"time"
)

type childProcessTimeServer interface {
Start(ctx context.Context) error
Time() (*time.Time, error)
}

var _ childProcessTimeServer = (*defaultChildProcessTimeServer)(nil)

// the default implementation would create another instance of e2e-helper, but bind with a different port
type defaultChildProcessTimeServer struct {
}

// Start implements childProcessTimeServer
func (s *defaultChildProcessTimeServer) Start(ctx context.Context) error {
selfPath, err := os.Executable()
if err != nil {
return err
}
return exec.CommandContext(ctx, selfPath, "--port", "8081").Run()
}

// Time implements childProcessTimeServer
func (s *defaultChildProcessTimeServer) Time() (*time.Time, error) {
resp, err := http.Get("http://localhost:8081/time")
if err != nil {
return nil, err
}
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
time, err := time.Parse(time.RFC3339Nano, string(bytes))
if err != nil {
return nil, err
}
return &time, nil
}
33 changes: 25 additions & 8 deletions e2e-test/cmd/e2e_helper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package main

import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
Expand All @@ -37,6 +38,10 @@ func main() {
flag.Parse()

s := newServer(*dataDir)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go s.childProcessTimeServer.Start(ctx)
err := s.setupUDPServer()
if err != nil {
fmt.Println("failed to serve udp server", err)
Expand All @@ -51,21 +56,24 @@ func main() {
}

type server struct {
mux *http.ServeMux
dataDir string
mux *http.ServeMux
dataDir string
childProcessTimeServer childProcessTimeServer

// ONLY FOR TEST: a buf without lock
recvBuf []byte
}

func newServer(dataDir string) *server {
s := &server{
mux: http.NewServeMux(),
dataDir: dataDir,
recvBuf: make([]byte, 5),
mux: http.NewServeMux(),
dataDir: dataDir,
recvBuf: make([]byte, 5),
childProcessTimeServer: &defaultChildProcessTimeServer{},
}
s.mux.HandleFunc("/ping", pong)
s.mux.HandleFunc("/time", s.timer)
s.mux.HandleFunc("/time", s.time)
s.mux.HandleFunc("/child-process-time", s.childProcessTime)
s.mux.HandleFunc("/io", s.ioTest)
s.mux.HandleFunc("/mistake", s.mistakeTest)
s.mux.HandleFunc("/network/send", s.networkSendTest)
Expand Down Expand Up @@ -100,11 +108,20 @@ func (s *server) setupUDPServer() error {
return nil
}

// a handler to print out the current time
func (s *server) timer(w http.ResponseWriter, _ *http.Request) {
// time write the current time as response body
func (s *server) time(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
}

// childProcessTime write the child process current time as response body
func (s *server) childProcessTime(w http.ResponseWriter, _ *http.Request) {
now, err := s.childProcessTimeServer.Time()
if err != nil {
panic(err)
}
w.Write([]byte(now.Format(time.RFC3339Nano)))
}

// a handler to test io chaos
func (s *server) mistakeTest(w http.ResponseWriter, _ *http.Request) {
path := filepath.Join(s.dataDir, "e2e-test")
Expand Down
4 changes: 4 additions & 0 deletions e2e-test/e2e/chaos/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ var _ = ginkgo.Describe("[Basic]", func() {
ginkgo.It("[Pause]", func() {
timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port)
})

ginkgo.It("[Child Process]", func() {
timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port)
})
})
})

Expand Down
20 changes: 20 additions & 0 deletions e2e-test/e2e/chaos/timechaos/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,23 @@ func getPodTimeNS(c http.Client, port uint16) (*time.Time, error) {
}
return &t, nil
}

// get pod current time in nanosecond
func getPodChildProcessTimeNS(c http.Client, port uint16) (*time.Time, error) {
resp, err := c.Get(fmt.Sprintf("http://localhost:%d/child-process-time", port))
if err != nil {
return nil, err
}

out, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return nil, err
}

t, err := time.Parse(time.RFC3339Nano, string(out))
if err != nil {
return nil, err
}
return &t, nil
}
73 changes: 73 additions & 0 deletions e2e-test/e2e/chaos/timechaos/time_skew.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,76 @@ func TestcaseTimeSkewPauseThenUnpause(
By("delete chaos CRD objects")
cli.Delete(ctx, timeChaos)
}

func TestcaseTimeSkewShouldAlsoAffectChildProces(
ns string,
cli client.Client,
c http.Client,
port uint16,
) {

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

By("wait e2e helper ready")
err := util.WaitE2EHelperReady(c, port)
framework.ExpectNoError(err, "wait e2e helper ready error")

By("create chaos CRD objects")
initTime, err := getPodChildProcessTimeNS(c, port)
framework.ExpectNoError(err, "failed to get pod time")

timeChaos := &v1alpha1.TimeChaos{
ObjectMeta: metav1.ObjectMeta{
Name: "timer-time-chaos",
Namespace: ns,
},
Spec: v1alpha1.TimeChaosSpec{
Duration: pointer.StringPtr("9m"),
TimeOffset: "-1h",
ContainerSelector: v1alpha1.ContainerSelector{
PodSelector: v1alpha1.PodSelector{
Selector: v1alpha1.PodSelectorSpec{
GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
Namespaces: []string{ns},
LabelSelectors: map[string]string{"app": "timer"},
},
},
Mode: v1alpha1.OneMode,
},
},
},
}
err = cli.Create(ctx, timeChaos)
framework.ExpectNoError(err, "create time chaos error")

By("waiting for assertion")
err = wait.PollImmediate(5*time.Second, 5*time.Minute, func() (done bool, err error) {
podTime, err := getPodChildProcessTimeNS(c, port)
framework.ExpectNoError(err, "failed to get pod time")
if podTime.Before(*initTime) {
return true, nil
}
return false, nil
})
framework.ExpectNoError(err, "time chaos doesn't work as expected")

By("delete chaos CRD objects")
err = cli.Delete(ctx, timeChaos)
framework.ExpectNoError(err, "failed to delete time chaos")

By("waiting for assertion recovering")
err = wait.Poll(5*time.Second, 1*time.Minute, func() (done bool, err error) {
podTime, err := getPodChildProcessTimeNS(c, port)
framework.ExpectNoError(err, "failed to get pod time")
// since there is no timechaos now, current pod time should not be earlier
// than the init time
if podTime.Before(*initTime) {
return true, nil
}
return false, nil
})
framework.ExpectError(err, "wait no timechaos error")
framework.ExpectEqual(err.Error(), wait.ErrWaitTimeout.Error())
By("success to perform time chaos")
}
2 changes: 1 addition & 1 deletion pkg/chaosdaemon/tasks/process_group_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (gp *ProcessGroupHandler) Inject(pid IsID) error {
gp.Logger.Error(err, "failed to create child process")
continue
}
err = childProcessChaos.Inject(pid)
err = childProcessChaos.Inject(childSysPID)
if err != nil {
gp.Logger.Error(err, "failed to inject new child process")
continue
Expand Down

0 comments on commit f45d612

Please sign in to comment.