mirror of
https://github.com/edgebox-iot/edgeboxctl.git
synced 2026-09-24 05:41:43 +02:00
Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1622ff69b7 | ||
|
|
9339e6cf09 | ||
|
|
92ac9c2b03 | ||
|
|
e611bf2ac4 | ||
|
|
c9f97d42bf | ||
|
|
1736b04a66 | ||
|
|
5d69a9fb22 | ||
|
|
3ef90ffb15 | ||
|
|
1ad554b9bf | ||
|
|
df3f8fe904 | ||
|
|
770e814b6e | ||
|
|
81b545f868 | ||
|
|
9f63ab7f03 | ||
|
|
58b7425fc7 | ||
|
|
f238b3fa46 | ||
|
|
d975710445 | ||
|
|
6cb3e198f0 | ||
|
|
84d7fd6a82 | ||
|
|
e6c07ddeae | ||
|
|
217309f10d | ||
|
|
74cbff1966 | ||
|
|
8f14a7cd15 | ||
|
|
11e9543a87 | ||
|
|
c42d96bf34 | ||
|
|
cb3ecec5f4 | ||
|
|
812cf31dc4 | ||
|
|
0ed5297f6d | ||
|
|
2e92ff53fe |
@@ -12,25 +12,17 @@ jobs:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.15
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
||||
run: make test-with-coverage
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: coverage.out
|
||||
|
||||
@@ -21,6 +21,3 @@ main
|
||||
# Build
|
||||
|
||||
/bin
|
||||
|
||||
# Go Sum files
|
||||
*.sum
|
||||
|
||||
+1
-1
@@ -8,4 +8,4 @@ RUN go mod download
|
||||
|
||||
RUN go get github.com/githubnemo/CompileDaemon
|
||||
|
||||
ENTRYPOINT CompileDaemon --build="make build" --command=./bin/sysctl
|
||||
ENTRYPOINT CompileDaemon --build="make build" --command=./bin/edgeboxctl
|
||||
@@ -1,4 +1,4 @@
|
||||
PROJECT?=github.com/edgebox-iot/sysctl
|
||||
PROJECT?=github.com/edgebox-iot/edgeboxctl
|
||||
|
||||
RELEASE ?= dev
|
||||
COMMIT := $(shell git rev-parse --short HEAD)
|
||||
@@ -9,15 +9,27 @@ build-all:
|
||||
GOOS=linux GOARCH=amd64 make build
|
||||
GOOS=linux GOARCH=arm make build
|
||||
|
||||
build-prod:
|
||||
GOOS=linux GOARCH=arm RELEASE=prod make build
|
||||
|
||||
build-cloud:
|
||||
GDOS=linux GOARCH=amd64 RELEASE=cloud make build
|
||||
|
||||
build:
|
||||
@echo "Building ${GOOS}-${GOARCH}"
|
||||
GOOS=${GOOS} GOARCH=${GOARCH} go build \
|
||||
-trimpath -ldflags "-s -w -X ${PROJECT}/internal/diagnostics.Version=${RELEASE} \
|
||||
-X ${PROJECT}/internal/diagnostics.Commit=${COMMIT} \
|
||||
-X ${PROJECT}/internal/diagnostics.BuildDate=${BUILD_DATE}" \
|
||||
-o bin/sysctl-${GOOS}-${GOARCH} ${PROJECT}/cmd/sysctl
|
||||
cp ./bin/sysctl-${GOOS}-${GOARCH} ./bin/sysctl
|
||||
-o bin/edgeboxctl-${GOOS}-${GOARCH} ${PROJECT}/cmd/edgeboxctl
|
||||
cp ./bin/edgeboxctl-${GOOS}-${GOARCH} ./bin/edgeboxctl
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILD_DIR}
|
||||
go clean
|
||||
|
||||
test:
|
||||
go test -tags=unit -timeout=600s -v ./...
|
||||
|
||||
test-with-coverage:
|
||||
go test -tags=unit -timeout=600s -v ./... -coverprofile=coverage.out
|
||||
|
||||
@@ -23,17 +23,17 @@
|
||||
<img src="docs/img/logo.png" alt="Logo" width="80" height="80">
|
||||
</a>
|
||||
|
||||
<h3 align="center">Edgebox SysCtl Module</h3>
|
||||
<h3 align="center">Edgebox Control Module</h3>
|
||||
|
||||
<p align="center">
|
||||
A System Control module written in Go. Its resonsability is to configure dependencies and perform system tasks, automatically in a schedule, or by command.
|
||||
<br />
|
||||
<a href="https://github.com/github_username/sysctl"><strong>Explore the docs »</strong></a>
|
||||
<a href="https://github.com/github_username/edgeboxctl"><strong>Explore the docs »</strong></a>
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://github.com/github_username/sysctl/issues">Report Bug</a>
|
||||
<a href="https://github.com/github_username/edgeboxctl/issues">Report Bug</a>
|
||||
·
|
||||
<a href="https://github.com/github_username/sysctl/issues">Request Feature</a>
|
||||
<a href="https://github.com/github_username/edgeboxctl/issues">Request Feature</a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@@ -42,15 +42,16 @@
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
## Table of Contents
|
||||
|
||||
* [About the Project](#about-the-project)
|
||||
* [Built With](#built-with)
|
||||
* [Getting Started](#getting-started)
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [Roadmap](#roadmap)
|
||||
* [Contributing](#contributing)
|
||||
* [License](#license)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [About The Project](#about-the-project)
|
||||
- [Built With](#built-with)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
|
||||
|
||||
@@ -88,11 +89,20 @@ sudo apt-get install docker docker-compose
|
||||
|
||||
Check the following links for more info on [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/).
|
||||
|
||||
Aditionally, edgeboxctl needs the following bash commands available wherever it runs:
|
||||
* `arm-linux-gnueabi-gcc` (`sudo apt-get install gcc-arm*`)
|
||||
* `sh`
|
||||
* `rm`
|
||||
* `systemctl`
|
||||
* `lsblk`
|
||||
* `yq`
|
||||
* `tinc-boot` _(not mandatory)_
|
||||
|
||||
### Installation
|
||||
|
||||
1. Clone the repo
|
||||
```sh
|
||||
git clone https://github.com/edgebox-iot/sysctl.git
|
||||
git clone https://github.com/edgebox-iot/edgeboxctl.git
|
||||
```
|
||||
2. Run Docker-Compose
|
||||
```sh
|
||||
@@ -111,7 +121,7 @@ _For more examples, please refer to the [Documentation](https://github.com/edgeb
|
||||
<!-- ROADMAP -->
|
||||
## Roadmap
|
||||
|
||||
See the [open issues](https://github.com/edgebox-iot/sysctl/issues) for a list of proposed features (and known issues).
|
||||
See the [open issues](https://github.com/edgebox-iot/edgeboxctl/issues) for a list of proposed features (and known issues).
|
||||
|
||||
|
||||
|
||||
@@ -136,15 +146,15 @@ Distributed under the MIT License. See `LICENSE` for more information.
|
||||
|
||||
<!-- MARKDOWN LINKS & IMAGES -->
|
||||
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/edgebox-iot/sysctl.svg?style=flat-square
|
||||
[contributors-url]: https://github.com/edgebox-iot/sysctl/graphs/contributors
|
||||
[forks-shield]: https://img.shields.io/github/forks/edgebox-iot/sysctl.svg?style=flat-square
|
||||
[forks-url]: https://github.com/edgebox-iot/sysctl/network/members
|
||||
[stars-shield]: https://img.shields.io/github/stars/edgebox-iot/sysctl.svg?style=flat-square
|
||||
[stars-url]: https://github.com/edgebox-iot/sysctl/stargazers
|
||||
[issues-shield]: https://img.shields.io/github/issues/edgebox-iot/sysctl.svg?style=flat-square
|
||||
[issues-url]: https://github.com/edgebox-iot/sysctl/issues
|
||||
[license-shield]: https://img.shields.io/github/license/edgebox-iot/sysctl.svg?style=flat-square
|
||||
[license-url]: https://github.com/edgebox-iot/sysctl/blob/master/LICENSE.txt
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/edgebox-iot/edgeboxctl.svg?style=flat-square
|
||||
[contributors-url]: https://github.com/edgebox-iot/edgeboxctl/graphs/contributors
|
||||
[forks-shield]: https://img.shields.io/github/forks/edgebox-iot/edgeboxctl.svg?style=flat-square
|
||||
[forks-url]: https://github.com/edgebox-iot/edgeboxctl/network/members
|
||||
[stars-shield]: https://img.shields.io/github/stars/edgebox-iot/edgeboxctl.svg?style=flat-square
|
||||
[stars-url]: https://github.com/edgebox-iot/edgeboxctl/stargazers
|
||||
[issues-shield]: https://img.shields.io/github/issues/edgebox-iot/edgeboxctl.svg?style=flat-square
|
||||
[issues-url]: https://github.com/edgebox-iot/edgeboxctl/issues
|
||||
[license-shield]: https://img.shields.io/github/license/edgebox-iot/edgeboxctl.svg?style=flat-square
|
||||
[license-url]: https://github.com/edgebox-iot/edgeboxctl/blob/master/LICENSE.txt
|
||||
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=flat-square&logo=linkedin&colorB=555
|
||||
[linkedin-url]: https://linkedin.com/in/edgebox-iot
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/edgebox-iot/sysctl/internal/diagnostics"
|
||||
"github.com/edgebox-iot/sysctl/internal/tasks"
|
||||
"github.com/edgebox-iot/sysctl/internal/utils"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/diagnostics"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/tasks"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
||||
)
|
||||
|
||||
const defaultNotReadySleepTime time.Duration = time.Second * 60
|
||||
@@ -37,7 +37,7 @@ func main() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log.Printf("Starting Sysctl service for %s", *name)
|
||||
log.Printf("Starting edgeboxctl service for %s", *name)
|
||||
|
||||
// setup signal catching
|
||||
sigs := make(chan os.Signal, 1)
|
||||
@@ -74,7 +74,6 @@ func main() {
|
||||
time.Sleep(defaultNotReadySleepTime)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,8 +92,8 @@ func printVersion() {
|
||||
|
||||
func printDbDetails() {
|
||||
fmt.Printf(
|
||||
"\n\nDatabase Connection Information:\n %s\n\n",
|
||||
utils.GetMySQLDbConnectionDetails(),
|
||||
"\n\nSQLite Database Location:\n %s\n\n",
|
||||
utils.GetSQLiteDbConnectionDetails(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,7 +115,11 @@ func systemIterator(name *string, tick int) {
|
||||
tasks.ExecuteSchedules(tick)
|
||||
nextTask := tasks.GetNextTask()
|
||||
if nextTask.Task != "" {
|
||||
log.Printf("Executing task %s / Args: %s", nextTask.Task, nextTask.Args)
|
||||
taskArguments := "No arguments"
|
||||
if nextTask.Args.Valid {
|
||||
taskArguments = nextTask.Args.String
|
||||
}
|
||||
log.Printf("Executing task %s / Args: %s", nextTask.Task, taskArguments)
|
||||
tasks.ExecuteTask(nextTask)
|
||||
} else {
|
||||
log.Printf("No tasks to execute.")
|
||||
@@ -0,0 +1,4 @@
|
||||
codecov:
|
||||
require_ci_to_pass: no
|
||||
|
||||
comment: false
|
||||
@@ -1,9 +1,17 @@
|
||||
module github.com/edgebox-iot/sysctl
|
||||
module github.com/edgebox-iot/edgeboxctl
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/dariubs/percent v0.0.0-20200128140941-b7801cf1c7e2 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/mattn/go-sqlite3 v1.14.7 // indirect
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/dariubs/percent v0.0.0-20200128140941-b7801cf1c7e2 h1:5EPE4Uk7ucthLTJAZqZxu6LZluox5/AqXUxJDpzgJjg=
|
||||
github.com/dariubs/percent v0.0.0-20200128140941-b7801cf1c7e2/go.mod h1:NDZpkezJ8QqyIW/510MywB5T2KdC8v/0oTlEoPcMsRM=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible h1:fuHcTm5mX+wzo542cmYcV9RTGQLbnHLI5SyQ5ryTVck=
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tklauser/go-sysconf v0.3.6 h1:oc1sJWvKkmvIxhDHeKWvZS4f6AW+YcoguSfRF2/Hmo4=
|
||||
github.com/tklauser/go-sysconf v0.3.6/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
|
||||
github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA=
|
||||
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 h1:OL5GcZ2XPkte3dpfuFQ9o884vrE3BZQhajdntNMruv4=
|
||||
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
@@ -9,13 +9,14 @@ import (
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"github.com/edgebox-iot/sysctl/internal/utils"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
||||
)
|
||||
|
||||
// EdgeApp : Struct representing an EdgeApp in the system
|
||||
type EdgeApp struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Status EdgeAppStatus `json:"status"`
|
||||
Services []EdgeAppService `json:"services"`
|
||||
InternetAccessible bool `json:"internet_accessible"`
|
||||
@@ -43,6 +44,7 @@ type EdgeAppService struct {
|
||||
|
||||
const configFilename = "/edgebox-compose.yml"
|
||||
const envFilename = "/edgebox.env"
|
||||
const runnableFilename = "/.run"
|
||||
const myEdgeAppServiceEnvFilename = "/myedgeapp.env"
|
||||
const defaultContainerOperationSleepTime time.Duration = time.Second * 10
|
||||
|
||||
@@ -59,6 +61,7 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||
// File exists. Start digging!
|
||||
|
||||
edgeAppName := ID
|
||||
edgeAppDescription := ""
|
||||
|
||||
edgeAppEnv, err := godotenv.Read(utils.GetPath("edgeAppsPath") + ID + envFilename)
|
||||
|
||||
@@ -68,6 +71,9 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||
if edgeAppEnv["EDGEAPP_NAME"] != "" {
|
||||
edgeAppName = edgeAppEnv["EDGEAPP_NAME"]
|
||||
}
|
||||
if edgeAppEnv["EDGEAPP_DESCRIPTION"] != "" {
|
||||
edgeAppDescription = edgeAppEnv["EDGEAPP_DESCRIPTION"]
|
||||
}
|
||||
}
|
||||
|
||||
edgeAppInternetAccessible := false
|
||||
@@ -87,6 +93,7 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||
EdgeApp: EdgeApp{
|
||||
ID: ID,
|
||||
Name: edgeAppName,
|
||||
Description: edgeAppDescription,
|
||||
Status: GetEdgeAppStatus(ID),
|
||||
Services: GetEdgeAppServices(ID),
|
||||
InternetAccessible: edgeAppInternetAccessible,
|
||||
@@ -102,6 +109,62 @@ func GetEdgeApp(ID string) MaybeEdgeApp {
|
||||
|
||||
}
|
||||
|
||||
func IsEdgeAppInstalled(ID string) bool {
|
||||
|
||||
result := false
|
||||
|
||||
_, err := os.Stat(utils.GetPath("edgeAppsPath") + ID + runnableFilename)
|
||||
if !os.IsNotExist(err) {
|
||||
result = true
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
func SetEdgeAppInstalled(ID string) bool {
|
||||
|
||||
result := true
|
||||
|
||||
_, err := os.Stat(utils.GetPath("edgeAppsPath") + ID + runnableFilename)
|
||||
if os.IsNotExist(err) {
|
||||
|
||||
_, err := os.Create(utils.GetPath("edgeAppsPath") + ID + runnableFilename)
|
||||
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
|
||||
err := os.Remove(utils.GetPath("edgeAppsPath") + ID + runnableFilename)
|
||||
if err != nil {
|
||||
result = false
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
buildFrameworkContainers()
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
// GetEdgeApps : Returns a list of all available EdgeApps in structs filled with information
|
||||
func GetEdgeApps() []EdgeApp {
|
||||
|
||||
@@ -142,20 +205,30 @@ func GetEdgeAppStatus(ID string) EdgeAppStatus {
|
||||
// - No service running = EdgeApp is off
|
||||
|
||||
runningServices := 0
|
||||
|
||||
status := EdgeAppStatus{0, "off"}
|
||||
services := GetEdgeAppServices(ID)
|
||||
for _, edgeAppService := range services {
|
||||
if edgeAppService.IsRunning {
|
||||
runningServices++
|
||||
|
||||
if !IsEdgeAppInstalled(ID) {
|
||||
|
||||
status = EdgeAppStatus{-1, "not-installed"}
|
||||
|
||||
} else {
|
||||
|
||||
services := GetEdgeAppServices(ID)
|
||||
for _, edgeAppService := range services {
|
||||
if edgeAppService.IsRunning {
|
||||
runningServices++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if runningServices > 0 && runningServices != len(services) {
|
||||
status = EdgeAppStatus{2, "error"}
|
||||
}
|
||||
if runningServices > 0 && runningServices != len(services) {
|
||||
status = EdgeAppStatus{2, "error"}
|
||||
}
|
||||
|
||||
if runningServices == len(services) {
|
||||
status = EdgeAppStatus{1, "on"}
|
||||
}
|
||||
|
||||
if runningServices == len(services) {
|
||||
status = EdgeAppStatus{1, "on"}
|
||||
}
|
||||
|
||||
return status
|
||||
@@ -166,14 +239,14 @@ func GetEdgeAppStatus(ID string) EdgeAppStatus {
|
||||
func GetEdgeAppServices(ID string) []EdgeAppService {
|
||||
|
||||
cmdArgs := []string{"-r", ".services | keys[]", utils.GetPath("edgeAppsPath") + ID + configFilename}
|
||||
servicesString := utils.Exec("yq", cmdArgs)
|
||||
servicesString := utils.Exec(utils.GetPath("wsPath"), "yq", cmdArgs)
|
||||
serviceSlices := strings.Split(servicesString, "\n")
|
||||
serviceSlices = utils.DeleteEmptySlices(serviceSlices)
|
||||
var edgeAppServices []EdgeAppService
|
||||
|
||||
for _, serviceID := range serviceSlices {
|
||||
cmdArgs = []string{"-f", utils.GetPath("wsPath") + "/docker-compose.yml", "exec", "-T", serviceID, "echo", "'Service Check'"}
|
||||
cmdResult := utils.Exec("docker-compose", cmdArgs)
|
||||
cmdResult := utils.Exec(utils.GetPath("wsPath"), "docker-compose", cmdArgs)
|
||||
isRunning := false
|
||||
if cmdResult != "" {
|
||||
isRunning = true
|
||||
@@ -195,7 +268,7 @@ func RunEdgeApp(ID string) EdgeAppStatus {
|
||||
for _, service := range services {
|
||||
|
||||
cmdArgs = []string{"-f", utils.GetPath("wsPath") + "/docker-compose.yml", "start", service.ID}
|
||||
utils.Exec("docker-compose", cmdArgs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "docker-compose", cmdArgs)
|
||||
|
||||
}
|
||||
|
||||
@@ -216,7 +289,7 @@ func StopEdgeApp(ID string) EdgeAppStatus {
|
||||
for _, service := range services {
|
||||
|
||||
cmdArgs = []string{"-f", utils.GetPath("wsPath") + "/docker-compose.yml", "stop", service.ID}
|
||||
utils.Exec("docker-compose", cmdArgs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "docker-compose", cmdArgs)
|
||||
|
||||
}
|
||||
|
||||
@@ -253,7 +326,7 @@ func DisableOnline(ID string) MaybeEdgeApp {
|
||||
log.Println("myedge.app environment file for " + ID + " not found. No need to delete.")
|
||||
} else {
|
||||
cmdArgs := []string{envFilePath}
|
||||
utils.Exec("rm", cmdArgs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "rm", cmdArgs)
|
||||
}
|
||||
|
||||
buildFrameworkContainers()
|
||||
@@ -265,7 +338,7 @@ func DisableOnline(ID string) MaybeEdgeApp {
|
||||
func buildFrameworkContainers() {
|
||||
|
||||
cmdArgs := []string{utils.GetPath("wsPath") + "ws", "--build"}
|
||||
utils.ExecAndStream("sh", cmdArgs)
|
||||
utils.ExecAndStream(utils.GetPath("wsPath"), "sh", cmdArgs)
|
||||
|
||||
time.Sleep(defaultContainerOperationSleepTime)
|
||||
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
||||
"github.com/shirou/gopsutil/disk"
|
||||
)
|
||||
|
||||
// Device : Struct representing a storage device in the system
|
||||
type Device struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Size string `json:"size"`
|
||||
InUse bool `json:"in_use"`
|
||||
MainDevice bool `json:"main_device"`
|
||||
MAJ string `json:"maj"`
|
||||
MIN string `json:"min"`
|
||||
RM string `json:"rm"`
|
||||
RO string `json:"ro"`
|
||||
Partitions []Partition `json:"partitions"`
|
||||
Status DeviceStatus `json:"status"`
|
||||
UsageStat UsageStat `json:"usage_stat"`
|
||||
}
|
||||
|
||||
// DeviceStatus : Struct representing possible storage device statuses (code + description)
|
||||
type DeviceStatus struct {
|
||||
ID int `json:"id"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// MaybeDevice : Boolean flag for validation of device existance
|
||||
type MaybeDevice struct {
|
||||
Device Device `json:"device"`
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
type UsageStat struct {
|
||||
Total uint64 `json:"total"`
|
||||
Used uint64 `json:"used"`
|
||||
Free uint64 `json:"free"`
|
||||
Percent string `json:"percent"`
|
||||
UsageSplit UsageSplit `json:"usage_split"`
|
||||
}
|
||||
|
||||
type UsageSplit struct {
|
||||
OS uint64 `json:"os"`
|
||||
EdgeApps uint64 `json:"edgeapps"`
|
||||
Buckets uint64 `json:"buckets"`
|
||||
Others uint64 `json:"others"`
|
||||
}
|
||||
|
||||
// Partition : Struct representing a partition / filesystem (Empty Mountpoint means it is not mounted)
|
||||
type Partition struct {
|
||||
ID string `json:"id"`
|
||||
Size string `json:"size"`
|
||||
MAJ string `json:"maj"`
|
||||
MIN string `json:"min"`
|
||||
RM string `json:"rm"`
|
||||
RO string `json:"ro"`
|
||||
Filesystem string `json:"filesystem"`
|
||||
Mountpoint string `json:"mountpoint"`
|
||||
UsageStat UsageStat `json:"usage_stat"`
|
||||
}
|
||||
|
||||
const mainDiskID = "mmcblk0"
|
||||
|
||||
// GetDevices : Returns a list of all available sotrage devices in structs filled with information
|
||||
func GetDevices() []Device {
|
||||
|
||||
var devices []Device
|
||||
|
||||
cmdArgs := []string{"--raw", "--bytes", "--noheadings"}
|
||||
scanner := utils.ExecAndGetLines("/", "lsblk", cmdArgs)
|
||||
|
||||
var currentDevice Device
|
||||
var currentPartitions []Partition
|
||||
|
||||
firstDevice := true
|
||||
currentDeviceInUseFlag := false
|
||||
|
||||
for scanner.Scan() {
|
||||
// 1 Device is represented here. Extract words in order for filling a Device struct
|
||||
// Example deviceRawInfo: "mmcblk0 179:0 0 29.7G 0 disk"
|
||||
deviceRawInfo := strings.Fields(scanner.Text())
|
||||
majMin := strings.SplitN(deviceRawInfo[1], ":", 2)
|
||||
|
||||
isDevice := false
|
||||
isPartition := false
|
||||
if deviceRawInfo[5] == "part" {
|
||||
isDevice = false
|
||||
isPartition = true
|
||||
|
||||
} else if deviceRawInfo[5] == "disk" {
|
||||
isDevice = true
|
||||
isPartition = false
|
||||
}
|
||||
|
||||
if isDevice {
|
||||
// Clean up on the latest device being prepared. Append all partitions found and delete the currentPartitions list afterwards.
|
||||
// The first device found should not run the cleanup lines below
|
||||
|
||||
if !firstDevice {
|
||||
currentDevice.Partitions = currentPartitions
|
||||
|
||||
if !currentDeviceInUseFlag {
|
||||
currentDevice.Status.ID = 0
|
||||
currentDevice.Status.Description = "not configured"
|
||||
}
|
||||
|
||||
currentDevice.InUse = currentDeviceInUseFlag
|
||||
currentDeviceInUseFlag = false
|
||||
currentPartitions = []Partition{}
|
||||
devices = append(devices, currentDevice)
|
||||
} else {
|
||||
firstDevice = false
|
||||
}
|
||||
|
||||
mainDevice := false
|
||||
|
||||
device := Device{
|
||||
ID: deviceRawInfo[0],
|
||||
Name: deviceRawInfo[0],
|
||||
Size: deviceRawInfo[3],
|
||||
MainDevice: mainDevice,
|
||||
MAJ: majMin[0],
|
||||
MIN: majMin[1],
|
||||
RM: deviceRawInfo[2],
|
||||
RO: deviceRawInfo[4],
|
||||
Status: DeviceStatus{ID: 1, Description: "healthy"},
|
||||
}
|
||||
|
||||
if device.ID == mainDiskID {
|
||||
device.MainDevice = true
|
||||
}
|
||||
|
||||
currentDevice = device
|
||||
|
||||
} else if isPartition {
|
||||
|
||||
mountpoint := ""
|
||||
if len(deviceRawInfo) >= 7 {
|
||||
mountpoint = deviceRawInfo[6]
|
||||
currentDeviceInUseFlag = true
|
||||
}
|
||||
|
||||
// It is a partition, part of the last device read.
|
||||
partition := Partition{
|
||||
ID: deviceRawInfo[0],
|
||||
Size: deviceRawInfo[3],
|
||||
MAJ: majMin[0],
|
||||
MIN: majMin[1],
|
||||
RM: deviceRawInfo[2],
|
||||
RO: deviceRawInfo[4],
|
||||
Filesystem: "",
|
||||
Mountpoint: mountpoint,
|
||||
}
|
||||
|
||||
currentPartitions = append(currentPartitions, partition)
|
||||
|
||||
} else {
|
||||
fmt.Println("Found device not compatible with Edgebox, ignoring.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
currentDevice.Partitions = currentPartitions
|
||||
if !currentDeviceInUseFlag {
|
||||
currentDevice.Status.ID = 0
|
||||
currentDevice.Status.Description = "Not configured"
|
||||
}
|
||||
currentDevice.InUse = currentDeviceInUseFlag
|
||||
devices = append([]Device{currentDevice}, devices...) // Prepending the first device...
|
||||
|
||||
devices = getDevicesSpaceUsage(devices)
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
func getDevicesSpaceUsage(devices []Device) []Device {
|
||||
|
||||
for deviceIndex, device := range devices {
|
||||
|
||||
if device.InUse {
|
||||
|
||||
deviceUsageStat := UsageStat{}
|
||||
|
||||
for partitionIndex, partition := range device.Partitions {
|
||||
|
||||
if partition.Mountpoint != "" {
|
||||
|
||||
s, _ := disk.Usage(partition.Mountpoint)
|
||||
|
||||
if s.Total == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
partitionUsagePercent := fmt.Sprintf("%2.f%%", s.UsedPercent)
|
||||
osUsageSplit := (uint64)(0)
|
||||
edgeappsUsageSplit := (uint64)(0)
|
||||
bucketsUsageSplit := (uint64)(0)
|
||||
othersUsageSplit := (uint64)(0)
|
||||
|
||||
edgeappsDirSize, _ := getDirSize(utils.GetPath("edgeAppsPath"))
|
||||
// TODO for later: Figure out to get correct paths for each partition...
|
||||
wsAppDataDirSize, _ := getDirSize("/home/system/components/ws/appdata")
|
||||
|
||||
if partition.Mountpoint == "/" {
|
||||
edgeappsUsageSplit = edgeappsDirSize + wsAppDataDirSize
|
||||
deviceUsageStat.UsageSplit.EdgeApps += edgeappsUsageSplit
|
||||
}
|
||||
|
||||
if device.MainDevice {
|
||||
osUsageSplit = (s.Used - othersUsageSplit - bucketsUsageSplit - edgeappsUsageSplit)
|
||||
} else {
|
||||
othersUsageSplit = (s.Used - bucketsUsageSplit - edgeappsUsageSplit)
|
||||
}
|
||||
|
||||
partitionUsageSplit := UsageSplit{
|
||||
OS: osUsageSplit,
|
||||
EdgeApps: edgeappsUsageSplit,
|
||||
Buckets: bucketsUsageSplit,
|
||||
Others: othersUsageSplit,
|
||||
}
|
||||
|
||||
deviceUsageStat.Total = deviceUsageStat.Total + s.Total
|
||||
deviceUsageStat.Used = deviceUsageStat.Used + s.Used
|
||||
deviceUsageStat.Free = deviceUsageStat.Free + s.Free
|
||||
deviceUsageStat.UsageSplit.OS = deviceUsageStat.UsageSplit.OS + osUsageSplit
|
||||
deviceUsageStat.UsageSplit.EdgeApps = deviceUsageStat.UsageSplit.EdgeApps + edgeappsUsageSplit
|
||||
deviceUsageStat.UsageSplit.Buckets = deviceUsageStat.UsageSplit.Buckets + bucketsUsageSplit
|
||||
deviceUsageStat.UsageSplit.Others = deviceUsageStat.UsageSplit.Others + othersUsageSplit
|
||||
|
||||
devices[deviceIndex].Partitions[partitionIndex].UsageStat = UsageStat{
|
||||
Total: s.Total,
|
||||
Used: s.Used,
|
||||
Free: s.Free,
|
||||
Percent: partitionUsagePercent,
|
||||
UsageSplit: partitionUsageSplit,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
devices[deviceIndex].UsageStat = deviceUsageStat
|
||||
totalDevicePercentUsage := fmt.Sprintf("%2.f%%", (float32(devices[deviceIndex].UsageStat.Used)/float32(devices[deviceIndex].UsageStat.Total))*100)
|
||||
devices[deviceIndex].UsageStat.Percent = totalDevicePercentUsage
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
func getDirSize(path string) (uint64, error) {
|
||||
var size uint64
|
||||
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
size += (uint64)(info.Size())
|
||||
}
|
||||
return err
|
||||
})
|
||||
return size, err
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// +build unit
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDevices(t *testing.T) {
|
||||
result := GetDevices()
|
||||
|
||||
if len(result) == 0 {
|
||||
t.Log("Expecting at least 1 block device, 0 elements found in slice")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
foundDevice := false
|
||||
|
||||
t.Log("Looking for a mmcblk0 or sda device")
|
||||
for _, device := range result {
|
||||
if device.ID == "mmcblk0" || device.ID == "sda" {
|
||||
t.Log("Found target device", device.ID)
|
||||
foundDevice = true
|
||||
}
|
||||
}
|
||||
|
||||
if !foundDevice {
|
||||
t.Log("Expected to find device mmcblk0 but did not. Devices:", result)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/shirou/gopsutil/host"
|
||||
)
|
||||
|
||||
func GetUptimeInSeconds() string {
|
||||
uptime, _ := host.Uptime()
|
||||
|
||||
return strconv.FormatUint(uptime, 10)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
+196
-35
@@ -6,18 +6,22 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/edgebox-iot/sysctl/internal/diagnostics"
|
||||
"github.com/edgebox-iot/sysctl/internal/edgeapps"
|
||||
"github.com/edgebox-iot/sysctl/internal/utils"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/diagnostics"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/edgeapps"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/storage"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/system"
|
||||
"github.com/edgebox-iot/edgeboxctl/internal/utils"
|
||||
_ "github.com/go-sql-driver/mysql" // Mysql Driver
|
||||
_ "github.com/mattn/go-sqlite3" // SQlite Driver
|
||||
)
|
||||
|
||||
// Task : Struct for Task type
|
||||
type Task struct {
|
||||
ID int `json:"id"`
|
||||
Task string `json:"task"`
|
||||
Args string `json:"args"`
|
||||
Args sql.NullString `json:"args"` // Database fields that can be null must use the sql.NullString type
|
||||
Status string `json:"status"`
|
||||
Result sql.NullString `json:"result"` // Database fields that can be null must use the sql.NullString type
|
||||
Created string `json:"created"`
|
||||
@@ -35,6 +39,14 @@ type taskStartEdgeAppArgs struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type taskInstallEdgeAppArgs struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type taskRemoveEdgeAppArgs struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
type taskStopEdgeAppArgs struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
@@ -52,18 +64,14 @@ type taskDisableOnlineArgs struct {
|
||||
func GetNextTask() Task {
|
||||
|
||||
// Will try to connect to API database, which should be running locally under WS.
|
||||
db, err := sql.Open("mysql", utils.GetMySQLDbConnectionDetails())
|
||||
db, err := sql.Open("sqlite3", utils.GetSQLiteDbConnectionDetails())
|
||||
|
||||
// if there is an error opening the connection, handle it
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
// defer the close till after the main function has finished executing
|
||||
defer db.Close()
|
||||
|
||||
// perform a db.Query insert
|
||||
results, err := db.Query("SELECT * FROM tasks WHERE status = 0 ORDER BY created ASC LIMIT 1;")
|
||||
results, err := db.Query("SELECT id, task, args, status, result, created, updated FROM task WHERE status = 0 ORDER BY created ASC LIMIT 1;")
|
||||
|
||||
// if there is an error inserting, handle it
|
||||
if err != nil {
|
||||
@@ -81,8 +89,8 @@ func GetNextTask() Task {
|
||||
}
|
||||
}
|
||||
|
||||
// be careful deferring Queries if you are using transactions
|
||||
defer results.Close()
|
||||
results.Close()
|
||||
db.Close()
|
||||
|
||||
return task
|
||||
|
||||
@@ -91,18 +99,22 @@ func GetNextTask() Task {
|
||||
// ExecuteTask : Performs execution of the given task, updating the task status as it goes, and publishing the task result
|
||||
func ExecuteTask(task Task) Task {
|
||||
|
||||
db, err := sql.Open("mysql", utils.GetMySQLDbConnectionDetails())
|
||||
db, err := sql.Open("sqlite3", utils.GetSQLiteDbConnectionDetails())
|
||||
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Query("UPDATE tasks SET status = 1 WHERE ID = " + strconv.Itoa(task.ID))
|
||||
|
||||
statement, err := db.Prepare("UPDATE task SET status = ?, updated = ? WHERE ID = ?;") // Prepare SQL Statement
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
||||
|
||||
_, err = statement.Exec(1, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if diagnostics.Version == "dev" {
|
||||
@@ -114,7 +126,7 @@ func ExecuteTask(task Task) Task {
|
||||
|
||||
log.Println("Setting up bootnode connection...")
|
||||
var args taskSetupTunnelArgs
|
||||
err := json.Unmarshal([]byte(task.Args), &args)
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of setup_bootnode task: %s", err)
|
||||
} else {
|
||||
@@ -122,11 +134,35 @@ func ExecuteTask(task Task) Task {
|
||||
task.Result = sql.NullString{String: taskResult, Valid: true}
|
||||
}
|
||||
|
||||
case "install_edgeapp":
|
||||
|
||||
log.Println("Installing EdgeApp...")
|
||||
var args taskInstallEdgeAppArgs
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of install_edgeapp task: %s", err)
|
||||
} else {
|
||||
taskResult := taskInstallEdgeApp(args)
|
||||
task.Result = sql.NullString{String: taskResult, Valid: true}
|
||||
}
|
||||
|
||||
case "remove_edgeapp":
|
||||
|
||||
log.Println("Removing EdgeApp...")
|
||||
var args taskRemoveEdgeAppArgs
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of remove_edgeapp task: %s", err)
|
||||
} else {
|
||||
taskResult := taskRemoveEdgeApp(args)
|
||||
task.Result = sql.NullString{String: taskResult, Valid: true}
|
||||
}
|
||||
|
||||
case "start_edgeapp":
|
||||
|
||||
log.Println("Starting EdgeApp...")
|
||||
var args taskStartEdgeAppArgs
|
||||
err := json.Unmarshal([]byte(task.Args), &args)
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of start_edgeapp task: %s", err)
|
||||
} else {
|
||||
@@ -138,7 +174,7 @@ func ExecuteTask(task Task) Task {
|
||||
|
||||
log.Println("Stopping EdgeApp...")
|
||||
var args taskStopEdgeAppArgs
|
||||
err := json.Unmarshal([]byte(task.Args), &args)
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of stop_edgeapp task: %s", err)
|
||||
} else {
|
||||
@@ -150,7 +186,7 @@ func ExecuteTask(task Task) Task {
|
||||
|
||||
log.Println("Enabling online access to EdgeApp...")
|
||||
var args taskEnableOnlineArgs
|
||||
err := json.Unmarshal([]byte(task.Args), &args)
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of enable_online task: %s", err)
|
||||
} else {
|
||||
@@ -162,7 +198,7 @@ func ExecuteTask(task Task) Task {
|
||||
|
||||
log.Println("Disabling online access to EdgeApp...")
|
||||
var args taskDisableOnlineArgs
|
||||
err := json.Unmarshal([]byte(task.Args), &args)
|
||||
err := json.Unmarshal([]byte(task.Args.String), &args)
|
||||
if err != nil {
|
||||
log.Printf("Error reading arguments of enable_online task: %s", err)
|
||||
} else {
|
||||
@@ -174,16 +210,35 @@ func ExecuteTask(task Task) Task {
|
||||
|
||||
}
|
||||
|
||||
statement, err = db.Prepare("Update task SET status = ?, result = ?, updated = ? WHERE ID = ?;") // Prepare SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
formatedDatetime = utils.GetSQLiteFormattedDateTime(time.Now())
|
||||
|
||||
if task.Result.Valid {
|
||||
db.Query("Update tasks SET status = 2, result = '" + task.Result.String + "' WHERE ID = " + strconv.Itoa(task.ID) + ";")
|
||||
_, err = statement.Exec(2, task.Result.String, formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with result info
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
} else {
|
||||
db.Query("Update tasks SET status = 3, result = 'Error' WHERE ID = " + strconv.Itoa(task.ID) + ";")
|
||||
_, err = statement.Exec(3, "Error", formatedDatetime, strconv.Itoa(task.ID)) // Execute SQL Statement with Error info
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
db.Close()
|
||||
|
||||
returnTask := task
|
||||
|
||||
return returnTask
|
||||
@@ -194,8 +249,19 @@ func ExecuteTask(task Task) Task {
|
||||
func ExecuteSchedules(tick int) {
|
||||
|
||||
if tick == 1 {
|
||||
|
||||
// Executing on startup (first tick). Schedules run before tasks in the SystemIterator
|
||||
uptime := taskGetSystemUptime()
|
||||
log.Println("Uptime is " + uptime + " seconds (" + system.GetUptimeFormatted() + ")")
|
||||
|
||||
log.Println(taskGetStorageDevices())
|
||||
log.Println(taskGetEdgeApps())
|
||||
|
||||
}
|
||||
|
||||
if tick%5 == 0 {
|
||||
// Executing every 5 ticks
|
||||
log.Println(taskGetStorageDevices())
|
||||
}
|
||||
|
||||
if tick%30 == 0 {
|
||||
@@ -218,19 +284,49 @@ func taskSetupTunnel(args taskSetupTunnelArgs) string {
|
||||
fmt.Println("Executing taskSetupTunnel")
|
||||
|
||||
cmdargs := []string{"gen", "--name", args.NodeName, "--token", args.BootnodeToken, args.BootnodeAddress + ":8655", "--prefix", args.AssignedAddress}
|
||||
utils.Exec("tinc-boot", cmdargs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "tinc-boot", cmdargs)
|
||||
|
||||
cmdargs = []string{"start", "tinc@dnet"}
|
||||
utils.Exec("systemctl", cmdargs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "systemctl", cmdargs)
|
||||
|
||||
cmdargs = []string{"enable", "tinc@dnet"}
|
||||
utils.Exec("systemctl", cmdargs)
|
||||
utils.Exec(utils.GetPath("wsPath"), "systemctl", cmdargs)
|
||||
|
||||
output := "OK" // Better check / logging of command execution result.
|
||||
return output
|
||||
|
||||
}
|
||||
|
||||
func taskInstallEdgeApp(args taskInstallEdgeAppArgs) string {
|
||||
|
||||
fmt.Println("Executing taskInstallEdgeApp for " + args.ID)
|
||||
|
||||
result := edgeapps.SetEdgeAppInstalled(args.ID)
|
||||
|
||||
resultJSON, _ := json.Marshal(result)
|
||||
|
||||
taskGetEdgeApps()
|
||||
|
||||
return string(resultJSON)
|
||||
|
||||
}
|
||||
|
||||
func taskRemoveEdgeApp(args taskRemoveEdgeAppArgs) string {
|
||||
|
||||
fmt.Println("Executing taskRemoveEdgeApp for " + args.ID)
|
||||
|
||||
// Making sure the application is stopped before setting it as removed.
|
||||
edgeapps.StopEdgeApp(args.ID)
|
||||
result := edgeapps.SetEdgeAppNotInstalled(args.ID)
|
||||
|
||||
resultJSON, _ := json.Marshal(result)
|
||||
|
||||
taskGetEdgeApps()
|
||||
|
||||
return string(resultJSON)
|
||||
|
||||
}
|
||||
|
||||
func taskStartEdgeApp(args taskStartEdgeAppArgs) string {
|
||||
|
||||
fmt.Println("Executing taskStartEdgeApp for " + args.ID)
|
||||
@@ -294,20 +390,85 @@ func taskGetEdgeApps() string {
|
||||
edgeApps := edgeapps.GetEdgeApps()
|
||||
edgeAppsJSON, _ := json.Marshal(edgeApps)
|
||||
|
||||
db, err := sql.Open("mysql", utils.GetMySQLDbConnectionDetails())
|
||||
db, err := sql.Open("sqlite3", utils.GetSQLiteDbConnectionDetails())
|
||||
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
_, err = db.Query("REPLACE into options (name, value) VALUES ('EDGEAPPS_LIST','" + string(edgeAppsJSON) + "');")
|
||||
|
||||
statement, err := db.Prepare("REPLACE into option (name, value, created, updated) VALUES (?, ?, ?, ?);") // Prepare SQL Statement
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
||||
|
||||
_, err = statement.Exec("EDGEAPPS_LIST", string(edgeAppsJSON), formatedDatetime, formatedDatetime) // Execute SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
db.Close()
|
||||
|
||||
return string(edgeAppsJSON)
|
||||
|
||||
}
|
||||
|
||||
func taskGetSystemUptime() string {
|
||||
fmt.Println("Executing taskGetSystemUptime")
|
||||
|
||||
uptime := system.GetUptimeInSeconds()
|
||||
|
||||
db, err := sql.Open("sqlite3", utils.GetSQLiteDbConnectionDetails())
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
statement, err := db.Prepare("REPLACE into option (name, value, created, updated) VALUES (?, ?, ?, ?);") // Prepare SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
||||
|
||||
_, err = statement.Exec("SYSTEM_UPTIME", uptime, formatedDatetime, formatedDatetime) // Execute SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
db.Close()
|
||||
|
||||
return uptime
|
||||
|
||||
}
|
||||
|
||||
func taskGetStorageDevices() string {
|
||||
fmt.Println("Executing taskGetStorageDevices")
|
||||
|
||||
devices := storage.GetDevices()
|
||||
devicesJSON, _ := json.Marshal(devices)
|
||||
|
||||
db, err := sql.Open("sqlite3", utils.GetSQLiteDbConnectionDetails())
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
statement, err := db.Prepare("REPLACE into option (name, value, created, updated) VALUES (?, ?, ?, ?);") // Prepare SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
formatedDatetime := utils.GetSQLiteFormattedDateTime(time.Now())
|
||||
|
||||
_, err = statement.Exec("STORAGE_DEVICES_LIST", devicesJSON, formatedDatetime, formatedDatetime) // Execute SQL Statement
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
db.Close()
|
||||
|
||||
return string(devicesJSON)
|
||||
|
||||
}
|
||||
|
||||
+32
-16
@@ -1,30 +1,33 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
// ExecAndStream : Runs a terminal command, but streams progress instead of outputting. Ideal for long lived process that need to be logged.
|
||||
func ExecAndStream(command string, args []string) {
|
||||
func ExecAndStream(path string, command string, args []string) {
|
||||
|
||||
cmd := exec.Command(command, args...)
|
||||
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
|
||||
cmd.Dir = GetPath("wsPath")
|
||||
cmd.Dir = path
|
||||
|
||||
err := cmd.Run()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("cmd.Run() failed with %s\n", err)
|
||||
fmt.Printf("cmd.Run() failed with %s\n", err)
|
||||
}
|
||||
|
||||
outStr, errStr := string(stdoutBuf.Bytes()), string(stderrBuf.Bytes())
|
||||
@@ -33,13 +36,13 @@ func ExecAndStream(command string, args []string) {
|
||||
}
|
||||
|
||||
// Exec : Runs a terminal Command, catches and logs errors, returns the result.
|
||||
func Exec(command string, args []string) string {
|
||||
func Exec(path string, command string, args []string) string {
|
||||
cmd := exec.Command(command, args...)
|
||||
var out bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &stderr
|
||||
cmd.Dir = GetPath("wsPath")
|
||||
cmd.Dir = path
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
// TODO: Deal with possibility of error in command, allow explicit error handling and return proper formatted stderr
|
||||
@@ -48,10 +51,20 @@ func Exec(command string, args []string) string {
|
||||
|
||||
// log.Println("Result: " + out.String()) // ... Silence ...
|
||||
|
||||
return out.String()
|
||||
return strings.Trim(out.String(), " \n")
|
||||
|
||||
}
|
||||
|
||||
// Exec : Runs a terminal Command, returns the result as a *bufio.Scanner type, split in lines and ready to parse.
|
||||
func ExecAndGetLines(path string, command string, args []string) *bufio.Scanner {
|
||||
cmdOutput := Exec(path, command, args)
|
||||
cmdOutputReader := strings.NewReader(cmdOutput)
|
||||
scanner := bufio.NewScanner(cmdOutputReader)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
return scanner
|
||||
}
|
||||
|
||||
// DeleteEmptySlices : Given a string array, delete empty entries.
|
||||
func DeleteEmptySlices(s []string) []string {
|
||||
var r []string
|
||||
@@ -63,8 +76,8 @@ func DeleteEmptySlices(s []string) []string {
|
||||
return r
|
||||
}
|
||||
|
||||
// GetMySQLDbConnectionDetails : Returns the necessary string as connection info for SQL.db()
|
||||
func GetMySQLDbConnectionDetails() string {
|
||||
// GetSQLiteDbConnectionDetails : Returns the necessary string as connection info for SQL.db()
|
||||
func GetSQLiteDbConnectionDetails() string {
|
||||
|
||||
var apiEnv map[string]string
|
||||
apiEnv, err := godotenv.Read(GetPath("apiEnvFileLocation"))
|
||||
@@ -73,13 +86,17 @@ func GetMySQLDbConnectionDetails() string {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
|
||||
Dbhost := "127.0.0.1:" + apiEnv["HOST_MACHINE_MYSQL_PORT"]
|
||||
Dbname := apiEnv["MYSQL_DATABASE"]
|
||||
Dbuser := apiEnv["MYSQL_USER"]
|
||||
Dbpass := apiEnv["MYSQL_PASSWORD"]
|
||||
return apiEnv["SQLITE_DATABASE"] // Will read from api project edgebox.env file
|
||||
|
||||
return Dbuser + ":" + Dbpass + "@tcp(" + Dbhost + ")/" + Dbname
|
||||
}
|
||||
|
||||
// GetSQLiteFormattedDateTime: Given a Time, Returns a string that is formatted ready to be inserted into an SQLite Datetime field using sql.Prepare.
|
||||
func GetSQLiteFormattedDateTime(t time.Time) string {
|
||||
// This date is used to indicate the layout.
|
||||
const datetimeLayout = "2006-01-02 15:04:05"
|
||||
formatedDatetime := t.Format(datetimeLayout)
|
||||
|
||||
return formatedDatetime
|
||||
}
|
||||
|
||||
// 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 ;)
|
||||
@@ -88,11 +105,10 @@ func GetPath(pathKey string) string {
|
||||
// Read whole of .env file to map.
|
||||
var env map[string]string
|
||||
env, err := godotenv.Read()
|
||||
targetPath := ""
|
||||
var targetPath string
|
||||
|
||||
if err != nil {
|
||||
// log.Println("Project .env file not found withing project root. Using only hardcoded path variables.")
|
||||
// Do Nothing...
|
||||
targetPath = ""
|
||||
}
|
||||
|
||||
switch pathKey {
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// +build unit
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestExec(t *testing.T) {
|
||||
testCommand := "echo"
|
||||
testArguments := []string{"Hello World"}
|
||||
|
||||
result := Exec("/", testCommand, testArguments)
|
||||
|
||||
if result != "Hello World" {
|
||||
t.Log("Expected 'Hello World' but got", "'"+result+"'")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleExecAndStream() {
|
||||
ExecAndStream("/", "echo", []string{"Hello"})
|
||||
// Output:
|
||||
// Hello
|
||||
//
|
||||
// out:
|
||||
// Hello
|
||||
//
|
||||
// err:
|
||||
}
|
||||
|
||||
func ExampleExecAndStreamExecutableNotFound() {
|
||||
ExecAndStream("/", "testcommand", []string{"Hello"})
|
||||
// Output:
|
||||
// cmd.Run() failed with exec: "testcommand": executable file not found in $PATH
|
||||
//
|
||||
// out:
|
||||
//
|
||||
// err:
|
||||
}
|
||||
|
||||
func ExampleExecAndStreamError() {
|
||||
ExecAndStream("/", "man", []string{"Hello"})
|
||||
// Output:
|
||||
// cmd.Run() failed with exit status 16
|
||||
//
|
||||
// out:
|
||||
//
|
||||
// err:
|
||||
// No manual entry for Hello
|
||||
}
|
||||
|
||||
func TestExecAndGetLines(t *testing.T) {
|
||||
testCommand := "echo"
|
||||
testArguments := []string{"$'Line1\nLine2\nLine3'"}
|
||||
var result []string
|
||||
|
||||
scanner := ExecAndGetLines("/", testCommand, testArguments)
|
||||
|
||||
for scanner.Scan() {
|
||||
result = append(result, scanner.Text())
|
||||
}
|
||||
|
||||
if len(result) != 3 {
|
||||
t.Log("Expected 3 lines but got ", len(result))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteEmptySlices(t *testing.T) {
|
||||
testSlice := []string{"Line1", "", "Line3"}
|
||||
|
||||
resultSlice := DeleteEmptySlices(testSlice)
|
||||
|
||||
if (len(resultSlice)) != 2 {
|
||||
t.Log("Expected 2 slices but got ", len(resultSlice))
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetPath(t *testing.T) {
|
||||
invalidPathKey := "test"
|
||||
|
||||
result := GetPath(invalidPathKey)
|
||||
if result != "" {
|
||||
t.Log("Expected empty result but got ", result)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
validPathKey := "wsPath"
|
||||
result = GetPath(validPathKey)
|
||||
if result != "/home/system/components/ws/" {
|
||||
t.Log("Expected /home/system/components/ws/ but got", result)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSQLiteFormattedDateTime(t *testing.T) {
|
||||
datetime := time.Date(2021, time.Month(1), 01, 1, 30, 15, 0, time.UTC)
|
||||
result := GetSQLiteFormattedDateTime(datetime)
|
||||
|
||||
if result != "2021-01-01 01:30:15" {
|
||||
t.Log("Expected 2021-01-01 01:30:15 but got ", result)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user