2021-02-15 20:37:16 +01:00
|
|
|
package edgeapps
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
2021-02-17 01:08:10 +01:00
|
|
|
"strings"
|
2021-02-18 23:59:14 +01:00
|
|
|
"time"
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-02-17 13:34:53 +01:00
|
|
|
"github.com/joho/godotenv"
|
|
|
|
|
2023-06-04 23:19:34 +02:00
|
|
|
"github.com/edgebox-iot/edgeboxctl/internal/system"
|
2021-03-04 13:43:49 +01:00
|
|
|
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
2021-02-15 20:37:16 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// EdgeApp : Struct representing an EdgeApp in the system
|
|
|
|
type EdgeApp struct {
|
2021-02-19 01:22:12 +01:00
|
|
|
ID string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
2021-06-01 13:40:58 +02:00
|
|
|
Description string `json:"description"`
|
2021-02-19 01:22:12 +01:00
|
|
|
Status EdgeAppStatus `json:"status"`
|
|
|
|
Services []EdgeAppService `json:"services"`
|
|
|
|
InternetAccessible bool `json:"internet_accessible"`
|
|
|
|
NetworkURL string `json:"network_url"`
|
|
|
|
InternetURL string `json:"internet_url"`
|
2021-02-15 20:37:16 +01:00
|
|
|
}
|
|
|
|
|
2021-02-20 15:26:23 +01:00
|
|
|
// MaybeEdgeApp : Boolean flag for validation of edgeapp existance
|
|
|
|
type MaybeEdgeApp struct {
|
|
|
|
EdgeApp EdgeApp `json:"edge_app"`
|
|
|
|
Valid bool `json:"valid"`
|
|
|
|
}
|
|
|
|
|
2021-02-15 20:37:16 +01:00
|
|
|
// EdgeAppStatus : Struct representing possible EdgeApp statuses (code + description)
|
|
|
|
type EdgeAppStatus struct {
|
|
|
|
ID int `json:"id"`
|
|
|
|
Description string `json:"description"`
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:30:01 +01:00
|
|
|
// EdgeAppService : Struct representing a single container that can be part of an EdgeApp package
|
|
|
|
type EdgeAppService struct {
|
|
|
|
ID string `json:"id"`
|
2021-02-17 01:08:10 +01:00
|
|
|
IsRunning bool `json:"is_running"`
|
2021-02-16 17:30:01 +01:00
|
|
|
}
|
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
const configFilename = "/edgebox-compose.yml"
|
2021-02-17 13:34:53 +01:00
|
|
|
const envFilename = "/edgebox.env"
|
2021-03-04 16:06:54 +01:00
|
|
|
const runnableFilename = "/.run"
|
2021-02-19 01:22:12 +01:00
|
|
|
const myEdgeAppServiceEnvFilename = "/myedgeapp.env"
|
2021-02-18 23:59:14 +01:00
|
|
|
const defaultContainerOperationSleepTime time.Duration = time.Second * 10
|
2021-02-17 12:10:15 +01:00
|
|
|
|
2021-02-20 15:26:23 +01:00
|
|
|
// GetEdgeApp : Returns a EdgeApp struct with the current application information
|
|
|
|
func GetEdgeApp(ID string) MaybeEdgeApp {
|
|
|
|
|
|
|
|
result := MaybeEdgeApp{
|
|
|
|
EdgeApp: EdgeApp{},
|
|
|
|
Valid: false,
|
|
|
|
}
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
_, err := os.Stat(utils.GetPath(utils.EdgeAppsPath) + ID + configFilename)
|
2021-02-20 15:26:23 +01:00
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
// File exists. Start digging!
|
|
|
|
|
|
|
|
edgeAppName := ID
|
2021-06-01 13:40:58 +02:00
|
|
|
edgeAppDescription := ""
|
2021-02-20 15:26:23 +01:00
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
edgeAppEnv, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + envFilename)
|
2021-02-20 15:26:23 +01:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Println("Error loading .env file for edgeapp " + edgeAppName)
|
|
|
|
} else {
|
|
|
|
if edgeAppEnv["EDGEAPP_NAME"] != "" {
|
|
|
|
edgeAppName = edgeAppEnv["EDGEAPP_NAME"]
|
|
|
|
}
|
2021-06-01 13:40:58 +02:00
|
|
|
if edgeAppEnv["EDGEAPP_DESCRIPTION"] != "" {
|
|
|
|
edgeAppDescription = edgeAppEnv["EDGEAPP_DESCRIPTION"]
|
|
|
|
}
|
2021-02-20 15:26:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
edgeAppInternetAccessible := false
|
|
|
|
edgeAppInternetURL := ""
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
myEdgeAppServiceEnv, err := godotenv.Read(utils.GetPath(utils.EdgeAppsPath) + ID + myEdgeAppServiceEnvFilename)
|
2021-02-20 15:26:23 +01:00
|
|
|
if err != nil {
|
2021-02-20 19:09:41 +01:00
|
|
|
log.Println("No myedge.app environment file found. Status is Network-Only")
|
|
|
|
} else {
|
2021-02-20 15:26:23 +01:00
|
|
|
if myEdgeAppServiceEnv["INTERNET_URL"] != "" {
|
|
|
|
edgeAppInternetAccessible = true
|
|
|
|
edgeAppInternetURL = myEdgeAppServiceEnv["INTERNET_URL"]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = MaybeEdgeApp{
|
|
|
|
EdgeApp: EdgeApp{
|
|
|
|
ID: ID,
|
|
|
|
Name: edgeAppName,
|
2021-06-01 13:40:58 +02:00
|
|
|
Description: edgeAppDescription,
|
2021-02-20 15:26:23 +01:00
|
|
|
Status: GetEdgeAppStatus(ID),
|
|
|
|
Services: GetEdgeAppServices(ID),
|
|
|
|
InternetAccessible: edgeAppInternetAccessible,
|
2023-06-04 23:19:34 +02:00
|
|
|
NetworkURL: ID + system.GetHostname() + ".local",
|
2021-02-20 15:26:23 +01:00
|
|
|
InternetURL: edgeAppInternetURL,
|
|
|
|
},
|
|
|
|
Valid: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-03-04 16:06:54 +01:00
|
|
|
func IsEdgeAppInstalled(ID string) bool {
|
|
|
|
|
|
|
|
result := false
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
_, err := os.Stat(utils.GetPath(utils.EdgeAppsPath) + ID + runnableFilename)
|
2021-03-04 16:06:54 +01:00
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
result = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetEdgeAppInstalled(ID string) bool {
|
|
|
|
|
|
|
|
result := true
|
2022-10-08 18:41:37 +02:00
|
|
|
edgeAppPath := utils.GetPath(utils.EdgeAppsPath)
|
2021-03-04 16:06:54 +01:00
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
_, err := os.Stat(edgeAppPath + ID + runnableFilename)
|
2021-03-04 16:06:54 +01:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
_, err := os.Create(edgeAppPath + ID + runnableFilename)
|
2021-03-04 16:06:54 +01:00
|
|
|
result = true
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Runnable file for EdgeApp could not be created!")
|
|
|
|
result = false
|
|
|
|
}
|
|
|
|
|
|
|
|
buildFrameworkContainers()
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Is already installed.
|
|
|
|
result = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetEdgeAppNotInstalled(ID string) bool {
|
|
|
|
|
|
|
|
result := true
|
2022-10-08 18:41:37 +02:00
|
|
|
err := os.Remove(utils.GetPath(utils.EdgeAppsPath) + ID + runnableFilename)
|
2021-03-04 16:06:54 +01:00
|
|
|
if err != nil {
|
2021-06-01 13:40:58 +02:00
|
|
|
result = false
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2021-03-04 16:06:54 +01:00
|
|
|
|
|
|
|
buildFrameworkContainers()
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-20 15:26:23 +01:00
|
|
|
// GetEdgeApps : Returns a list of all available EdgeApps in structs filled with information
|
2021-02-17 01:08:10 +01:00
|
|
|
func GetEdgeApps() []EdgeApp {
|
2021-02-15 20:37:16 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
var edgeApps []EdgeApp
|
2021-02-15 20:37:16 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
// Building list of available edgeapps in the system with their status
|
2021-02-15 20:37:16 +01:00
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
files, err := ioutil.ReadDir(utils.GetPath(utils.EdgeAppsPath))
|
2021-02-15 20:37:16 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, f := range files {
|
|
|
|
if f.IsDir() {
|
|
|
|
// It is a folder that most probably contains an EdgeApp.
|
|
|
|
// To be fully sure, test that edgebox-compose.yml file exists in the target directory.
|
2021-02-20 15:26:23 +01:00
|
|
|
maybeEdgeApp := GetEdgeApp(f.Name())
|
|
|
|
if maybeEdgeApp.Valid {
|
|
|
|
|
|
|
|
edgeApp := maybeEdgeApp.EdgeApp
|
2021-02-17 01:08:10 +01:00
|
|
|
edgeApps = append(edgeApps, edgeApp)
|
2021-02-20 15:26:23 +01:00
|
|
|
|
2021-02-15 20:37:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 17:30:01 +01:00
|
|
|
// return edgeApps
|
2021-02-17 01:08:10 +01:00
|
|
|
return edgeApps
|
2021-02-16 17:30:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetEdgeAppStatus : Returns a struct representing the current status of the EdgeApp
|
2021-02-17 01:08:10 +01:00
|
|
|
func GetEdgeAppStatus(ID string) EdgeAppStatus {
|
|
|
|
|
|
|
|
// Possible states of an EdgeApp:
|
|
|
|
// - All services running = EdgeApp running
|
|
|
|
// - Some services running = Problem detected, needs restart
|
|
|
|
// - No service running = EdgeApp is off
|
|
|
|
|
|
|
|
runningServices := 0
|
2021-06-01 13:40:58 +02:00
|
|
|
|
2021-03-04 16:19:31 +01:00
|
|
|
status := EdgeAppStatus{0, "off"}
|
2021-03-04 16:06:54 +01:00
|
|
|
|
|
|
|
if !IsEdgeAppInstalled(ID) {
|
|
|
|
|
2021-03-04 16:19:31 +01:00
|
|
|
status = EdgeAppStatus{-1, "not-installed"}
|
2021-03-04 16:06:54 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
services := GetEdgeAppServices(ID)
|
|
|
|
for _, edgeAppService := range services {
|
|
|
|
if edgeAppService.IsRunning {
|
|
|
|
runningServices++
|
|
|
|
}
|
2021-02-17 01:08:10 +01:00
|
|
|
}
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-03-04 16:06:54 +01:00
|
|
|
if runningServices > 0 && runningServices != len(services) {
|
|
|
|
status = EdgeAppStatus{2, "error"}
|
|
|
|
}
|
|
|
|
|
|
|
|
if runningServices == len(services) {
|
|
|
|
status = EdgeAppStatus{1, "on"}
|
|
|
|
}
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
}
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
return status
|
|
|
|
|
|
|
|
}
|
2021-02-16 17:30:01 +01:00
|
|
|
|
|
|
|
// GetEdgeAppServices : Returns a
|
2021-02-17 01:08:10 +01:00
|
|
|
func GetEdgeAppServices(ID string) []EdgeAppService {
|
2022-10-08 18:41:37 +02:00
|
|
|
wsPath := utils.GetPath(utils.WsPath)
|
|
|
|
cmdArgs := []string{"-r", ".services | keys[]", utils.GetPath(utils.EdgeAppsPath) + ID + configFilename}
|
|
|
|
servicesString := utils.Exec(utils.GetPath(utils.WsPath), "yq", cmdArgs)
|
2021-02-17 01:08:10 +01:00
|
|
|
serviceSlices := strings.Split(servicesString, "\n")
|
|
|
|
serviceSlices = utils.DeleteEmptySlices(serviceSlices)
|
|
|
|
var edgeAppServices []EdgeAppService
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
for _, serviceID := range serviceSlices {
|
2022-10-08 18:41:37 +02:00
|
|
|
cmdArgs = []string{"-f", wsPath + "/docker-compose.yml", "exec", "-T", serviceID, "echo", "'Service Check'"}
|
|
|
|
cmdResult := utils.Exec(wsPath, "docker-compose", cmdArgs)
|
2021-02-17 01:08:10 +01:00
|
|
|
isRunning := false
|
|
|
|
if cmdResult != "" {
|
|
|
|
isRunning = true
|
|
|
|
}
|
|
|
|
edgeAppServices = append(edgeAppServices, EdgeAppService{ID: serviceID, IsRunning: isRunning})
|
|
|
|
}
|
2021-02-16 17:30:01 +01:00
|
|
|
|
2021-02-17 01:08:10 +01:00
|
|
|
return edgeAppServices
|
2021-02-15 20:37:16 +01:00
|
|
|
|
|
|
|
}
|
2021-02-17 01:24:51 +01:00
|
|
|
|
|
|
|
// RunEdgeApp : Run an EdgeApp and return its most current status
|
|
|
|
func RunEdgeApp(ID string) EdgeAppStatus {
|
2022-10-08 18:41:37 +02:00
|
|
|
wsPath := utils.GetPath(utils.WsPath)
|
2021-02-18 23:59:14 +01:00
|
|
|
services := GetEdgeAppServices(ID)
|
|
|
|
cmdArgs := []string{}
|
|
|
|
|
|
|
|
for _, service := range services {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
cmdArgs = []string{"-f", wsPath + "/docker-compose.yml", "start", service.ID}
|
|
|
|
utils.Exec(wsPath, "docker-compose", cmdArgs)
|
2021-02-18 23:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for it to settle up before continuing...
|
|
|
|
time.Sleep(defaultContainerOperationSleepTime)
|
2021-02-17 01:24:51 +01:00
|
|
|
|
|
|
|
return GetEdgeAppStatus(ID)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// StopEdgeApp : Stops an EdgeApp and return its most current status
|
|
|
|
func StopEdgeApp(ID string) EdgeAppStatus {
|
2022-10-08 18:41:37 +02:00
|
|
|
wsPath := utils.GetPath(utils.WsPath)
|
2021-02-18 23:59:14 +01:00
|
|
|
services := GetEdgeAppServices(ID)
|
|
|
|
cmdArgs := []string{}
|
|
|
|
for _, service := range services {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
cmdArgs = []string{"-f", wsPath + "/docker-compose.yml", "stop", service.ID}
|
|
|
|
utils.Exec(wsPath, "docker-compose", cmdArgs)
|
2021-02-18 23:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for it to settle up before continuing...
|
|
|
|
time.Sleep(defaultContainerOperationSleepTime)
|
2021-02-17 01:24:51 +01:00
|
|
|
|
|
|
|
return GetEdgeAppStatus(ID)
|
|
|
|
|
|
|
|
}
|
2021-02-20 15:26:23 +01:00
|
|
|
|
2023-05-31 02:03:23 +02:00
|
|
|
// StopAllEdgeApps: Stops all EdgeApps and returns a count of how many were stopped
|
|
|
|
func StopAllEdgeApps() int {
|
|
|
|
edgeApps := GetEdgeApps()
|
|
|
|
appCount := 0
|
|
|
|
for _, edgeApp := range edgeApps {
|
|
|
|
StopEdgeApp(edgeApp.ID)
|
|
|
|
appCount++
|
|
|
|
}
|
|
|
|
|
|
|
|
return appCount
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// StartAllEdgeApps: Starts all EdgeApps and returns a count of how many were started
|
|
|
|
func StartAllEdgeApps() int {
|
|
|
|
edgeApps := GetEdgeApps()
|
|
|
|
appCount := 0
|
|
|
|
for _, edgeApp := range edgeApps {
|
|
|
|
RunEdgeApp(edgeApp.ID)
|
|
|
|
appCount++
|
|
|
|
}
|
|
|
|
|
|
|
|
return appCount
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func RestartEdgeAppsService() {
|
|
|
|
buildFrameworkContainers()
|
|
|
|
}
|
|
|
|
|
2021-02-20 15:26:23 +01:00
|
|
|
// EnableOnline : Write environment file and rebuild the necessary containers. Rebuilds containers in project (in case of change only)
|
|
|
|
func EnableOnline(ID string, InternetURL string) MaybeEdgeApp {
|
|
|
|
|
|
|
|
maybeEdgeApp := GetEdgeApp(ID)
|
|
|
|
if maybeEdgeApp.Valid { // We're only going to do this operation if the EdgeApp actually exists.
|
|
|
|
// Create the myedgeapp.env file and add the InternetURL entry to it
|
2022-10-08 18:41:37 +02:00
|
|
|
envFilePath := utils.GetPath(utils.EdgeAppsPath) + ID + myEdgeAppServiceEnvFilename
|
2021-02-20 15:26:23 +01:00
|
|
|
env, _ := godotenv.Unmarshal("INTERNET_URL=" + InternetURL)
|
|
|
|
_ = godotenv.Write(env, envFilePath)
|
|
|
|
}
|
|
|
|
|
|
|
|
buildFrameworkContainers()
|
|
|
|
|
|
|
|
return GetEdgeApp(ID) // Return refreshed information
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// DisableOnline : Removes env files necessary for system external access config. Rebuilds containers in project (in case of change only).
|
|
|
|
func DisableOnline(ID string) MaybeEdgeApp {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
envFilePath := utils.GetPath(utils.EdgeAppsPath) + ID + myEdgeAppServiceEnvFilename
|
2021-02-20 15:26:23 +01:00
|
|
|
_, err := godotenv.Read(envFilePath)
|
|
|
|
if err != nil {
|
2021-02-20 19:09:41 +01:00
|
|
|
log.Println("myedge.app environment file for " + ID + " not found. No need to delete.")
|
|
|
|
} else {
|
2021-02-20 15:26:23 +01:00
|
|
|
cmdArgs := []string{envFilePath}
|
2022-10-08 18:41:37 +02:00
|
|
|
utils.Exec(utils.GetPath(utils.WsPath), "rm", cmdArgs)
|
2021-02-20 15:26:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
buildFrameworkContainers()
|
|
|
|
|
|
|
|
return GetEdgeApp(ID)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-06 15:37:50 +01:00
|
|
|
func EnablePublicDashboard(InternetURL string) bool {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
envFilePath := utils.GetPath(utils.ApiPath) + myEdgeAppServiceEnvFilename
|
2022-02-06 15:37:50 +01:00
|
|
|
env, _ := godotenv.Unmarshal("INTERNET_URL=" + InternetURL)
|
|
|
|
_ = godotenv.Write(env, envFilePath)
|
|
|
|
|
|
|
|
buildFrameworkContainers()
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func DisablePublicDashboard() bool {
|
2022-10-08 18:41:37 +02:00
|
|
|
envFilePath := utils.GetPath(utils.ApiPath) + myEdgeAppServiceEnvFilename
|
2022-02-06 15:37:50 +01:00
|
|
|
if !IsPublicDashboard() {
|
|
|
|
log.Println("myedge.app environment file for the dashboard / api not found. No need to delete.")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdArgs := []string{envFilePath}
|
2022-10-08 18:41:37 +02:00
|
|
|
utils.Exec(utils.GetPath(utils.ApiPath), "rm", cmdArgs)
|
2022-02-06 15:37:50 +01:00
|
|
|
buildFrameworkContainers()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func IsPublicDashboard() bool {
|
2022-10-08 18:41:37 +02:00
|
|
|
envFilePath := utils.GetPath(utils.ApiPath) + myEdgeAppServiceEnvFilename
|
2022-02-06 15:37:50 +01:00
|
|
|
_, err := godotenv.Read(envFilePath)
|
|
|
|
return err == nil
|
|
|
|
}
|
|
|
|
|
2021-02-20 15:26:23 +01:00
|
|
|
func buildFrameworkContainers() {
|
|
|
|
|
2022-10-08 18:41:37 +02:00
|
|
|
wsPath := utils.GetPath(utils.WsPath)
|
|
|
|
cmdArgs := []string{wsPath + "ws", "--build"}
|
|
|
|
utils.ExecAndStream(wsPath, "sh", cmdArgs)
|
2021-02-20 15:26:23 +01:00
|
|
|
|
|
|
|
time.Sleep(defaultContainerOperationSleepTime)
|
|
|
|
|
|
|
|
}
|