6 Commits
Author SHA1 Message Date
aziis98 994cff1190 chore: updated github workflow 2023-12-25 10:10:45 +01:00
aziis98 c85ec78793 chore: some updates 2023-12-25 10:05:22 +01:00
aziis98 10938c1d98 chore: updated readme 2023-12-25 01:06:37 +01:00
aziis98 631af1cda6 chore: updated readme 2023-12-25 01:01:37 +01:00
aziis98 c488d41ac0 chore: updated readme 2023-12-25 00:41:27 +01:00
aziis98 0a375c0990 fix: setup also updates binary 2023-12-25 00:26:22 +01:00
3 changed files with 92 additions and 52 deletions
+3 -3
View File
@@ -12,12 +12,12 @@ jobs:
contents: write
steps:
- name: Checkout Repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: 1.21
go-version-file: './go.mod'
- name: Build
run: |
+46 -34
View File
@@ -1,64 +1,76 @@
# Go Stats Server
This Go project implements a simple TCP server that responds to custom commands over the network. The server performs various system-related tasks and provides
information such as CPU usage, memory status, network statistics, storage details, and system uptime.
This Go project implements a simple TCP server that responds to custom commands over an internal network. The server performs various system-related tasks and provides information such as CPU usage, memory status, network statistics, storage details, and system uptime.
## Commands
The protocol supports the following commands:
- `cpu` — returns the CPU usage percentage
- `memory` — returns the memory usage in MB
- `network` — returns the network usage in bytes
- `storage` — returns the storage usage in GB
- `uptime` — returns the system uptime in seconds
[TODO: check if the command docs are correct]
## Usage
1. **Build the Server:**
```bash
CGO_ENABLED=0 GOARCH=<arch> go build -a -ldflags '-s -w' -o ./out/stats-server main.go
```bash shell
$ CGO_ENABLED=0 GOARCH=<arch> go build -a -ldflags '-s -w' -o ./out/stats-server main.go
```
2. **Run the Server:**
```bash
./out/stats-server
```bash shell
$ ./out/stats-server serve
```
3. **Connect to the Server:** Use a TCP client to connect to the server on port 12345. You can send commands like "cpu," "memory," "network," "storage,"
"uptime," and "exit."
3. **Connect to the Server:** Use a TCP client to connect to the server on port 12345. You can send commands like "cpu", "memory", "network", "storage" or
"uptime".
Example using `nc`:
```bash
echo "cpu" | nc localhost 12345
```bash shell
$ time ( echo "cpu" | nc <hostname> 12345 )
```
or using golang
or directly using golang:
```go
import "net"
conn, _ := net.Dial("tcp", "<hostname>:12345")
conn.Write([]byte("cpu\n"))
func main() {
conn, err := net.Dial("tcp", "localhost:12345")
if err != nil {
// handle error
}
defer conn.Close()
conn.Write([]byte("cpu"))
}
data, _ := io.RealAll(conn)
log.Printf("data: %s", data)
```
## GitHub Actions Workflow
The included GitHub Actions workflow automates the build and release process. On each push to the main branch, the workflow builds the Go program, creates a
GitHub release, and uploads the compiled binary as an artifact.
The included GitHub Actions workflow automates the build and release process. On each push to the main branch, the workflow builds the Go program, creates a GitHub release, and uploads the compiled binary as an artifact.
## Downloading the Artifact
## Self-Installing Binary
TODO
<!--
To download the compiled binary on multiple machines using GNU Parallel, use the following `wget` command:
Assuming you have a cluster of machines, you can use the following commands to download, install and setup systemd services for the latest version of the binary on all nodes. You must have root access to all nodes.
```bash
cat machines.txt | parallel --slf - 'wget -qO- https://github.com/aziis98/go-stats-server/releases/latest/download/stats-server | tar -xz -C /path/to/destination/'
$ parallel --nonall --slf nodes.txt 'mkdir -p cluster'
$ parallel --nonall --slf nodes.txt 'wget -qO- https://github.com/aziis98/go-stats-server/releases/latest/download/stats-server > ./cluster/stats-server'
$ parallel --nonall --slf nodes.txt 'chmod -v +x ./cluster/stats-server'
# setup systemd services on all nodes
$ parallel --nonall --slf nodes.txt './cluster/stats-server setup'
# setup systemd service on a single node
$ ssh root@<node>
$ cd cluster
$ ./stats-server setup
# trying out the new binary using netcat
$ time ( echo '<command>' | nc <node> 12345 )
# stop and disable the systemd service on all nodes
$ parallel --nonall --slf nodes.txt 'systemctl disable --now stats-server.service'
```
Replace "your-username" and "your-repo" with your GitHub username and repository name. Adjust "/path/to/destination/" to the desired destination on the target machines.
Feel free to explore and customize the server to suit your needs. If you encounter any issues or have suggestions for improvements, please open an issue on this repository. Contributions are welcome!
-->
+43 -15
View File
@@ -78,22 +78,25 @@ func handleConnection(conn net.Conn) {
func runCommand(args ...string) error {
cmd := exec.Command(args[0], args[1:]...)
if err := cmd.Run(); err != nil {
return err
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%w: %s", err, output)
}
return nil
}
func setupSystemdService() error {
// copy itself to /usr/bin
if _, err := os.Stat("/usr/local/bin/stats-server"); err == nil {
log.Println("binary already exists in /usr/local/bin, updating...")
}
log.Println("copying itself to /usr/local/bin/stats-server")
if err := runCommand("cp", os.Args[0], "/usr/local/bin/stats-server"); err != nil {
if err := runCommand("cp", "-f", os.Args[0], "/usr/local/bin/stats-server"); err != nil {
return err
}
// write systemd service unit
log.Println("generating /etc/systemd/system/stats-server.service")
log.Println("writing unit to /etc/systemd/system/stats-server.service")
if err := os.WriteFile(
"/etc/systemd/system/stats-server.service",
[]byte(systemdServiceUnit),
@@ -102,15 +105,18 @@ func setupSystemdService() error {
return err
}
// reload systemd
log.Println("running systemctl daemon-reload")
if err := runCommand("systemctl", "daemon-reload"); err != nil {
return err
}
// enable and start the service
log.Println("running systemctl enable --now stats-server.service")
if err := runCommand("systemctl", "enable", "--now", "stats-server.service"); err != nil {
log.Println("running systemctl enable stats-server.service")
if err := runCommand("systemctl", "enable", "stats-server.service"); err != nil {
return err
}
log.Println("running systemctl (re)start stats-server.service")
if err := runCommand("systemctl", "restart", "stats-server.service"); err != nil {
return err
}
@@ -142,11 +148,29 @@ func startTCPServer() error {
}
}
func showHelp() {
fmt.Println("usage: stats-server [setup|serve]")
fmt.Println(" setup: setup systemd service")
fmt.Println(" serve: start tcp server")
var helpText = strings.TrimSpace(`
usage: stats-server [setup|serve]
This is a simple tcp server that returns system stats, it can be run as a
systemd service or as a standalone server.
protocol commands:
cpu returns cpu usage
memory returns memory usage
network returns network usage
storage returns storage usage
uptime returns uptime
subcommands:
setup auto-install and setup systemd service
serve start tcp server
config, environment variables:
HOST tcp host to bind to (default: :12345)
`)
func showHelp() {
fmt.Println(helpText)
os.Exit(1)
}
@@ -157,17 +181,21 @@ func main() {
switch os.Args[1] {
case "setup":
log.Println("starting setup")
if err := setupSystemdService(); err != nil {
log.Fatal(err)
}
log.Println("setup complete")
log.Println("setup completed")
case "serve":
log.Println("starting server")
if err := startTCPServer(); err != nil {
log.Fatal(err)
}
log.Println("server exited")
default:
showHelp()
}