hashicorp/faas-nomad

View on GitHub
handlers/reader.go

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
package handlers

import (
    "encoding/json"
    "log"
    "net/http"
    "strings"

    "github.com/hashicorp/faas-nomad/metrics"
    "github.com/hashicorp/faas-nomad/nomad"
    hclog "github.com/hashicorp/go-hclog"
    "github.com/hashicorp/nomad/api"
    "github.com/openfaas/faas/gateway/requests"
)

// MakeReader implements the OpenFaaS reader handler
func MakeReader(client nomad.Job, logger hclog.Logger, stats metrics.StatsD) http.HandlerFunc {
    log := logger.Named("reader_handler")

    return func(w http.ResponseWriter, r *http.Request) {
        // Not sure if prefix is the right option
        options := &api.QueryOptions{}
        options.Prefix = nomad.JobPrefix

        log.Info("List functions called")
        stats.Incr("reader.called", nil, 1)

        jobs, _, err := client.List(options)
        if err != nil {
            writeError(w, err)

            log.Error("Error getting functions", "error", err)
            stats.Incr("reader.error.getjobs", nil, 1)
            return
        }

        functions, err := getFunctions(client, jobs)
        if err != nil {
            writeError(w, err)

            log.Error("Error getting functions", "error", err.Error())
            stats.Incr("reader.error.getfunctions", nil, 1)
            return
        }

        writeFunctionResponse(w, functions)

        log.Info("List functions success")
        stats.Incr("reader.success", nil, 1)
    }
}

func getFunctions(client nomad.Job, jobs []*api.JobListStub) ([]requests.Function, error) {
    functions := make([]requests.Function, 0)
    for _, j := range jobs {

        if j.Status == "running" || j.Status == "pending" {
            job, _, err := client.Info(j.ID, nil)
            if err != nil {
                return functions, err
            }

            functions = append(functions, requests.Function{
                Name:            sanitiseJobName(job),
                Image:           job.TaskGroups[0].Tasks[0].Config["image"].(string),
                Replicas:        uint64(*job.TaskGroups[0].Count),
                InvocationCount: 0,
                Labels:          parseLabels(job.TaskGroups[0].Tasks[0].Config["labels"].([]interface{})),
                Annotations:     &job.Meta,
            })
        }
    }

    return functions, nil
}

func parseLabels(labels []interface{}) *map[string]string {
    newLabels := map[string]string{}
    if len(labels) > 0 {
        for _, l := range labels {
            for k, v := range l.(map[string]interface{}) {
                newLabels[k] = v.(string)
            }
        }
    }
    return &newLabels
}

func sanitiseJobName(job *api.Job) string {
    return strings.Replace(job.TaskGroups[0].Tasks[0].Name, nomad.JobPrefix, "", -1)
}

func writeFunctionResponse(w http.ResponseWriter, fs []requests.Function) {
    functionBytes, _ := json.Marshal(fs)
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(200)
    w.Write(functionBytes)
}
func writeError(w http.ResponseWriter, err error) {
    w.WriteHeader(http.StatusInternalServerError)
    w.Write([]byte(err.Error()))
    log.Println(err)
    return
}