2021-05-31 13:21:14 +02:00
package system
import (
"fmt"
"strconv"
2022-02-06 15:37:50 +01:00
"strings"
2023-03-20 00:54:42 +01:00
"log"
"os"
"os/exec"
"bufio"
"path/filepath"
"io/ioutil"
"encoding/json"
2022-02-06 15:37:50 +01:00
"github.com/edgebox-iot/edgeboxctl/internal/utils"
2021-05-31 13:21:14 +02:00
2022-02-06 15:37:50 +01:00
"github.com/joho/godotenv"
2022-10-08 18:41:37 +02:00
"github.com/shirou/gopsutil/host"
2021-05-31 13:21:14 +02:00
)
2023-03-20 00:54:42 +01:00
type cloudflaredTunnelJson struct {
AccountTag string ` json:"AccountTag" `
TunnelSecret string ` json:"TunnelSecret" `
TunnelID string ` json:"TunnelID" `
}
2022-02-06 15:37:50 +01:00
// GetUptimeInSeconds: Returns a value (as string) of the total system uptime
2021-05-31 13:21:14 +02:00
func GetUptimeInSeconds ( ) string {
uptime , _ := host . Uptime ( )
return strconv . FormatUint ( uptime , 10 )
}
2022-02-06 15:37:50 +01:00
// GetUptimeFormatted: Returns a humanized version that can be useful for logging
2021-05-31 13:21:14 +02:00
func GetUptimeFormatted ( ) string {
uptime , _ := host . Uptime ( )
days := uptime / ( 60 * 60 * 24 )
hours := ( uptime - ( days * 60 * 60 * 24 ) ) / ( 60 * 60 )
minutes := ( ( uptime - ( days * 60 * 60 * 24 ) ) - ( hours * 60 * 60 ) ) / 60
return fmt . Sprintf ( "%d days, %d hours, %d minutes" , days , hours , minutes )
}
2022-02-06 15:37:50 +01:00
2022-10-08 18:41:37 +02:00
// GetIP: Returns the ip address of the instance
2022-02-06 15:37:50 +01:00
func GetIP ( ) string {
ip := ""
// Trying to find a valid IP (For direct connection, not tunneled)
ethResult := utils . ExecAndGetLines ( "/" , "ip" , [ ] string { "-o" , "-4" , "addr" , "list" , "eth0" } )
for ethResult . Scan ( ) {
adapterRawInfo := strings . Fields ( ethResult . Text ( ) )
if ip == "" {
ip = strings . Split ( adapterRawInfo [ 3 ] , "/" ) [ 0 ]
}
}
// If no IP was found yet, try wlan0
if ip == "" {
wlanResult := utils . ExecAndGetLines ( "/" , "ip" , [ ] string { "-o" , "-4" , "addr" , "list" , "wlan0" } )
for wlanResult . Scan ( ) {
adapterRawInfo := strings . Fields ( wlanResult . Text ( ) )
if ip == "" {
ip = strings . Split ( adapterRawInfo [ 3 ] , "/" ) [ 0 ]
}
}
}
return ip
}
func GetHostname ( ) string {
return utils . Exec ( "/" , "hostname" , [ ] string { } )
}
// SetupCloudOptions: Reads the designated env file looking for options to write into the options table. Meant to be used on initial setup. Deletes source env file after operation.
func SetupCloudOptions ( ) {
var cloudEnv map [ string ] string
2022-10-08 18:41:37 +02:00
cloudEnvFileLocationPath := utils . GetPath ( utils . CloudEnvFileLocation )
cloudEnv , err := godotenv . Read ( cloudEnvFileLocationPath )
2022-02-06 15:37:50 +01:00
if err != nil {
fmt . Println ( "Error loading .env file for cloud version setup" )
}
if cloudEnv [ "NAME" ] != "" {
utils . WriteOption ( "NAME" , cloudEnv [ "NAME" ] )
}
if cloudEnv [ "EMAIL" ] != "" {
utils . WriteOption ( "EMAIL" , cloudEnv [ "EMAIL" ] )
}
if cloudEnv [ "EDGEBOXIO_API_TOKEN" ] != "" {
utils . WriteOption ( "EDGEBOXIO_API_TOKEN" , cloudEnv [ "EDGEBOXIO_API_TOKEN" ] )
}
// In the end of this operation takes place, remove the env file as to not overwrite any options once they are set.
2022-10-08 18:41:37 +02:00
utils . Exec ( "/" , "rm" , [ ] string { cloudEnvFileLocationPath } )
2022-02-06 15:37:50 +01:00
}
2023-03-20 00:54:42 +01:00
// StartService: Starts a service
func StartService ( serviceID string ) {
wsPath := utils . GetPath ( utils . WsPath )
fmt . Println ( "Starting" + serviceID + "service" )
cmdargs := [ ] string { "start" , serviceID }
utils . Exec ( wsPath , "systemctl" , cmdargs )
}
// StopService: Stops a service
func StopService ( serviceID string ) {
wsPath := utils . GetPath ( utils . WsPath )
fmt . Println ( "Stopping" + serviceID + "service" )
cmdargs := [ ] string { "stop" , "cloudflared" }
utils . Exec ( wsPath , "systemctl" , cmdargs )
}
// RestartService: Restarts a service
func RestartService ( serviceID string ) {
wsPath := utils . GetPath ( utils . WsPath )
fmt . Println ( "Restarting" + serviceID + "service" )
cmdargs := [ ] string { "restart" , serviceID }
utils . Exec ( wsPath , "systemctl" , cmdargs )
}
// GetServiceStatus: Returns the status output of a service
func GetServiceStatus ( serviceID string ) string {
wsPath := utils . GetPath ( utils . WsPath )
cmdargs := [ ] string { "status" , serviceID }
return utils . Exec ( wsPath , "systemctl" , cmdargs )
}
2023-05-29 21:52:27 +02:00
func CreateBackupsPasswordFile ( password string ) {
// Create a password file for backups
backupPasswordFile := utils . GetPath ( utils . BackupPasswordFileLocation )
backupPasswordFileDir := filepath . Dir ( backupPasswordFile )
if _ , err := os . Stat ( backupPasswordFileDir ) ; os . IsNotExist ( err ) {
os . MkdirAll ( backupPasswordFileDir , 0755 )
}
// Write the password to the file, overriting an existing file
err := ioutil . WriteFile ( backupPasswordFile , [ ] byte ( password ) , 0644 )
if err != nil {
panic ( err )
}
}
2023-03-20 00:54:42 +01:00
// CreateTunnel: Creates a tunnel via cloudflared, needs to be authenticated first
func CreateTunnel ( configDestination string ) {
fmt . Println ( "Creating Tunnel for Edgebox." )
cmd := exec . Command ( "sh" , "/home/system/components/edgeboxctl/scripts/cloudflared_tunnel_create.sh" )
stdout , err := cmd . StdoutPipe ( )
if err != nil {
panic ( err )
}
scanner := bufio . NewScanner ( stdout )
err = cmd . Start ( )
if err != nil {
panic ( err )
}
for scanner . Scan ( ) {
fmt . Println ( scanner . Text ( ) )
text := scanner . Text ( )
fmt . Println ( text )
}
if scanner . Err ( ) != nil {
cmd . Process . Kill ( )
cmd . Wait ( )
panic ( scanner . Err ( ) )
}
// This also needs to be executed in root and non root variants
fmt . Println ( "Reading cloudflared folder to get the JSON file." )
isRoot := false
dir := "/home/system/.cloudflared/"
dir2 := "/root/.cloudflared/"
files , err := os . ReadDir ( dir )
if err != nil {
panic ( err )
}
var jsonFile os . DirEntry
for _ , file := range files {
// check if file has json extension
if filepath . Ext ( file . Name ( ) ) == ".json" {
fmt . Println ( "Non-Root JSON file found: " + file . Name ( ) )
jsonFile = file
}
}
// If the files are not in the home folder, try the root folder
if jsonFile == nil {
files , err = os . ReadDir ( dir2 )
if err != nil {
panic ( err )
}
for _ , file := range files {
// check if file has json extension
if filepath . Ext ( file . Name ( ) ) == ".json" {
fmt . Println ( "Root JSON file found: " + file . Name ( ) )
jsonFile = file
isRoot = true
}
}
}
if jsonFile == nil {
panic ( "No JSON file found in directory" )
}
fmt . Println ( "Reading JSON file." )
targetDir := "/home/system/.cloudflared/"
if isRoot {
targetDir = "/root/.cloudflared/"
}
jsonFilePath := filepath . Join ( targetDir , jsonFile . Name ( ) )
jsonBytes , err := ioutil . ReadFile ( jsonFilePath )
if err != nil {
panic ( err )
}
fmt . Println ( "Parsing JSON file." )
var data cloudflaredTunnelJson
err = json . Unmarshal ( jsonBytes , & data )
if err != nil {
log . Printf ( "Error reading tunnel JSON file: %s" , err )
}
fmt . Println ( "Tunnel ID is:" + data . TunnelID )
// create the config.yml file with the following content in each line:
// "url": "http://localhost:80"
// "tunnel": "<TunnelID>"
// "credentials-file": "/root/.cloudflared/<tunnelID>.json"
file := configDestination
f , err := os . Create ( file )
if err != nil {
panic ( err )
}
defer f . Close ( )
_ , err = f . WriteString ( "url: http://localhost:80\ntunnel: " + data . TunnelID + "\ncredentials-file: " + jsonFilePath )
if err != nil {
panic ( err )
}
}
// DeleteTunnel: Deletes a tunnel via cloudflared, this does not remove the service
func DeleteTunnel ( ) {
fmt . Println ( "Deleting possible previous tunnel." )
// Configure the service and start it
cmd := exec . Command ( "sh" , "/home/system/components/edgeboxctl/scripts/cloudflared_tunnel_delete.sh" )
stdout , err := cmd . StdoutPipe ( )
if err != nil {
panic ( err )
}
scanner := bufio . NewScanner ( stdout )
err = cmd . Start ( )
if err != nil {
panic ( err )
}
for scanner . Scan ( ) {
fmt . Println ( scanner . Text ( ) )
text := scanner . Text ( )
fmt . Println ( text )
}
if scanner . Err ( ) != nil {
cmd . Process . Kill ( )
cmd . Wait ( )
panic ( scanner . Err ( ) )
}
}
// InstallTunnelService: Installs the tunnel service
func InstallTunnelService ( config string ) {
fmt . Println ( "Installing cloudflared service." )
cmd := exec . Command ( "cloudflared" , "--config" , config , "service" , "install" )
cmd . Start ( )
cmd . Wait ( )
}
// RemoveTunnelService: Removes the tunnel service
func RemoveTunnelService ( ) {
wsPath := utils . GetPath ( utils . WsPath )
fmt . Println ( "Removing possibly previous service install." )
cmd := exec . Command ( "cloudflared" , "service" , "uninstall" )
cmd . Start ( )
cmd . Wait ( )
fmt . Println ( "Removing cloudflared files" )
cmdargs := [ ] string { "-rf" , "/home/system/.cloudflared" }
utils . Exec ( wsPath , "rm" , cmdargs )
cmdargs = [ ] string { "-rf" , "/etc/cloudflared/config.yml" }
utils . Exec ( wsPath , "rm" , cmdargs )
cmdargs = [ ] string { "-rf" , "/root/.cloudflared/cert.pem" }
utils . Exec ( wsPath , "rm" , cmdargs )
}