Add: Download the nu and deno binaries from GitHub
Signed-off-by: David Randall <David@NiceGuyIT.biz>
This commit is contained in:
parent
6ba3272dc0
commit
87e1b29ef6
@ -58,6 +58,8 @@ type Agent struct {
|
|||||||
MeshSystemEXE string
|
MeshSystemEXE string
|
||||||
MeshSVC string
|
MeshSVC string
|
||||||
PyBin string
|
PyBin string
|
||||||
|
NuBin string
|
||||||
|
DenoBin string
|
||||||
Headers map[string]string
|
Headers map[string]string
|
||||||
Logger *logrus.Logger
|
Logger *logrus.Logger
|
||||||
Version string
|
Version string
|
||||||
@ -86,10 +88,13 @@ const (
|
|||||||
nixAgentDir = "/opt/tacticalagent"
|
nixAgentDir = "/opt/tacticalagent"
|
||||||
nixMeshDir = "/opt/tacticalmesh"
|
nixMeshDir = "/opt/tacticalmesh"
|
||||||
nixAgentBin = nixAgentDir + "/tacticalagent"
|
nixAgentBin = nixAgentDir + "/tacticalagent"
|
||||||
|
nixAgentBinDir = nixAgentDir + "/bin"
|
||||||
nixMeshAgentBin = nixMeshDir + "/meshagent"
|
nixMeshAgentBin = nixMeshDir + "/meshagent"
|
||||||
macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist"
|
macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist"
|
||||||
macPlistName = "tacticalagent"
|
macPlistName = "tacticalagent"
|
||||||
defaultMacMeshSvcDir = "/usr/local/mesh_services"
|
defaultMacMeshSvcDir = "/usr/local/mesh_services"
|
||||||
|
nuVersion = "0.87.0"
|
||||||
|
denoVersion = "v1.38.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM")
|
var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM")
|
||||||
@ -119,6 +124,22 @@ func New(logger *logrus.Logger, version string) *Agent {
|
|||||||
pybin = filepath.Join(pd, "py38-x32", "python.exe")
|
pybin = filepath.Join(pd, "py38-x32", "python.exe")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nuBin string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
nuBin = filepath.Join(pd, "bin", "nu.exe")
|
||||||
|
default:
|
||||||
|
nuBin = filepath.Join(nixAgentBinDir, "nu")
|
||||||
|
}
|
||||||
|
|
||||||
|
var denoBin string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
denoBin = filepath.Join(pd, "bin", "deno.exe")
|
||||||
|
default:
|
||||||
|
denoBin = filepath.Join(nixAgentBinDir, "deno")
|
||||||
|
}
|
||||||
|
|
||||||
ac := NewAgentConfig()
|
ac := NewAgentConfig()
|
||||||
|
|
||||||
headers := make(map[string]string)
|
headers := make(map[string]string)
|
||||||
@ -232,6 +253,8 @@ func New(logger *logrus.Logger, version string) *Agent {
|
|||||||
MeshSystemEXE: MeshSysExe,
|
MeshSystemEXE: MeshSysExe,
|
||||||
MeshSVC: meshSvcName,
|
MeshSVC: meshSvcName,
|
||||||
PyBin: pybin,
|
PyBin: pybin,
|
||||||
|
NuBin: nuBin,
|
||||||
|
DenoBin: denoBin,
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
Version: version,
|
Version: version,
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -196,31 +197,42 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
|
|||||||
opts.IsScript = true
|
opts.IsScript = true
|
||||||
switch shell {
|
switch shell {
|
||||||
case "nushell":
|
case "nushell":
|
||||||
// FIXME: Make this dynamic and use /opt/tacticalagent/bin/nu
|
opts.Shell = a.NuBin
|
||||||
opts.Shell = "/usr/local/bin/nu"
|
|
||||||
opts.Args = append([]string{
|
opts.Args = append([]string{
|
||||||
"--no-config-file",
|
"--no-config-file",
|
||||||
f.Name(),
|
f.Name(),
|
||||||
},
|
},
|
||||||
args...)
|
args...)
|
||||||
|
if !trmm.FileExists(a.NuBin) {
|
||||||
|
a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin)
|
||||||
|
err := errors.New("File Not Found: " + a.NuBin)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
case "deno":
|
case "deno":
|
||||||
// FIXME: Make this dynamic and use /opt/tacticalagent/bin/nu
|
opts.Shell = a.DenoBin
|
||||||
opts.Shell = "/usr/local/bin/deno"
|
|
||||||
opts.Args = []string{
|
opts.Args = []string{
|
||||||
"run",
|
"run",
|
||||||
"--no-prompt",
|
"--no-prompt",
|
||||||
}
|
}
|
||||||
|
if !trmm.FileExists(a.DenoBin) {
|
||||||
|
a.Logger.Errorln("RunScript(): Executable does not exist. Install deno and try again:", a.DenoBin)
|
||||||
|
err := errors.New("File Not Found: " + a.DenoBin)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
// Search the environment variables for DENO_PERMISSIONS and use that to set permissions for the script.
|
// Search the environment variables for DENO_PERMISSIONS and use that to set permissions for the script.
|
||||||
// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list
|
// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list
|
||||||
// DENO_PERMISSIONS is not an official environment variable.
|
// DENO_PERMISSIONS is not an official environment variable.
|
||||||
// https://docs.deno.com/runtime/manual/basics/env_variables
|
// https://docs.deno.com/runtime/manual/basics/env_variables
|
||||||
// TODO: Remove DENO_PERMISSIONS from the environment variables.
|
for i, v := range envVars {
|
||||||
for _, v := range envVars {
|
|
||||||
if strings.HasPrefix(v, "DENO_PERMISSIONS=") {
|
if strings.HasPrefix(v, "DENO_PERMISSIONS=") {
|
||||||
permissions := strings.Split(v, "=")[1]
|
permissions := strings.Split(v, "=")[1]
|
||||||
opts.Args = append(opts.Args, strings.Split(permissions, " ")...)
|
opts.Args = append(opts.Args, strings.Split(permissions, " ")...)
|
||||||
|
// Remove the DENO_PERMISSIONS variable from the environment variables slice.
|
||||||
|
// It's possible more variables may exist with the same prefix.
|
||||||
|
envVars = append(envVars[:i], envVars[i+1:]...)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +248,7 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
|
|||||||
|
|
||||||
opts.EnvVars = envVars
|
opts.EnvVars = envVars
|
||||||
opts.Timeout = time.Duration(timeout)
|
opts.Timeout = time.Duration(timeout)
|
||||||
a.Logger.Debugln("RunScript(): ", opts.Shell, opts.Args)
|
a.Logger.Debugln("RunScript():", opts.Shell, opts.Args)
|
||||||
out := a.CmdV2(opts)
|
out := a.CmdV2(opts)
|
||||||
retError := ""
|
retError := ""
|
||||||
if out.Status.Error != nil {
|
if out.Status.Error != nil {
|
||||||
@ -541,6 +553,235 @@ func GetServiceStatus(name string) (string, error) { return "", nil }
|
|||||||
|
|
||||||
func (a *Agent) GetPython(force bool) {}
|
func (a *Agent) GetPython(force bool) {}
|
||||||
|
|
||||||
|
// GetNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir
|
||||||
|
func (a *Agent) GetNushell(force bool) {
|
||||||
|
if trmm.FileExists(a.NuBin) {
|
||||||
|
if force {
|
||||||
|
err := os.Remove(a.NuBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error removing nu binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !trmm.FileExists(nixAgentBinDir) {
|
||||||
|
err := os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error creating nixAgentBinDir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
assetName string
|
||||||
|
url string
|
||||||
|
targzDirName string
|
||||||
|
)
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "arm64":
|
||||||
|
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz
|
||||||
|
assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", nuVersion)
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "linux":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz
|
||||||
|
assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", nuVersion)
|
||||||
|
case "arm64":
|
||||||
|
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz
|
||||||
|
assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", nuVersion)
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName)
|
||||||
|
a.Logger.Debugln("GetNushell(): Nu download url:", url)
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "trmm")
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error creating temp directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(path string) {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error removing temp directory:", err)
|
||||||
|
}
|
||||||
|
}(tmpDir)
|
||||||
|
|
||||||
|
tmpAssetName := filepath.Join(tmpDir, assetName)
|
||||||
|
a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName)
|
||||||
|
|
||||||
|
rClient := resty.New()
|
||||||
|
rClient.SetTimeout(20 * time.Minute)
|
||||||
|
rClient.SetRetryCount(10)
|
||||||
|
rClient.SetRetryWaitTime(1 * time.Minute)
|
||||||
|
rClient.SetRetryMaxWaitTime(15 * time.Minute)
|
||||||
|
if len(a.Proxy) > 0 {
|
||||||
|
rClient.SetProxy(a.Proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.IsError() {
|
||||||
|
a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Failed to extract downloaded tar.gz file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Failed to copy nu file to install dir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(a.NuBin, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Failed to chmod nu binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir
|
||||||
|
func (a *Agent) GetDeno(force bool) {
|
||||||
|
if trmm.FileExists(a.DenoBin) {
|
||||||
|
if force {
|
||||||
|
err := os.Remove(a.DenoBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error removing deno binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !trmm.FileExists(nixAgentBinDir) {
|
||||||
|
err := os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
assetName string
|
||||||
|
url string
|
||||||
|
)
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "arm64":
|
||||||
|
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip
|
||||||
|
assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip")
|
||||||
|
case "amd64":
|
||||||
|
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip
|
||||||
|
assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip")
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "linux":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip
|
||||||
|
assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip")
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName)
|
||||||
|
a.Logger.Debugln("GetDeno(): Deno download url:", url)
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "trmm")
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating temp directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(path string) {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error removing temp directory:", err)
|
||||||
|
}
|
||||||
|
}(tmpDir)
|
||||||
|
|
||||||
|
tmpAssetName := filepath.Join(tmpDir, assetName)
|
||||||
|
a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName)
|
||||||
|
|
||||||
|
if !trmm.FileExists(nixAgentBinDir) {
|
||||||
|
err = os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rClient := resty.New()
|
||||||
|
rClient.SetTimeout(20 * time.Minute)
|
||||||
|
rClient.SetRetryCount(10)
|
||||||
|
rClient.SetRetryWaitTime(1 * time.Minute)
|
||||||
|
rClient.SetRetryMaxWaitTime(15 * time.Minute)
|
||||||
|
if len(a.Proxy) > 0 {
|
||||||
|
rClient.SetProxy(a.Proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.IsError() {
|
||||||
|
a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Unzip(tmpAssetName, tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Failed to copy deno file to install dir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chmod(a.DenoBin, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Failed to chmod deno binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
type SchedTask struct{ Name string }
|
type SchedTask struct{ Name string }
|
||||||
|
|
||||||
func (a *Agent) PatchMgmnt(enable bool) error { return nil }
|
func (a *Agent) PatchMgmnt(enable bool) error { return nil }
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -156,9 +157,41 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
|
|||||||
case "cmd":
|
case "cmd":
|
||||||
exe = tmpfn.Name()
|
exe = tmpfn.Name()
|
||||||
case "nushell":
|
case "nushell":
|
||||||
exe = tmpfn.Name()
|
exe = a.NuBin
|
||||||
|
cmdArgs = []string{"--no-config-file", tmpfn.Name()}
|
||||||
|
if !trmm.FileExists(a.NuBin) {
|
||||||
|
a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin)
|
||||||
|
err := errors.New("File Not Found: " + a.NuBin)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
case "deno":
|
case "deno":
|
||||||
exe = tmpfn.Name()
|
exe = a.DenoBin
|
||||||
|
cmdArgs = []string{"run", "--no-prompt"}
|
||||||
|
if !trmm.FileExists(a.DenoBin) {
|
||||||
|
a.Logger.Errorln("RunScript(): Executable does not exist. Install deno and try again:", a.DenoBin)
|
||||||
|
err := errors.New("File Not Found: " + a.DenoBin)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search the environment variables for DENO_PERMISSIONS and use that to set permissions for the script.
|
||||||
|
// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list
|
||||||
|
// DENO_PERMISSIONS is not an official environment variable.
|
||||||
|
// https://docs.deno.com/runtime/manual/basics/env_variables
|
||||||
|
for i, v := range envVars {
|
||||||
|
if strings.HasPrefix(v, "DENO_PERMISSIONS=") {
|
||||||
|
permissions := strings.Split(v, "=")[1]
|
||||||
|
cmdArgs = append(cmdArgs, strings.Split(permissions, " ")...)
|
||||||
|
// Remove the DENO_PERMISSIONS variable from the environment variables slice.
|
||||||
|
// It's possible more variables may exist with the same prefix.
|
||||||
|
envVars = append(envVars[:i], envVars[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't append a variadic slice after a string arg.
|
||||||
|
// https://pkg.go.dev/builtin#append
|
||||||
|
cmdArgs = append(cmdArgs, tmpfn.Name())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
@ -846,6 +879,204 @@ func (a *Agent) GetPython(force bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is
|
||||||
|
// initialized to C:\Program Files\TacticalAgent
|
||||||
|
func (a *Agent) GetNushell(force bool) {
|
||||||
|
if trmm.FileExists(a.NuBin) {
|
||||||
|
if force {
|
||||||
|
err := os.Remove(a.NuBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error removing nu binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
programBinDir := path.Join(a.ProgramDir, "bin")
|
||||||
|
if !trmm.FileExists(programBinDir) {
|
||||||
|
err := os.MkdirAll(programBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error creating Program Files bin folder:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
assetName string
|
||||||
|
url string
|
||||||
|
)
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip
|
||||||
|
assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", nuVersion)
|
||||||
|
case "arm64":
|
||||||
|
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip
|
||||||
|
assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", nuVersion)
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName)
|
||||||
|
a.Logger.Debugln("GetNushell(): Nu download url:", url)
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "trmm")
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error creating temp directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(path string) {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Error removing temp directory:", err)
|
||||||
|
}
|
||||||
|
}(tmpDir)
|
||||||
|
|
||||||
|
tmpAssetName := filepath.Join(tmpDir, assetName)
|
||||||
|
a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName)
|
||||||
|
|
||||||
|
rClient := resty.New()
|
||||||
|
rClient.SetTimeout(20 * time.Minute)
|
||||||
|
rClient.SetRetryCount(10)
|
||||||
|
rClient.SetRetryWaitTime(1 * time.Minute)
|
||||||
|
rClient.SetRetryMaxWaitTime(15 * time.Minute)
|
||||||
|
if len(a.Proxy) > 0 {
|
||||||
|
rClient.SetProxy(a.Proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.IsError() {
|
||||||
|
a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Unzip(tmpAssetName, tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Failed to unzip downloaded zip file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetNushell(): Failed to copy nu.exe file to install dir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir
|
||||||
|
func (a *Agent) GetDeno(force bool) {
|
||||||
|
if trmm.FileExists(a.DenoBin) {
|
||||||
|
if force {
|
||||||
|
err := os.Remove(a.DenoBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error removing deno binary:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
programBinDir := path.Join(a.ProgramDir, "bin")
|
||||||
|
if !trmm.FileExists(programBinDir) {
|
||||||
|
err := os.MkdirAll(programBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating Program Files bin folder:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
assetName string
|
||||||
|
url string
|
||||||
|
)
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip
|
||||||
|
assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip")
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName)
|
||||||
|
a.Logger.Debugln("GetDeno(): Deno download url:", url)
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "trmm")
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating temp directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(path string) {
|
||||||
|
err := os.RemoveAll(path)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error removing temp directory:", err)
|
||||||
|
}
|
||||||
|
}(tmpDir)
|
||||||
|
|
||||||
|
tmpAssetName := filepath.Join(tmpDir, assetName)
|
||||||
|
a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName)
|
||||||
|
|
||||||
|
if !trmm.FileExists(nixAgentBinDir) {
|
||||||
|
err = os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rClient := resty.New()
|
||||||
|
rClient.SetTimeout(20 * time.Minute)
|
||||||
|
rClient.SetRetryCount(10)
|
||||||
|
rClient.SetRetryWaitTime(1 * time.Minute)
|
||||||
|
rClient.SetRetryMaxWaitTime(15 * time.Minute)
|
||||||
|
if len(a.Proxy) > 0 {
|
||||||
|
rClient.SetProxy(a.Proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.IsError() {
|
||||||
|
a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Unzip(tmpAssetName, tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetDeno(): Failed to copy deno.exe file to install dir:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Agent) RecoverMesh() {
|
func (a *Agent) RecoverMesh() {
|
||||||
a.Logger.Infoln("Attempting mesh recovery")
|
a.Logger.Infoln("Attempting mesh recovery")
|
||||||
defer CMD("net", []string{"start", a.MeshSVC}, 60, false)
|
defer CMD("net", []string{"start", a.MeshSVC}, 60, false)
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -258,8 +259,13 @@ func (a *Agent) Install(i *Installer) {
|
|||||||
// check in once
|
// check in once
|
||||||
a.DoNatsCheckIn()
|
a.DoNatsCheckIn()
|
||||||
|
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
// Used for Nushell and Deno binaries
|
||||||
|
os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
os.MkdirAll(nixAgentDir, 0755)
|
os.MkdirAll(nixAgentBinDir, 0755)
|
||||||
self, _ := os.Executable()
|
self, _ := os.Executable()
|
||||||
copyFile(self, nixAgentBin)
|
copyFile(self, nixAgentBin)
|
||||||
os.Chmod(nixAgentBin, 0755)
|
os.Chmod(nixAgentBin, 0755)
|
||||||
@ -300,6 +306,8 @@ func (a *Agent) Install(i *Installer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
os.MkdirAll(path.Join(a.ProgramDir, "bin"), 0755)
|
||||||
|
|
||||||
// send software api
|
// send software api
|
||||||
a.SendSoftware()
|
a.SendSoftware()
|
||||||
|
|
||||||
@ -341,7 +349,7 @@ func (a *Agent) Install(i *Installer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.installerMsg("Installation was successfull!\nAllow a few minutes for the agent to properly display in the RMM", "info", i.Silent)
|
a.installerMsg("Installation was successful!\nAllow a few minutes for the agent to properly display in the RMM", "info", i.Silent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(src, dst string) error {
|
func copyFile(src, dst string) error {
|
||||||
|
@ -437,6 +437,10 @@ func (a *Agent) RunRPC() {
|
|||||||
}()
|
}()
|
||||||
case "installpython":
|
case "installpython":
|
||||||
go a.GetPython(true)
|
go a.GetPython(true)
|
||||||
|
case "installnushell":
|
||||||
|
go a.GetNushell(true)
|
||||||
|
case "installdeno":
|
||||||
|
go a.GetDeno(true)
|
||||||
case "installchoco":
|
case "installchoco":
|
||||||
go a.InstallChoco()
|
go a.InstallChoco()
|
||||||
case "installwithchoco":
|
case "installwithchoco":
|
||||||
|
@ -49,6 +49,9 @@ func (a *Agent) AgentSvc(nc *nats.Conn) {
|
|||||||
a.Logger.Errorln("AgentSvc() createWinTempDir():", err)
|
a.Logger.Errorln("AgentSvc() createWinTempDir():", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
a.GetNushell(false)
|
||||||
|
a.GetDeno(false)
|
||||||
|
|
||||||
a.RunMigrations()
|
a.RunMigrations()
|
||||||
|
|
||||||
sleepDelay := randRange(7, 25)
|
sleepDelay := randRange(7, 25)
|
||||||
|
@ -12,8 +12,10 @@ https://license.tacticalrmm.com
|
|||||||
package agent
|
package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
@ -21,6 +23,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
goDebug "runtime/debug"
|
goDebug "runtime/debug"
|
||||||
@ -280,6 +283,70 @@ func Unzip(src, dest string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractTarGz extracts a tar.gz file to the specified directory.
|
||||||
|
// Returns the extracted directory name.
|
||||||
|
// https://stackoverflow.com/questions/57639648/how-to-decompress-tar-gz-file-in-go
|
||||||
|
func (a *Agent) ExtractTarGz(targz string, destDir string) (extractedDir string, err error) {
|
||||||
|
gzipStream, err := os.Open(targz)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Open() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): NewReader() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
extractedDir = ""
|
||||||
|
tarReader := tar.NewReader(uncompressedStream)
|
||||||
|
for true {
|
||||||
|
header, err := tarReader.Next()
|
||||||
|
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Next() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeDir:
|
||||||
|
if err := os.MkdirAll(path.Join(destDir, header.Name), 0755); err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Mkdir() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if extractedDir == "" {
|
||||||
|
extractedDir = header.Name
|
||||||
|
}
|
||||||
|
case tar.TypeReg:
|
||||||
|
outFile, err := os.Create(path.Join(destDir, header.Name))
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Create() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Copy() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = outFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Close() failed:", err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
a.Logger.Errorln("ExtractTarGz(): Unknown type: %s in %s", header.Typeflag, header.Name)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return extractedDir, nil
|
||||||
|
}
|
||||||
|
|
||||||
// https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/
|
// https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format/
|
||||||
func ByteCountSI(b uint64) string {
|
func ByteCountSI(b uint64) string {
|
||||||
const unit = 1024
|
const unit = 1024
|
||||||
|
4
main.go
4
main.go
@ -117,6 +117,10 @@ func main() {
|
|||||||
fmt.Println(a.PublicIP())
|
fmt.Println(a.PublicIP())
|
||||||
case "getpython":
|
case "getpython":
|
||||||
a.GetPython(true)
|
a.GetPython(true)
|
||||||
|
case "getdeno":
|
||||||
|
a.GetDeno(true)
|
||||||
|
case "getnushell":
|
||||||
|
a.GetNushell(true)
|
||||||
case "runmigrations":
|
case "runmigrations":
|
||||||
a.RunMigrations()
|
a.RunMigrations()
|
||||||
case "recovermesh":
|
case "recovermesh":
|
||||||
|
Loading…
Reference in New Issue
Block a user