#60: Created API endpoint to hotload apps from directory

This commit is contained in:
frikky
2020-06-15 12:02:52 +02:00
21 changed files with 1587 additions and 577 deletions
+159 -6
View File
@@ -9,6 +9,7 @@ import (
"encoding/hex"
"encoding/json"
"errors"
"path/filepath"
"fmt"
"io"
@@ -36,7 +37,9 @@ import (
"github.com/google/go-github/v28/github"
"golang.org/x/oauth2"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/storage/memory"
@@ -238,7 +241,7 @@ type AppInfo struct {
type ScheduleOld struct {
Id string `json:"id" datastore:"id"`
Seconds int `json:"seconds" datastore:"seconds"`
WorkflowId string `json:"workflow_id datastore:"workflow_id", `
WorkflowId string `json:"workflow_id" datastore:"workflow_id", `
Argument string `json:"argument" datastore:"argument"`
AppInfo AppInfo `json:"appinfo" datastore:"appinfo,noindex"`
Finished bool `json:"finished" finished:"id"`
@@ -1803,6 +1806,49 @@ func getUserCount() (int, error) {
return count, nil
}
func handleGetSchedules(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request)
if cors {
return
}
user, err := handleApiAuthentication(resp, request)
if err != nil {
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
}
if user.Role != "admin" {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
return
}
ctx := context.Background()
schedules, err := getAllSchedules(ctx)
if err != nil {
log.Printf("Failed getting schedules: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Couldn't get schedules"}`))
return
}
newjson, err := json.Marshal(schedules)
if err != nil {
log.Printf("Failed unmarshal: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed unpacking environments"}`)))
return
}
//log.Printf("Existing environments: %s", string(newjson))
resp.WriteHeader(200)
resp.Write(newjson)
}
func handleGetEnvironments(resp http.ResponseWriter, request *http.Request) {
cors := handleCors(resp, request)
if cors {
@@ -1897,10 +1943,12 @@ func handleGetUsers(resp http.ResponseWriter, request *http.Request) {
}
func checkAdminLogin(resp http.ResponseWriter, request *http.Request) {
log.Printf("HELLO?")
cors := handleCors(resp, request)
if cors {
return
}
log.Printf("HELLO2?")
count, err := getUserCount()
if err != nil {
@@ -2635,6 +2683,21 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
return
}
user, err := handleApiAuthentication(resp, request)
if err != nil {
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
}
// FIXME: IAM - Get workflow and check owner
if user.Role != "admin" {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Admin required"}`))
return
}
location := strings.Split(request.URL.String(), "/")
var workflowId string
@@ -2655,7 +2718,7 @@ func handleDeleteSchedule(resp http.ResponseWriter, request *http.Request) {
}
ctx := context.Background()
err := DeleteKey(ctx, "schedules", workflowId)
err = DeleteKey(ctx, "schedules", workflowId)
if err != nil {
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "message": "Can't delete"}`))
@@ -4648,7 +4711,7 @@ func handleDeleteOutlookSub(resp http.ResponseWriter, request *http.Request) {
ctx := context.Background()
workflow, err := getWorkflow(ctx, workflowId)
if err != nil {
log.Printf("Failed getting the workflow locally: %s", err)
log.Printf("Failed getting the workflow locally (delete outlook): %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
@@ -4782,7 +4845,7 @@ func createOutlookSub(resp http.ResponseWriter, request *http.Request) {
ctx := context.Background()
workflow, err := getWorkflow(ctx, workflowId)
if err != nil {
log.Printf("Failed getting the workflow locally: %s", err)
log.Printf("Failed getting the workflow locally (outlook sub): %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
@@ -5729,6 +5792,86 @@ func healthCheckHandler(resp http.ResponseWriter, request *http.Request) {
fmt.Fprint(resp, "OK")
}
// Creates osfs from folderpath with a basepath as directory base
func createFs(basepath, pathname string) (billy.Filesystem, error) {
fs := osfs.New("")
err := filepath.Walk(pathname,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.Contains(path, ".git") {
return nil
}
fullpath := fmt.Sprintf("%s%s", basepath, path)
switch mode := info.Mode(); {
case mode.IsDir():
err = fs.MkdirAll(fullpath, 0644)
if err != nil {
log.Printf("Failed making folder: %s", err)
}
case mode.IsRegular():
srcData, err := ioutil.ReadFile(path)
if err != nil {
log.Printf("Src error: %s", err)
return err
}
//if strings.Contains(path, "yaml") {
// log.Printf("PATH: %s -> %s", path, fullpath)
// //log.Printf("DATA: %s", string(srcData))
//}
dst, err := fs.Create(fullpath)
if err != nil {
log.Printf("Dst error: %s", err)
return err
}
_, err = dst.Write(srcData)
if err != nil {
log.Printf("Dst write error: %s", err)
return err
}
}
return nil
})
return fs, err
}
// Hotloads new apps from a folder
// FIXME: Not finished
func handleAppHotload(location string) error {
basepath := "base"
fs, err := createFs(basepath, location)
if err != nil {
log.Printf("Failed making files and stuff: %s", err)
return err
} else {
log.Printf("Hotloading from %s finished", location)
}
dir, err := fs.ReadDir(basepath)
if err != nil {
log.Printf("Failed reading folder: %s", err)
return err
}
err = iterateAppGithubFolders(fs, dir, "", "")
if err != nil {
log.Printf("Err: %s", err)
return err
}
return nil
}
// Handles configuration items during Shuffle startup
func runInit(ctx context.Context) {
// Setting stats for backend starts (failure count as well)
err := increaseStatisticsField(ctx, "backend_executions", "", 1)
@@ -5765,7 +5908,7 @@ func runInit(ctx context.Context) {
_, _, err := handleExecution(schedule.WorkflowId, Workflow{}, request)
if err != nil {
log.Printf("Failed to execute: %s", err)
log.Printf("Failed to execute %s: %s", schedule.WorkflowId, err)
}
}
@@ -5822,10 +5965,16 @@ func runInit(ctx context.Context) {
// FIXME: Get all the apps?
iterateAppGithubFolders(fs, dir, "", "")
// Hotloads locally
location := os.Getenv("APP_HOTLOAD_FOLDER")
if len(location) != 0 {
handleAppHotload(location)
}
}
log.Printf("Downloading OpenAPI data for search - EXTRA APPS")
apis := "https://github.com/frikky/OpenAPI-security-definitions"
apis := "https://github.com/frikky/security-openapis"
// THis gets memory problems hahah
//apis := "https://github.com/APIs-guru/openapi-directory"
@@ -5896,7 +6045,9 @@ func init() {
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
// App specific
r.HandleFunc("/api/v1/apps/run_hotload", handleAppHotloadRequest).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/apps/get_existing", loadSpecificApps).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/download_remote", loadSpecificApps).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/validate", validateAppInput).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/{appId}", deleteWorkflowApp).Methods("DELETE", "OPTIONS")
r.HandleFunc("/api/v1/apps/{appId}/config", getWorkflowAppConfig).Methods("GET", "OPTIONS")
@@ -5914,6 +6065,8 @@ func init() {
/* Everything below here increases the counters*/
r.HandleFunc("/api/v1/workflows", getWorkflows).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/workflows", setNewWorkflow).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/workflows/schedules", handleGetSchedules).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/workflows/download_remote", loadSpecificWorkflows).Methods("POST", "OPTIONS")
//r.HandleFunc("/api/v1/workflows/{key}/execute_fs", executeWorkflowFS)
r.HandleFunc("/api/v1/workflows/{key}/execute", executeWorkflow).Methods("GET", "POST", "OPTIONS")
r.HandleFunc("/api/v1/workflows/{key}/schedule", scheduleWorkflow).Methods("POST", "OPTIONS")