diff --git a/Dockerfile.loadtester b/Dockerfile.loadtester index 238ad5c1..7c6c5e1d 100644 --- a/Dockerfile.loadtester +++ b/Dockerfile.loadtester @@ -1,20 +1,4 @@ -FROM golang:1.12 AS hey-builder - -RUN mkdir -p /go/src/github.com/rakyll/hey/ - -WORKDIR /go/src/github.com/rakyll/hey - -ADD https://github.com/rakyll/hey/archive/v0.1.1.tar.gz . - -RUN tar xzf v0.1.1.tar.gz --strip 1 - -RUN go get ./... - -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ - go install -ldflags '-w -extldflags "-static"' \ - /go/src/github.com/rakyll/hey - -FROM golang:1.11 AS builder +FROM golang:1.12 AS builder RUN mkdir -p /go/src/github.com/weaveworks/flagger/ @@ -26,15 +10,17 @@ RUN go test -race ./pkg/loadtester/ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o loadtester ./cmd/loadtester/* -FROM alpine:3.9 +FROM bats/bats:v1.1.0 RUN addgroup -S app \ && adduser -S -g app app \ - && apk --no-cache add ca-certificates curl + && apk --no-cache add ca-certificates curl jq WORKDIR /home/app -COPY --from=hey-builder /go/bin/hey /usr/local/bin/hey +RUN curl -sSLo hey "https://storage.googleapis.com/jblabs/dist/hey_linux_v0.1.2" && \ +chmod +x hey && mv hey /usr/local/bin/hey + COPY --from=builder /go/src/github.com/weaveworks/flagger/loadtester . RUN chown -R app:app ./ diff --git a/pkg/loadtester/bats.go b/pkg/loadtester/bats.go new file mode 100644 index 00000000..d27eb4b0 --- /dev/null +++ b/pkg/loadtester/bats.go @@ -0,0 +1,39 @@ +package loadtester + +import ( + "context" + "fmt" + "os/exec" +) + +const TaskTypeBats = "bats" + +type BatsTask struct { + TaskBase + command string + logCmdOutput bool +} + +func (task *BatsTask) Hash() string { + return hash(task.canary + task.command) +} + +func (task *BatsTask) Run(ctx context.Context) (bool, error) { + cmd := exec.CommandContext(ctx, "bash", "-c", task.command) + out, err := cmd.CombinedOutput() + + if err != nil { + task.logger.With("canary", task.canary).Errorf("command failed %s %v %s", task.command, err, out) + return false, fmt.Errorf(" %v %v", err, out) + } else { + if task.logCmdOutput { + fmt.Printf("%s\n", out) + } + task.logger.With("canary", task.canary).Infof("command finished %s", task.command) + } + return true, nil +} + +func (task *BatsTask) String() string { + return task.command +} diff --git a/pkg/loadtester/server.go b/pkg/loadtester/server.go index 533c5554..c5a34aae 100644 --- a/pkg/loadtester/server.go +++ b/pkg/loadtester/server.go @@ -44,6 +44,27 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge if !ok { typ = TaskTypeShell } + + // run bats command (blocking task) + if typ == TaskTypeBats { + bats := BatsTask{ + command: payload.Metadata["cmd"], + logCmdOutput: taskRunner.logCmdOutput, + } + + ctx, cancel := context.WithTimeout(context.Background(), taskRunner.timeout) + defer cancel() + + ok, err := bats.Run(ctx) + if !ok { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + } + + w.WriteHeader(http.StatusOK) + return + } + taskFactory, ok := GetTaskFactory(typ) if !ok { w.WriteHeader(http.StatusBadRequest) diff --git a/pkg/loadtester/task.go b/pkg/loadtester/task.go index 2e30228a..395b34a9 100644 --- a/pkg/loadtester/task.go +++ b/pkg/loadtester/task.go @@ -24,6 +24,7 @@ type TaskBase struct { func (task *TaskBase) Canary() string { return task.canary } + func hash(str string) string { fnvHash := fnv.New32() fnvBytes := fnvHash.Sum([]byte(str))