Added Edgeapps Options Feature
parent
445bc41d0e
commit
ca7f4af7fe
|
@ -6,7 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
|
|
||||||
"github.com/edgebox-iot/edgeboxctl/internal/system"
|
"github.com/edgebox-iot/edgeboxctl/internal/system"
|
||||||
|
@ -23,6 +23,8 @@ type EdgeApp struct {
|
||||||
InternetAccessible bool `json:"internet_accessible"`
|
InternetAccessible bool `json:"internet_accessible"`
|
||||||
NetworkURL string `json:"network_url"`
|
NetworkURL string `json:"network_url"`
|
||||||
InternetURL string `json:"internet_url"`
|
InternetURL string `json:"internet_url"`
|
||||||
|
Options []EdgeAppOption `json:"options"`
|
||||||
|
NeedsConfig bool `json:"needs_config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaybeEdgeApp : Boolean flag for validation of edgeapp existance
|
// MaybeEdgeApp : Boolean flag for validation of edgeapp existance
|
||||||
|
@ -43,8 +45,20 @@ type EdgeAppService struct {
|
||||||
IsRunning bool `json:"is_running"`
|
IsRunning bool `json:"is_running"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EdgeAppOption struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
DefaultValue string `json:"default_value"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
IsSecret bool `json:"is_secret"`
|
||||||
|
IsInstallLocked bool `json:"is_install_locked"`
|
||||||
|
}
|
||||||
|
|
||||||
const configFilename = "/edgebox-compose.yml"
|
const configFilename = "/edgebox-compose.yml"
|
||||||
const envFilename = "/edgebox.env"
|
const envFilename = "/edgebox.env"
|
||||||
|
const optionsTemplateFilename = "/edgeapp.template.env"
|
||||||
|
const optionsEnvFilename = "/edgeapp.env"
|
||||||
const runnableFilename = "/.run"
|
const runnableFilename = "/.run"
|
||||||
const myEdgeAppServiceEnvFilename = "/myedgeapp.env"
|
const myEdgeAppServiceEnvFilename = "/myedgeapp.env"
|
||||||
const defaultContainerOperationSleepTime time.Duration = time.Second * 10
|
const defaultContainerOperationSleepTime time.Duration = time.Second * 10
|
||||||
|
@ -63,6 +77,7 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||||
|
|
||||||
edgeAppName := ID
|
edgeAppName := ID
|
||||||
edgeAppDescription := ""
|
edgeAppDescription := ""
|
||||||
|
edgeAppOptions := []EdgeAppOption{}
|
||||||
|
|
||||||
edgeAppEnv, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + envFilename)
|
edgeAppEnv, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + envFilename)
|
||||||
|
|
||||||
|
@ -77,6 +92,103 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needsConfig := false
|
||||||
|
hasFilledOptions := false
|
||||||
|
edgeAppOptionsTemplate, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + optionsTemplateFilename)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error loading options template file for edgeapp " + edgeAppName)
|
||||||
|
} else {
|
||||||
|
// Try to read the edgeAppOptionsEnv file
|
||||||
|
edgeAppOptionsEnv, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + optionsEnvFilename)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error loading options env file for edgeapp " + edgeAppName)
|
||||||
|
} else {
|
||||||
|
hasFilledOptions = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range edgeAppOptionsTemplate {
|
||||||
|
|
||||||
|
optionFilledValue := ""
|
||||||
|
if hasFilledOptions {
|
||||||
|
// Check if key exists in edgeAppOptionsEnv
|
||||||
|
optionFilledValue = edgeAppOptionsEnv[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
format := ""
|
||||||
|
defaultValue := ""
|
||||||
|
description := ""
|
||||||
|
installLocked := false
|
||||||
|
|
||||||
|
// Parse value to separate by | and get the format, installLocked, description and default value
|
||||||
|
// Format is the first element
|
||||||
|
// InstallLocked is the second element
|
||||||
|
// Description is the third element
|
||||||
|
// Default value is the fourth element
|
||||||
|
|
||||||
|
valueSlices := strings.Split(value, "|")
|
||||||
|
if len(valueSlices) > 0 {
|
||||||
|
format = valueSlices[0]
|
||||||
|
}
|
||||||
|
if len(valueSlices) > 1 {
|
||||||
|
installLocked = valueSlices[1] == "true"
|
||||||
|
}
|
||||||
|
if len(valueSlices) > 2 {
|
||||||
|
description = valueSlices[2]
|
||||||
|
}
|
||||||
|
if len(valueSlices) > 3 {
|
||||||
|
defaultValue = valueSlices[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
// // If value contains ">|", then get everything that is to the right of it as the description
|
||||||
|
// // and get everything between "<>" as the format
|
||||||
|
// if strings.Contains(value, ">|") {
|
||||||
|
// description = strings.Split(value, ">|")[1]
|
||||||
|
// // Check if description has default value. That would be everything that is to the right of the last "|"
|
||||||
|
// if strings.Contains(description, "|") {
|
||||||
|
// defaultValue = strings.Split(description, "|")[1]
|
||||||
|
// description = strings.Split(description, "|")[0]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// value = strings.Split(value, ">|")[0]
|
||||||
|
// // Remove the initial < from value
|
||||||
|
// value = strings.TrimPrefix(value, "<")
|
||||||
|
// } else {
|
||||||
|
// // Trim initial < and final > from value
|
||||||
|
// value = strings.TrimPrefix(value, "<")
|
||||||
|
// value = strings.TrimSuffix(value, ">")
|
||||||
|
// }
|
||||||
|
|
||||||
|
isSecret := false
|
||||||
|
|
||||||
|
// Check if the lowercased key string contains the letters "pass", "secret", "key"
|
||||||
|
lowercaseKey := strings.ToLower(key)
|
||||||
|
// check if lowercaseInput contains "pass", "key", or "secret", or "token"
|
||||||
|
if strings.Contains(lowercaseKey, "pass") ||
|
||||||
|
strings.Contains(lowercaseKey, "key") ||
|
||||||
|
strings.Contains(lowercaseKey, "secret") ||
|
||||||
|
strings.Contains(lowercaseKey, "token") {
|
||||||
|
isSecret = true
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOption := EdgeAppOption{
|
||||||
|
Key: key,
|
||||||
|
Value: optionFilledValue,
|
||||||
|
DefaultValue: defaultValue,
|
||||||
|
Description: description,
|
||||||
|
Format: format,
|
||||||
|
IsSecret: isSecret,
|
||||||
|
IsInstallLocked: installLocked,
|
||||||
|
}
|
||||||
|
edgeAppOptions = append(edgeAppOptions, currentOption)
|
||||||
|
|
||||||
|
if optionFilledValue == "" {
|
||||||
|
needsConfig = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
edgeAppInternetAccessible := false
|
edgeAppInternetAccessible := false
|
||||||
edgeAppInternetURL := ""
|
edgeAppInternetURL := ""
|
||||||
|
|
||||||
|
@ -100,6 +212,8 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||||
InternetAccessible: edgeAppInternetAccessible,
|
InternetAccessible: edgeAppInternetAccessible,
|
||||||
NetworkURL: ID + "." + system.GetHostname() + ".local",
|
NetworkURL: ID + "." + system.GetHostname() + ".local",
|
||||||
InternetURL: edgeAppInternetURL,
|
InternetURL: edgeAppInternetURL,
|
||||||
|
Options: edgeAppOptions,
|
||||||
|
NeedsConfig: needsConfig,
|
||||||
},
|
},
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,29 @@ func SetupCloudOptions() {
|
||||||
utils.Exec("/", "rm", []string{cloudEnvFileLocationPath})
|
utils.Exec("/", "rm", []string{cloudEnvFileLocationPath})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StartSystemLogger() {
|
||||||
|
fmt.Println("Starting system logger")
|
||||||
|
loggerPath := utils.GetPath(utils.LoggerPath)
|
||||||
|
utils.Exec(loggerPath, "make", []string{"start"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSystemLoggerServices: Updates the services.txt file with the services that are currently running
|
||||||
|
func UpdateSystemLoggerServices(services []string) {
|
||||||
|
fmt.Println("Updating system logger services:")
|
||||||
|
fmt.Println(services)
|
||||||
|
loggerPath := utils.GetPath(utils.LoggerPath)
|
||||||
|
|
||||||
|
utils.Exec(loggerPath, "bash", []string{"-c", "rm services.txt && touch services.txt"})
|
||||||
|
|
||||||
|
for _, service := range services {
|
||||||
|
fmt.Println("Adding " + service + " to services.txt")
|
||||||
|
utils.Exec(loggerPath, "bash", []string{"-c", "echo " + service + " >> services.txt"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add empty line at the end of file (best practice)
|
||||||
|
utils.Exec(loggerPath, "bash", []string{"-c", "echo '' >> services.txt"})
|
||||||
|
}
|
||||||
|
|
||||||
// StartWs: Starts the webserver service for Edgeapps
|
// StartWs: Starts the webserver service for Edgeapps
|
||||||
func StartWs() {
|
func StartWs() {
|
||||||
wsPath := utils.GetPath(utils.WsPath)
|
wsPath := utils.GetPath(utils.WsPath)
|
||||||
|
|
|
@ -33,6 +33,12 @@ type Task struct {
|
||||||
Updated string `json:"updated"`
|
Updated string `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TaskOption: Struct for Task Options (kv pair)
|
||||||
|
type TaskOption struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
type taskSetupTunnelArgs struct {
|
type taskSetupTunnelArgs struct {
|
||||||
DomainName string `json:"domain_name"`
|
DomainName string `json:"domain_name"`
|
||||||
}
|
}
|
||||||
|
@ -53,6 +59,12 @@ type taskStopEdgeAppArgs struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type taskSetEdgeAppOptionsArgs struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
// Options should be an array of "key":"value" pairs
|
||||||
|
Options []TaskOption `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
type taskEnableOnlineArgs struct {
|
type taskEnableOnlineArgs struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
InternetURL string `json:"internet_url"`
|
InternetURL string `json:"internet_url"`
|
||||||
|
@ -262,6 +274,19 @@ func ExecuteTask(task Task) Task {
|
||||||
task.Result = sql.NullString{String: taskResult, Valid: true}
|
task.Result = sql.NullString{String: taskResult, Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "set_edgeapp_options":
|
||||||
|
|
||||||
|
log.Println("Setting EdgeApp Options...")
|
||||||
|
var args taskSetEdgeAppOptionsArgs
|
||||||
|
// {"id":"podgrab","options":{"PODGRAB_PASSWORD":"fumarmata"}}
|
||||||
|
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error reading arguments of set_edgeapp_options task: %s", err)
|
||||||
|
} else {
|
||||||
|
taskResult := taskSetEdgeAppOptions(args)
|
||||||
|
task.Result = sql.NullString{String: taskResult, Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
case "enable_online":
|
case "enable_online":
|
||||||
|
|
||||||
log.Println("Enabling online access to EdgeApp...")
|
log.Println("Enabling online access to EdgeApp...")
|
||||||
|
@ -376,7 +401,7 @@ func ExecuteSchedules(tick int) {
|
||||||
log.Println(taskGetStorageDevices())
|
log.Println(taskGetStorageDevices())
|
||||||
taskStartWs()
|
taskStartWs()
|
||||||
log.Println(taskGetEdgeApps())
|
log.Println(taskGetEdgeApps())
|
||||||
|
taskUpdateSystemLoggerServices()
|
||||||
}
|
}
|
||||||
|
|
||||||
if tick%5 == 0 {
|
if tick%5 == 0 {
|
||||||
|
@ -388,6 +413,7 @@ func ExecuteSchedules(tick int) {
|
||||||
if tick%30 == 0 {
|
if tick%30 == 0 {
|
||||||
// Executing every 30 ticks
|
// Executing every 30 ticks
|
||||||
log.Println(taskGetEdgeApps())
|
log.Println(taskGetEdgeApps())
|
||||||
|
taskUpdateSystemLoggerServices()
|
||||||
// RESET SOME VARIABLES HERE IF NEEDED, SINCE SYSTEM IS UNBLOCKED
|
// RESET SOME VARIABLES HERE IF NEEDED, SINCE SYSTEM IS UNBLOCKED
|
||||||
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
utils.WriteOption("BACKUP_IS_WORKING", "0")
|
||||||
|
|
||||||
|
@ -909,6 +935,57 @@ func taskStopEdgeApp(args taskStopEdgeAppArgs) string {
|
||||||
return string(resultJSON)
|
return string(resultJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func taskSetEdgeAppOptions(args taskSetEdgeAppOptionsArgs) string {
|
||||||
|
// Id is the edgeapp id
|
||||||
|
appID := args.ID
|
||||||
|
|
||||||
|
|
||||||
|
// Open the file to write the options,
|
||||||
|
// it is an env file in /home/system/components/apps/<app_id>/edgeapp.env
|
||||||
|
|
||||||
|
// Get the path to the edgeapp.env file
|
||||||
|
edgeappEnvPath := "/home/system/components/apps/" + appID + "/edgeapp.env"
|
||||||
|
|
||||||
|
// If the file does not exist, create it
|
||||||
|
if _, err := os.Stat(edgeappEnvPath); os.IsNotExist(err) {
|
||||||
|
// Create the file
|
||||||
|
_, err := os.Create(edgeappEnvPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error creating edgeapp.env file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is an env file, so we can use go-dotenv to write the options
|
||||||
|
// Open the file
|
||||||
|
edgeappEnvFile, err := os.OpenFile(edgeappEnvPath, os.O_WRONLY, 0600)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error opening edgeapp.env file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the options to the file
|
||||||
|
for _, value := range args.Options {
|
||||||
|
// Write the option to the file
|
||||||
|
_, err := edgeappEnvFile.WriteString(value.Key + "=" + value.Value + "\n")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error writing option to edgeapp.env file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file
|
||||||
|
err = edgeappEnvFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error closing edgeapp.env file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := edgeapps.GetEdgeAppStatus(appID)
|
||||||
|
resultJSON, _ := json.Marshal(result)
|
||||||
|
|
||||||
|
system.StartWs()
|
||||||
|
taskGetEdgeApps() // This task will imediatelly update the entry in the api database.
|
||||||
|
|
||||||
|
return string(resultJSON)
|
||||||
|
}
|
||||||
|
|
||||||
func taskEnableOnline(args taskEnableOnlineArgs) string {
|
func taskEnableOnline(args taskEnableOnlineArgs) string {
|
||||||
fmt.Println("Executing taskEnableOnline for " + args.ID)
|
fmt.Println("Executing taskEnableOnline for " + args.ID)
|
||||||
|
|
||||||
|
@ -961,6 +1038,35 @@ func taskSetReleaseVersion() string {
|
||||||
return diagnostics.Version
|
return diagnostics.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func taskUpdateSystemLoggerServices() string {
|
||||||
|
fmt.Println("Executing taskUpdateSystemLoggerServices")
|
||||||
|
// The input is an array of strings
|
||||||
|
// Each string is a service name to be logged
|
||||||
|
var input []string
|
||||||
|
|
||||||
|
// Get the services
|
||||||
|
edgeAppsList := utils.ReadOption("EDGEAPPS_LIST")
|
||||||
|
var edgeApps []edgeapps.EdgeApp
|
||||||
|
err := json.Unmarshal([]byte(edgeAppsList), &edgeApps)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to unmarshal EDGEAPPS_LIST: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, edgeApp := range edgeApps {
|
||||||
|
for _, service := range edgeApp.Services {
|
||||||
|
input = append(input, service.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input = append(input, "edgeboxctl")
|
||||||
|
input = append(input, "tunnel")
|
||||||
|
|
||||||
|
// Run the system logger
|
||||||
|
system.UpdateSystemLoggerServices(input)
|
||||||
|
|
||||||
|
return "{\"status\": \"ok\"}"
|
||||||
|
}
|
||||||
|
|
||||||
func taskGetEdgeApps() string {
|
func taskGetEdgeApps() string {
|
||||||
fmt.Println("Executing taskGetEdgeApps")
|
fmt.Println("Executing taskGetEdgeApps")
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,8 @@ const ApiPath string = "apiPath"
|
||||||
const EdgeAppsPath string = "edgeAppsPath"
|
const EdgeAppsPath string = "edgeAppsPath"
|
||||||
const EdgeAppsBackupPath string = "edgeAppsBackupPath"
|
const EdgeAppsBackupPath string = "edgeAppsBackupPath"
|
||||||
const WsPath string = "wsPath"
|
const WsPath string = "wsPath"
|
||||||
|
const LoggerPath string = "loggerPath"
|
||||||
|
|
||||||
|
|
||||||
// GetPath : Returns either the hardcoded path, or a overwritten value via .env file at project root. Register paths here for seamless working code between dev and prod environments ;)
|
// GetPath : Returns either the hardcoded path, or a overwritten value via .env file at project root. Register paths here for seamless working code between dev and prod environments ;)
|
||||||
func GetPath(pathKey string) string {
|
func GetPath(pathKey string) string {
|
||||||
|
@ -172,6 +174,13 @@ func GetPath(pathKey string) string {
|
||||||
targetPath = "/home/system/components/ws/"
|
targetPath = "/home/system/components/ws/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LoggerPath:
|
||||||
|
if env["LOGGER_PATH"] != "" {
|
||||||
|
targetPath = env["LOGGER_PATH"]
|
||||||
|
} else {
|
||||||
|
targetPath = "/home/system/components/logger/"
|
||||||
|
}
|
||||||
|
|
||||||
case BackupPasswordFileLocation:
|
case BackupPasswordFileLocation:
|
||||||
|
|
||||||
if env["BACKUP_PASSWORD_FILE_LOCATION"] != "" {
|
if env["BACKUP_PASSWORD_FILE_LOCATION"] != "" {
|
||||||
|
|
Loading…
Reference in New Issue