diff --git a/.cirrus.yml b/.cirrus.yml index 5c3837bd0..c88071cac 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -12,8 +12,8 @@ task: . $HOME/.cargo/env cargo_cache: folder: $HOME/.cargo/registry - build_script: env PATH="$HOME/.cargo/bin:$PATH" cargo build - test_script: env PATH="$HOME/.cargo/bin:$PATH" cargo test + build_script: env PATH="$HOME/.cargo/bin:$PATH" cargo build --all-features + test_script: env PATH="$HOME/.cargo/bin:$PATH" cargo test --all-features coverage_script: | cat $0 echo $SHELL diff --git a/.travis.yml b/.travis.yml index 562f532b8..5926a0d70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ install: matrix: include: - env: TARGET=x86_64-unknown-freebsd - script: cargo build --target=$TARGET + script: cargo build --target=$TARGET --all-features - env: TARGET=i686-unknown-freebsd - script: cargo build --target=$TARGET + script: cargo build --target=$TARGET --all-features addons: apt: packages: diff --git a/Cargo.toml b/Cargo.toml index 346fa2338..099764332 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ travis-ci = { repository = "fubarnetes/libjail-rs", branch = "master" } is-it-maintained-issue-resolution = { repository = "fubarnetes/libjail-rs" } is-it-maintained-open-issues = { repository = "fubarnetes/libjail-rs" } +[features] +serialize = ["serde", "serde_json", "rctl/serialize"] + [dependencies] bitflags = "^1" byteorder = "^1.2.3" @@ -31,6 +34,8 @@ nix= "^0.13.0" rctl = "0.1.0" strum = "0.15.0" strum_macros = "0.15.0" +serde = { version="1.0", features = ["derive"], optional=true} +serde_json = { version="1.0", optional=true } [dev-dependencies] pretty_env_logger = "0.3" diff --git a/examples/serialize.rs b/examples/serialize.rs new file mode 100644 index 000000000..882995713 --- /dev/null +++ b/examples/serialize.rs @@ -0,0 +1,56 @@ +extern crate jail; + +#[macro_use] +extern crate log; + +extern crate pretty_env_logger; +extern crate rctl; +#[cfg(features="serialize")] +extern crate serde_json; + +use jail::param; +use std::str::FromStr; + +#[cfg(feature="serialize")] +fn main() { + pretty_env_logger::init(); + + let mut stopped = jail::StoppedJail::new("/rescue") + .name("example_serializing") + .ip("127.0.1.1".parse().expect("couldn't parse IP Addr")) + .ip("fe80::2".parse().expect("couldn't parse IP Addr")) + .param( + "osrelease", + param::Value::String("FreeBSD 42.23".to_string()), + ) + .param("allow.raw_sockets", param::Value::Int(1)) + .param("allow.sysvipc", param::Value::Int(1)); + + if rctl::State::check().is_enabled() { + // skip setting limits when racct is not enabled + stopped = stopped.limit( + rctl::Resource::from_str("maxproc") + .expect("couldn't parse Resource name"), + rctl::Limit::from_str("1000") + .expect("couldn't parse resource Limit"), + rctl::Action::Signal(rctl::Signal::SIGTERM)); + } + + stopped.hostname = Some("testjail.example.org".to_string()); + + let running = stopped.start().expect("Failed to start jail"); + + info!("created new jail with JID {}", running.jid); + + let stopped = running.stop().expect("Failed to stop jail"); + + let serialized = serde_json::to_string_pretty(&stopped) + .expect("Failed to serialize jail"); + + println!("{}", serialized); +} + +#[cfg(not(feature="serialize"))] +fn main() { + println!("Run `cargo build --features=serialize` to enable this example."); +} diff --git a/src/lib.rs b/src/lib.rs index 5a7d6c8b8..2771e8e0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,12 @@ extern crate strum; #[macro_use] extern crate strum_macros; +#[cfg(feature="serialize")] +extern crate serde; + +#[cfg(feature="serialize")] +extern crate serde_json; + use std::collections::HashMap; use std::convert; use std::net; diff --git a/src/param.rs b/src/param.rs index a8c50cd06..98c4785a4 100644 --- a/src/param.rs +++ b/src/param.rs @@ -15,6 +15,8 @@ use JailError; use byteorder::{ByteOrder, LittleEndian, NetworkEndian, WriteBytesExt}; use sysctl::{Ctl, CtlFlags, CtlType, CtlValue}; +#[cfg(feature="serialize")] +use serde::{Serialize}; use nix; @@ -206,6 +208,7 @@ impl convert::Into for Type { /// An enum representing the value of a parameter. #[derive(EnumDiscriminants, Clone, PartialEq, Eq, Debug, Hash)] #[strum_discriminants(name(Type), derive(PartialOrd, Ord, Hash))] +#[cfg_attr(feature="serialize", derive(Serialize))] pub enum Value { Int(libc::c_int), String(String), diff --git a/src/stopped.rs b/src/stopped.rs index 231f76dcb..0c3a5075d 100644 --- a/src/stopped.rs +++ b/src/stopped.rs @@ -8,11 +8,15 @@ use sys; use JailError; use RunningJail; +#[cfg(feature="serialize")] +use serde::{Serialize}; + use std::fmt; /// Represent a stopped jail including all information required to start it #[derive(Clone, PartialEq, Eq, Debug)] #[cfg(target_os = "freebsd")] +#[cfg_attr(feature="serialize", derive(Serialize))] pub struct StoppedJail { /// The path of root file system of the jail pub path: Option, @@ -270,4 +274,5 @@ impl StoppedJail { self.ips.push(ip); self } + } diff --git a/src/tests.rs b/src/tests.rs index 4da80783f..e044c9489 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -4,6 +4,55 @@ use running::RunningJail; use std::os::unix::process::ExitStatusExt; use std::process::Command; use stopped::StoppedJail; +use param; +#[cfg(feature="serialize")] +use serde_json; + +#[cfg(feature="serialize")] +#[test] +fn test_serializing_jail() { + + let rctl_enabled = rctl::State::check().is_enabled(); + + let mut stopped = StoppedJail::new("/") + .name("testjail_serializing") + .ip("127.0.1.1".parse().expect("couldn't parse IP Addr")) + .param( + "osrelease", + param::Value::String("FreeBSD 42.23".to_string()), + ); + + if rctl_enabled { + // Skip setting limits if racct is disabled. + stopped = stopped.limit( + rctl::Resource::Wallclock, + rctl::Limit::amount(1), + rctl::Action::Signal(rctl::Signal::SIGKILL), + ); + } + + let serialized = serde_json::to_string(&stopped) + .expect("could not serialize jail"); + + let output: serde_json::Value = serde_json::from_str(&serialized) + .expect("could not parse serialized string"); + + assert_eq!(output["name"], "testjail_serializing"); + assert_eq!(output["ips"][0], "127.0.1.1"); + assert_eq!(output["params"]["osrelease"]["String"] + .as_str() + .expect("could not read jails parameter value"), + "FreeBSD 42.23"); + + if rctl_enabled { + let limits = &output["limits"][0]; + assert_eq!(limits[0], "Wallclock"); + assert_eq!(limits[1]["amount"], 1); + assert_eq!(limits[2]["Signal"], "SIGKILL") + } + +} + #[test] fn test_rctl_yes() {