Skip to content

Commit

Permalink
Merge pull request #1 from WIPACrepo/smartrest
Browse files Browse the repository at this point in the history
Created REST Service for smartctl Access
  • Loading branch information
blinkdog authored Jun 18, 2024
2 parents 30484f9 + 25412c0 commit df9b1cc
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ env:
CARGO_TERM_COLOR: always

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: cargo fmt --check
- run: cargo clippy --locked

test:
name: Test
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wipac-disk-tracking"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
publish = false

Expand All @@ -9,3 +9,5 @@ env_logger = "0.11.3"
gotham = "0.7.4"
gotham_restful = "0.9.0"
log = "0.4.21"
serde = "1.0.203"
serde_json = "1.0.117"
132 changes: 132 additions & 0 deletions src/bin/smartrest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// smartrest.rs

use gotham::{
router::{build_simple_router, response::StaticResponseExtender, Router},
state::StateData,
};
use gotham_restful::{read_all, search, DrawResources, Resource, Success};
use log::{error, info};
use serde::Deserialize;
use serde_json::{json, Value};
use std::process::Command;

// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

#[derive(Resource)]
#[resource(smartctl_scan)]
#[resource(smartctl_all)]
struct SmartCtlResource;

#[derive(Clone, Deserialize, StateData, StaticResponseExtender)]
struct DevicePath {
device: String,
}

#[read_all]
fn smartctl_scan() -> Success<Value> {
execute_smartctl_scan().into()
}

#[search]
fn smartctl_all(path: DevicePath) -> Success<Value> {
execute_smartctl_all(&path.device).into()
}

// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

fn execute_smartctl_all(device: &str) -> Value {
// enumerate all the devices on the system
let mut smartctl_devices = Vec::new();

// query smartctl to ask what devices we have on the system
let smartctl = execute_smartctl_scan();
// if we got back some useful data from smartctl
if let Some(smartctl_obj) = smartctl.as_object() {
// if there is a 'devices' array
if let Some(devices) = smartctl_obj.get("devices") {
if let Some(devices_array) = devices.as_array() {
// for each device in the array
for smartctl_device in devices_array {
// if the device has a name
if let Some(device_name) = smartctl_device.get("name") {
if let Some(name) = device_name.as_str() {
// add it to the list of devices
smartctl_devices.push(name);
}
}
}
}
}
}

// check to see if the provided device is on the list
if smartctl_devices.contains(&device) {
// if we get output from the smartctl command
if let Ok(output) = Command::new("/usr/sbin/smartctl")
.arg("--all") // give us all the information for the device
.arg("--json") // give us the result in JSON
.arg(device) // about this device
.output()
{
// if we can convert that output into a sensible utf8 string
if let Ok(stdout) = String::from_utf8(output.stdout) {
// if we can parse that result into a JSON value
if let Ok(result) = serde_json::from_str(&stdout) {
// give the output to the caller
return result;
}
}
}
}

// give the caller an empty object
error!(
"Device {} was not found in the list of smartctl devices: {:?}",
device, smartctl_devices
);
json!("{}")
}

fn execute_smartctl_scan() -> Value {
// if we get output from the smartctl command
if let Ok(output) = Command::new("/usr/sbin/smartctl")
.arg("--scan") // scan for devices
.arg("--json") // give us the result in JSON
.output()
{
// if we can convert that output into a sensible utf8 string
if let Ok(stdout) = String::from_utf8(output.stdout) {
// if we can parse that result into a JSON value
if let Ok(result) = serde_json::from_str(&stdout) {
// give the output to the caller
return result;
}
}
}

// give the caller an empty object
json!("{}")
}

// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

fn router() -> Router {
build_simple_router(|route| {
route.resource::<SmartCtlResource>("smartctl");
})
}

pub fn main() {
// initialize logging, configured by environment
env_logger::init();
// start the service
let addr = "0.0.0.0:8080";
info!("Listening for requests at http://{}", addr);
let _ = gotham::start(addr, router());
}

0 comments on commit df9b1cc

Please sign in to comment.