cloudfoundry/stratos

View on GitHub
src/jetstream/plugins/analysis/container/run.go

Summary

Maintainability
C
7 hrs
Test Coverage
package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "path/filepath"

    "github.com/labstack/echo/v4"
    log "github.com/sirupsen/logrus"
)

const idHeaderName = "X-Stratos-Analaysis-ID"

func (a *Analyzer) run(ec echo.Context) error {
    err := a.doRun(ec)
    if err != nil {
        log.Error(err)
    }
    return err
}

func (a *Analyzer) doRun(ec echo.Context) error {

    log.Debug("Run analyzer!")

    engine := ec.Param("analyzer")
    if len(engine) == 0 {
        log.Warn("No analyzer")
        return errors.New("No analyzer specified")
    }

    // ID is username/endpoint/id
    id := ec.Request().Header.Get(idHeaderName)
    if len(id) == 0 {
        return errors.New("Mising ID header")
    }

    folder := filepath.Join(a.reportsDir, id)
    if os.MkdirAll(folder, os.ModePerm) != nil {
        return errors.New("Could not create folder for analysis report")
    }

    tempFiles := make([]string, 0)
    reader, err := ec.Request().MultipartReader()
    if err != nil {
        log.Error("Could not parse request")
        log.Error(err)
        return errors.New("Failed to parse request payload")
    }

    job := AnalysisJob{}
    params := kubeAnalyzerConfig{}

    for {
        part, err := reader.NextPart()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Error("Unexpected error when retrieving a part of the message")
            return errors.New("Unexpected error when retrieving a part of the message")
        }
        defer part.Close()
        fileBytes, err := ioutil.ReadAll(part)
        if err != nil {
            log.Error("Failed to read content of the part")
            return errors.New("Failed to read content of the part")
        }
        filename := part.Header.Get("Content-ID")

        // Decide what to do with the part
        switch filename {
        case "job":
            if err = json.Unmarshal(fileBytes, &job); err != nil {
                return fmt.Errorf("Can not parse Job: %v", err)
            }
        case "body":
            if err = json.Unmarshal(fileBytes, &params); err != nil {
                return fmt.Errorf("Can not parse parameters: %v", err)
            }
            job.Config = &params
        default:
            fullpath := filepath.Join(folder, filename)
            if err = ioutil.WriteFile(fullpath, fileBytes, os.ModePerm); err != nil {
                log.Error("Could not write data for: %s", filename)
                return fmt.Errorf("Could not write file data for: %s", filename)
            }
            if filename == "kubeconfig" {
                job.KubeConfigPath = fullpath
            }
            tempFiles = append(tempFiles, fullpath)
        }
    }

    if len(job.ID) == 0 {
        return errors.New("Invalid Job metadata supplied")
    }

    job.Folder = folder
    job.TempFiles = tempFiles

    // Store the job so we track which jobs are running
    a.jobs[job.ID] = &job

    job.Status = "running"

    switch engine {
    case "popeye":
        err = runPopeye(&job)
    case "kube-score":
        err = runKubeScore(&job)
    // case "sonobuoy":
    //     runSonobuoy(dbStore, file, folder, report, requestBody)
    default:
        job.Status = "error"
        return fmt.Errorf("Unkown analyzer: %s", engine)
    }

    if err != nil {
        job.Status = "error"
        log.Error("Error running analyzer: %s", err)
    }

    return ec.JSON(http.StatusOK, job)
}