Skip to content

Commit

Permalink
Merge pull request #449 from ta924/loadtesterRollbackSupport
Browse files Browse the repository at this point in the history
Add support for rollback gating in tester API
  • Loading branch information
stefanprodan authored Feb 19, 2020
2 parents 7f9cc30 + 34ed690 commit 91ef812
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 3 deletions.
21 changes: 18 additions & 3 deletions docs/gitbook/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ Spec:
some: "message"
- name: "rollback gate"
type: rollback
url: http://flagger-loadtester.test/gate/halt
url: http://flagger-loadtester.test/rollback/check
- name: "send to Slack"
type: event
url: http://event-recevier.notifications/slack
Expand Down Expand Up @@ -908,14 +908,29 @@ While the promotion is paused, Flagger will continue to run the metrics checks a
url: http://flagger-loadtester.test/gate/halt
```

The `rollback` hook type can be used to manually rollback the canary promotion.
The `rollback` hook type can be used to manually rollback the canary promotion. As with gating, rollbacks can be driven
with Flagger's tester API by setting the rollback URL to `/rollback/check`

```yaml
canaryAnalysis:
webhooks:
- name: "rollback"
type: rollback
url: http://flagger-loadtester.test/gate/halt
url: http://flagger-loadtester.test/rollback/check
```

By default rollback is closed, you can rollback a canary rollout with:

```bash
kubectl -n test exec -it flagger-loadtester-xxxx-xxxx sh
curl -d '{"name": "podinfo","namespace":"test"}' http://localhost:8080/rollback/open
```

You can close the rollback with:

```bash
curl -d '{"name": "podinfo","namespace":"test"}' http://localhost:8080/rollback/close
``
If you have notifications enabled, Flagger will post a message to Slack or MS Teams if a canary promotion is waiting for approval.
79 changes: 79 additions & 0 deletions pkg/loadtester/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,85 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
logger.Infof("%s gate closed", canaryName)
})

mux.HandleFunc("/rollback/check", func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
logger.Error("reading the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}
defer r.Body.Close()

canary := &flaggerv1.CanaryWebhookPayload{}
err = json.Unmarshal(body, canary)
if err != nil {
logger.Error("decoding the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}

canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
approved := gate.isOpen(canaryName)
if approved {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Approved"))
} else {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("Forbidden"))
}

logger.Infof("%s rollback check: approved %v", canaryName, approved)
})
mux.HandleFunc("/rollback/open", func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
logger.Error("reading the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}
defer r.Body.Close()

canary := &flaggerv1.CanaryWebhookPayload{}
err = json.Unmarshal(body, canary)
if err != nil {
logger.Error("decoding the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}

canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
gate.open(canaryName)

w.WriteHeader(http.StatusAccepted)

logger.Infof("%s rollback opened", canaryName)
})
mux.HandleFunc("/rollback/close", func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
logger.Error("reading the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}
defer r.Body.Close()

canary := &flaggerv1.CanaryWebhookPayload{}
err = json.Unmarshal(body, canary)
if err != nil {
logger.Error("decoding the request body failed", zap.Error(err))
w.WriteHeader(http.StatusBadRequest)
return
}


canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
gate.close(canaryName)

w.WriteHeader(http.StatusAccepted)

logger.Infof("%s rollback closed", canaryName)
})

mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
Expand Down

0 comments on commit 91ef812

Please sign in to comment.