Skip to content
Snippets Groups Projects
alerthandler.go 2.05 KiB
package handlers

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/alexellis/faas/gateway/requests"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func scaleService(req requests.PrometheusAlert, c *client.Client) error {
	var err error
	//Todo: convert to loop / handler.
	serviceName := req.Alerts[0].Labels.FunctionName
	service, _, inspectErr := c.ServiceInspectWithRaw(context.Background(), serviceName)
	if inspectErr == nil {
		var replicas uint64

		if req.Status == "firing" {
			if *service.Spec.Mode.Replicated.Replicas < 20 {
				replicas = *service.Spec.Mode.Replicated.Replicas + uint64(5)
			} else {
				return err
			}
		} else { // Resolved event.
			// Previously decremented by 5, but event only fires once, so set to 1/1.
			if *service.Spec.Mode.Replicated.Replicas > 1 {
				// replicas = *service.Spec.Mode.Replicated.Replicas - uint64(5)
				// if replicas < 1 {
				// replicas = 1
				// }
				// return nil

				replicas = 1
			} else {
				return nil
			}
		}

		log.Printf("Scaling %s to %d replicas.\n", serviceName, replicas)

		service.Spec.Mode.Replicated.Replicas = &replicas
		updateOpts := types.ServiceUpdateOptions{}
		updateOpts.RegistryAuthFrom = types.RegistryAuthFromSpec

		response, updateErr := c.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, updateOpts)
		if updateErr != nil {
			err = updateErr
		}
		log.Println(response)

	} else {
		err = inspectErr
	}

	return err
}

func MakeAlertHandler(c *client.Client) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println("Alert received.")
		body, readErr := ioutil.ReadAll(r.Body)
		if readErr != nil {
			log.Println(readErr)
			return
		}

		var req requests.PrometheusAlert
		err := json.Unmarshal(body, &req)
		if err != nil {
			log.Println(err)
			return
		}

		if len(req.Alerts) > 0 {
			err := scaleService(req, c)
			if err != nil {
				log.Println(err)
				w.WriteHeader(http.StatusInternalServerError)
			} else {
				w.WriteHeader(http.StatusOK)
			}
		}
	}
}