func GetLocks(w http.ResponseWriter, _ *http.Request, sps []state.Provider) {
	allLocks := make(map[string]state.LockInfo)
	for _, sp := range sps {
		locks, err := sp.GetLocks()
		if err != nil {
			JSONError(w, "Failed to get locks on a provider", err)
			return
		}
		for k, v := range locks {
			allLocks[k] = v
		}
	}
	j, err := json.Marshal(allLocks)
	if err != nil {
		JSONError(w, "Failed to marshal locks", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
GetLocks returns information on locked States
@Summary Get locked states information
@Description Returns information on locked States
@ID get-locks
@Produce  json
@Success 200 {string} string	"ok"
@Router /locks [get]
package api
import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"github.com/camptocamp/terraboard/auth"
	"github.com/camptocamp/terraboard/compare"
	"github.com/camptocamp/terraboard/db"
	"github.com/camptocamp/terraboard/state"
	"github.com/gorilla/mux"
	log "github.com/sirupsen/logrus"
	"gorm.io/datatypes"
)
type planPayload struct {
	Lineage   string         `json:"lineage"`
	TFVersion string         `json:"terraform_version"`
	GitRemote string         `json:"git_remote"`
	GitCommit string         `json:"git_commit"`
	CiURL     string         `json:"ci_url"`
	Source    string         `json:"source"`
	ExitCode  int            `json:"exit_code"`
	PlanJSON  datatypes.JSON `json:"plan_json" swaggertype:"object"`
}
var _ *planPayload = nil  
func JSONError(w http.ResponseWriter, message string, err error) {
	errObj := make(map[string]string)
	errObj["error"] = message
	errObj["details"] = fmt.Sprintf("%v", err)
	j, _ := json.Marshal(errObj)
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
func ListTerraformVersionsWithCount(w http.ResponseWriter, r *http.Request, d *db.Database) {
	query := r.URL.Query()
	versions, _ := d.ListTerraformVersionsWithCount(query)
	j, err := json.Marshal(versions)
	if err != nil {
		JSONError(w, "Failed to marshal states", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
func ListStateStats(w http.ResponseWriter, r *http.Request, d *db.Database) {
	query := r.URL.Query()
	states, page, total := d.ListStateStats(query)
	response := make(map[string]interface{})
	response["states"] = states
	response["page"] = page
	response["total"] = total
	j, err := json.Marshal(response)
	if err != nil {
		JSONError(w, "Failed to marshal states", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
func GetState(w http.ResponseWriter, r *http.Request, d *db.Database) {
	params := mux.Vars(r)
	versionID := r.URL.Query().Get("versionid")
	var err error
	if versionID == "" {
		versionID, err = d.DefaultVersion(params["lineage"])
		if err != nil {
			JSONError(w, "Failed to retrieve default version", err)
			return
		}
	}
	state := d.GetState(params["lineage"], versionID)
	j, err := json.Marshal(state)
	if err != nil {
		JSONError(w, "Failed to marshal state", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
func GetLineageActivity(w http.ResponseWriter, r *http.Request, d *db.Database) {
	params := mux.Vars(r)
	activity := d.GetLineageActivity(params["lineage"])
	j, err := json.Marshal(activity)
	if err != nil {
		JSONError(w, "Failed to marshal state activity", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}
func StateCompare(w http.ResponseWriter, r *http.Request, d *db.Database) {
	params := mux.Vars(r)
	query := r.URL.Query()
	fromVersion := query.Get("from")
	toVersion := query.Get("to")
	from := d.GetState(params["lineage"], fromVersion)
	to := d.GetState(params["lineage"], toVersion)
	compare, err := compare.Compare(from, to)
	if err != nil {
		JSONError(w, "Failed to compare state versions", err)
		return
	}
	j, err := json.Marshal(compare)
	if err != nil {
		JSONError(w, "Failed to marshal state compare", err)
		return
	}
	if _, err := io.WriteString(w, string(j)); err != nil {
		log.Error(err.Error())
	}
}