Initial build

This commit is contained in:
Zeva Rose 2025-05-23 20:15:45 -06:00
commit 0ca14c2d92
5 changed files with 1419 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1253
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

19
Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "beszel-register"
version = "1.0.0"
edition = "2024"
license = "GPL-3.0-or-later"
authors = ["Zevaryx <zevaryx@gmail.com>"]
repository = "https://git.zevaryx.com/zevaryx/beszel-register"
readme = "README.md"
description = "A small Rust program to join a system to a Beszel instance"
[dependencies]
anyhow = "1.0.98"
chrono = { version = "0.4.41", features = ["serde"] }
clap = { version = "4.5.38", features = ["derive"] }
gethostname = "1.0.2"
local-ip-address = "0.6.5"
pocketbase-sdk = "0.1.1"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# `beszel-register`
A small Rust program to register a system using the Beszel API
## Basic Usage
```bash
beszel-register --beszel http://beszel:8090 --username user@example.com --password 'Password'
```
### Advanced Usage
```bash
beszel-register \
--beszel http://beszel:8090 \
--username user@example.com \
--password 'Password' \
--name 'System Name' \
--ip 'System IP' \
--port 45876
```

125
src/main.rs Normal file
View file

@ -0,0 +1,125 @@
use anyhow::Result;
use chrono::{DateTime, Utc};
use clap::Parser;
use gethostname::gethostname;
use local_ip_address::local_ip;
use pocketbase_sdk::client::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
#[arg(short, long)]
beszel: String,
#[arg(short, long)]
username: String,
#[arg(short, long)]
password: String,
#[arg(short, long)]
name: Option<String>,
#[arg(short, long)]
ip: Option<String>,
#[arg(long, default_value_t = 45876)]
port: u32,
}
#[derive(Debug, Clone, Serialize)]
struct NewSystem {
name: String,
host: String,
users: Vec<String>,
port: u32,
}
#[derive(Debug, Clone, Deserialize, Default)]
#[allow(dead_code, non_snake_case)]
struct System {
collectionId: String,
collectionName: String,
created: DateTime<Utc>,
host: String,
id: String,
info: Value,
name: String,
port: String,
status: String,
updated: DateTime<Utc>,
users: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Default)]
#[allow(dead_code, non_snake_case)]
struct User {
avatar: String,
collectionId: String,
collectionName: String,
created: DateTime<Utc>,
email: String,
emailVisibility: bool,
id: String,
name: String,
role: String,
updated: DateTime<Utc>,
username: String,
verified: bool,
}
fn main() -> Result<()> {
let args = Args::parse();
let hostname = match args.name {
Some(n) => n,
None => gethostname().to_string_lossy().to_string(),
};
let ip = match args.ip {
Some(i) => i,
None => local_ip()?.to_string()
};
let client = Client::new(&args.beszel)
.auth_with_password("users", &args.username, &args.password)?;
let users = client
.records("users")
.list()
.call::<User>()?
.items;
let user = users
.iter()
.find(|x| x.email == args.username)
.expect("Was not able to retrieve self, something is wrong!");
let systems = client
.records("systems")
.list()
.call::<System>()?
.items;
if systems.iter().any(|x| x.name == hostname && x.host == ip) {
println!("System already exists!")
} else {
let system = NewSystem {
name: hostname.to_owned(),
host: ip.to_owned(),
users: vec![user.id.to_owned()],
port: args.port,
};
client
.records("systems")
.create(system)
.call()?;
println!("Regestered system as {} with IP {}", hostname, ip);
}
Ok(())
}