pub mod fop;
pub mod heal;
pub mod peer;
pub mod volume;
mod rpc;
extern crate byteorder;
#[macro_use]
extern crate log;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate unix_socket;
extern crate uuid;
use regex::Regex;
use std::cmp::Ord;
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::OsStr;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::net::IpAddr;
use std::path::PathBuf;
use std::str::FromStr;
use volume::{Brick, volume_info};
pub enum SelfHealAlgorithm {
Full,
Diff,
Reset,
}
impl SelfHealAlgorithm {
fn to_string(&self) -> String {
match self {
&SelfHealAlgorithm::Full => "full".to_string(),
&SelfHealAlgorithm::Diff => "diff".to_string(),
&SelfHealAlgorithm::Reset => "reset".to_string(),
}
}
fn from_str(s: &str) -> SelfHealAlgorithm {
match s {
"full" => SelfHealAlgorithm::Full,
"diff" => SelfHealAlgorithm::Diff,
"reset" => SelfHealAlgorithm::Reset,
_ => SelfHealAlgorithm::Full,
}
}
}
pub enum SplitBrainPolicy {
Ctime,
Disable,
Majority,
Mtime,
Size,
}
impl SplitBrainPolicy {
pub fn to_string(&self) -> String {
match self {
&SplitBrainPolicy::Ctime => "ctime".to_string(),
&SplitBrainPolicy::Disable => "none".to_string(),
&SplitBrainPolicy::Majority => "majority".to_string(),
&SplitBrainPolicy::Mtime => "mtime".to_string(),
&SplitBrainPolicy::Size => "size".to_string(),
}
}
pub fn from_str(s: &str) -> Result<SplitBrainPolicy, GlusterError> {
match s {
"ctime" => Ok(SplitBrainPolicy::Ctime),
"none" => Ok(SplitBrainPolicy::Disable),
"majority" => Ok(SplitBrainPolicy::Majority),
"mtime" => Ok(SplitBrainPolicy::Mtime),
"size" => Ok(SplitBrainPolicy::Size),
_ => Err(GlusterError::new("Unknown access mode".to_string())),
}
}
}
impl<'a> Into<&'a str> for SplitBrainPolicy {
fn into(self) -> &'a str {
match self {
SplitBrainPolicy::Ctime => "ctime",
SplitBrainPolicy::Disable => "none",
SplitBrainPolicy::Majority => "majority",
SplitBrainPolicy::Mtime => "mtime",
SplitBrainPolicy::Size => "size",
}
}
}
pub enum AccessMode {
ReadOnly,
ReadWrite,
}
impl AccessMode {
pub fn to_string(&self) -> String {
match self {
&AccessMode::ReadOnly => "read-only".to_string(),
&AccessMode::ReadWrite => "read-write".to_string(),
}
}
pub fn from_str(s: &str) -> AccessMode {
match s {
"read-only" => AccessMode::ReadOnly,
"read-write" => AccessMode::ReadWrite,
_ => AccessMode::ReadWrite,
}
}
}
impl<'a> Into<&'a str> for AccessMode {
fn into(self) -> &'a str {
match self {
AccessMode::ReadOnly => "read-only",
AccessMode::ReadWrite => "read-write",
}
}
}
pub enum Toggle {
On,
Off,
}
impl Into<bool> for Toggle {
fn into(self) -> bool {
match self {
Toggle::On => true,
Toggle::Off => false,
}
}
}
impl Toggle {
pub fn to_string(&self) -> String {
match self {
&Toggle::On => "On".to_string(),
&Toggle::Off => "Off".to_string(),
}
}
pub fn from_str(s: &str) -> Toggle {
match s {
"on" => Toggle::On,
"off" => Toggle::Off,
"true" => Toggle::On,
"false" => Toggle::Off,
_ => Toggle::Off,
}
}
}
pub enum ScrubSchedule {
Hourly,
Daily,
Weekly,
BiWeekly,
Monthly,
}
impl ScrubSchedule {
pub fn to_string(&self) -> String {
match self {
&ScrubSchedule::Hourly => "hourly".to_string(),
&ScrubSchedule::Daily => "daily".to_string(),
&ScrubSchedule::Weekly => "weekly".to_string(),
&ScrubSchedule::BiWeekly => "biweekly".to_string(),
&ScrubSchedule::Monthly => "monthly".to_string(),
}
}
pub fn from_str(s: &str) -> ScrubSchedule {
match s {
"hourly" => ScrubSchedule::Hourly,
"daily" => ScrubSchedule::Daily,
"weekly" => ScrubSchedule::Weekly,
"biweekly" => ScrubSchedule::BiWeekly,
"monthly" => ScrubSchedule::Monthly,
_ => ScrubSchedule::Weekly,
}
}
}
pub enum ScrubAggression {
Aggressive,
Lazy,
Normal,
}
impl ScrubAggression {
pub fn to_string(&self) -> String {
match self {
&ScrubAggression::Aggressive => "aggressive".to_string(),
&ScrubAggression::Lazy => "lazy".to_string(),
&ScrubAggression::Normal => "normal".to_string(),
}
}
pub fn from_str(s: &str) -> ScrubAggression {
match s {
"aggressive" => ScrubAggression::Aggressive,
"lazy" => ScrubAggression::Lazy,
"normal" => ScrubAggression::Normal,
_ => ScrubAggression::Normal,
}
}
}
pub enum ScrubControl {
Pause,
Resume,
Status,
OnDemand,
}
impl ScrubControl {
fn to_string(&self) -> String {
match self {
&ScrubControl::Pause => "pause".to_string(),
&ScrubControl::Resume => "resume".to_string(),
&ScrubControl::Status => "status".to_string(),
&ScrubControl::OnDemand => "ondemand".to_string(),
}
}
}
impl FromStr for ScrubControl {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pause" => Ok(ScrubControl::Pause),
"resume" => Ok(ScrubControl::Resume),
"status" => Ok(ScrubControl::Status),
"ondemand" => Ok(ScrubControl::OnDemand),
_ => Err(format!("Unknown Control value: {}", s)),
}
}
}
pub enum BitrotOption {
ScrubThrottle(ScrubAggression),
ScrubFrequency(ScrubSchedule),
Scrub(ScrubControl),
}
impl BitrotOption {
fn to_string(&self) -> String {
match self {
&BitrotOption::ScrubThrottle(_) => "scrub-throttle".to_string(),
&BitrotOption::ScrubFrequency(_) => "scrub-frequency".to_string(),
&BitrotOption::Scrub(_) => "scrub".to_string(),
}
}
fn value(&self) -> String {
match self {
&BitrotOption::ScrubThrottle(ref val) => val.to_string(),
&BitrotOption::ScrubFrequency(ref val) => val.to_string(),
&BitrotOption::Scrub(ref val) => val.to_string(),
}
}
}
pub enum GlusterOption {
AuthAllow(String),
AuthReject(String),
ClientGraceTimeout(i64),
ClusterSelfHealWindowSize(u16),
ClientSsl(Toggle),
ClusterDataSelfHealAlgorithm(SelfHealAlgorithm),
ClusterMinFreeDisk(u8),
ClusterStripeBlockSize(u64),
ClusterSelfHealDaemon(Toggle),
ClusterEnsureDurability(Toggle),
DiagnosticsBrickLogLevel(log::LogLevel),
DiagnosticsClientLogLevel(log::LogLevel),
DiagnosticsFopSampleInterval(u64),
DiagnosticsFopSampleBufSize(u64),
DiagnosticsCountFopHits(Toggle),
DiagnosticsStatsDumpInterval(u64),
DiagnosticsStatsDnscacheTtlSec(u64),
DiagnosticsLatencyMeasurement(Toggle),
DiagnosticsDumpFdStats(Toggle),
FavoriteChildPolicy(SplitBrainPolicy),
FeaturesReadOnly(Toggle),
FeaturesLockHeal(Toggle),
FeaturesQuotaTimeout(u16),
GeoReplicationIndexing(Toggle),
NetworkFrameTimeout(u16),
NfsEnableIno32(Toggle),
NfsVolumeAccess(AccessMode),
NfsTrustedWrite(Toggle),
NfsTrustedSync(Toggle),
NfsExportDir(String),
NfsExportVolumes(Toggle),
NfsRpcAuthUnix(Toggle),
NfsRpcAuthNull(Toggle),
NfsPortsInsecure(Toggle),
NfsAddrNamelookup(Toggle),
NfsRegisterWithPortmap(Toggle),
NfsDisable(Toggle),
PerformanceWriteBehindWindowSize(u64),
PerformanceIoThreadCount(u8),
PerformanceFlushBehind(Toggle),
PerformanceCacheMaxFileSize(u64),
PerformanceCacheMinFileSize(u64),
PerformanceCacheRefreshTimeout(u8),
PerformanceCacheSize(u64),
PerformanceReadDirAhead(Toggle),
PerformanceParallelReadDir(Toggle),
PerformanceReadDirAheadCacheLimit(u64),
ServerAllowInsecure(Toggle),
ServerGraceTimeout(u16),
ServerSsl(Toggle),
ServerStatedumpPath(PathBuf),
SslAllow(String),
SslCertificateDepth(u8),
SslCipherList(String),
StorageHealthCheckInterval(u16),
}
impl GlusterOption {
fn to_string(&self) -> String {
match self {
&GlusterOption::AuthAllow(_) => "auth.allow".to_string(),
&GlusterOption::AuthReject(_) => "auth.reject".to_string(),
&GlusterOption::ClientGraceTimeout(_) => "client.grace-timeout".to_string(),
&GlusterOption::ClientSsl(_) => "client.ssl".to_string(),
&GlusterOption::ClusterSelfHealWindowSize(_) => {
"cluster.self-heal-window-size".to_string()
}
&GlusterOption::ClusterDataSelfHealAlgorithm(_) => {
"cluster.data-self-heal-algorithm".to_string()
}
&GlusterOption::ClusterMinFreeDisk(_) => "cluster.min-free-disk".to_string(),
&GlusterOption::ClusterStripeBlockSize(_) => "cluster.stripe-block-size".to_string(),
&GlusterOption::ClusterSelfHealDaemon(_) => "cluster.self-heal-daemon".to_string(),
&GlusterOption::ClusterEnsureDurability(_) => "cluster.ensure-durability".to_string(),
&GlusterOption::DiagnosticsBrickLogLevel(_) => {
"diagnostics.brick-log-level".to_string()
}
&GlusterOption::DiagnosticsClientLogLevel(_) => {
"diagnostics.client-log-level".to_string()
}
&GlusterOption::DiagnosticsLatencyMeasurement(_) => {
"diagnostics.latency-measurement".to_string()
}
&GlusterOption::DiagnosticsCountFopHits(_) => "diagnostics.count-fop-hits".to_string(),
&GlusterOption::DiagnosticsDumpFdStats(_) => "diagnostics.dump-fd-stats".to_string(),
&GlusterOption::DiagnosticsFopSampleBufSize(_) => {
"diagnostics.fop-sample-buf-size".to_string()
}
&GlusterOption::DiagnosticsFopSampleInterval(_) => {
"diagnostics.fop-sample-interval".to_string()
}
&GlusterOption::DiagnosticsStatsDnscacheTtlSec(_) => {
"diagnostics.stats-dnscache-ttl-sec".to_string()
}
&GlusterOption::DiagnosticsStatsDumpInterval(_) => {
"diagnostics.stats-dump-interval".to_string()
}
&GlusterOption::FavoriteChildPolicy(_) => "cluster.favorite-child-policy".to_string(),
&GlusterOption::FeaturesReadOnly(_) => "features.read-only".to_string(),
&GlusterOption::FeaturesLockHeal(_) => "features.lock-heal".to_string(),
&GlusterOption::FeaturesQuotaTimeout(_) => "features.quota-timeout".to_string(),
&GlusterOption::GeoReplicationIndexing(_) => "geo-replication.indexing".to_string(),
&GlusterOption::NetworkFrameTimeout(_) => "network.frame-timeout".to_string(),
&GlusterOption::NfsEnableIno32(_) => "nfs.enable-ino32".to_string(),
&GlusterOption::NfsVolumeAccess(_) => "nfs.volume-access".to_string(),
&GlusterOption::NfsTrustedWrite(_) => "nfs.trusted-write".to_string(),
&GlusterOption::NfsTrustedSync(_) => "nfs.trusted-sync".to_string(),
&GlusterOption::NfsExportDir(_) => "nfs.export-dir".to_string(),
&GlusterOption::NfsExportVolumes(_) => "nfs.export-volumes".to_string(),
&GlusterOption::NfsRpcAuthUnix(_) => "nfs.rpc-auth-unix".to_string(),
&GlusterOption::NfsRpcAuthNull(_) => "nfs.rpc-auth-null".to_string(),
&GlusterOption::NfsPortsInsecure(_) => "nfs.ports-insecure".to_string(),
&GlusterOption::NfsAddrNamelookup(_) => "nfs.addr-namelookup".to_string(),
&GlusterOption::NfsRegisterWithPortmap(_) => "nfs.register-with-portmap".to_string(),
&GlusterOption::NfsDisable(_) => "nfs.disable".to_string(),
&GlusterOption::PerformanceWriteBehindWindowSize(_) => {
"performance.write-behind-window-size".to_string()
}
&GlusterOption::PerformanceIoThreadCount(_) => {
"performance.io-thread-count".to_string()
}
&GlusterOption::PerformanceFlushBehind(_) => "performance.flush-behind".to_string(),
&GlusterOption::PerformanceCacheMaxFileSize(_) => {
"performance.cache-max-file-size".to_string()
}
&GlusterOption::PerformanceCacheMinFileSize(_) => {
"performance.cache-min-file-size".to_string()
}
&GlusterOption::PerformanceCacheRefreshTimeout(_) => {
"performance.cache-refresh-timeout".to_string()
}
&GlusterOption::PerformanceCacheSize(_) => "performance.cache-size".to_string(),
&GlusterOption::PerformanceReadDirAhead(_) => "performance.readdir-ahead".to_string(),
&GlusterOption::PerformanceParallelReadDir(_) => {
"performance.parallel-readdir".to_string()
}
&GlusterOption::PerformanceReadDirAheadCacheLimit(_) => {
"performance.rda-cache-limit".to_string()
}
&GlusterOption::ServerAllowInsecure(_) => "server.allow-insecure".to_string(),
&GlusterOption::ServerGraceTimeout(_) => "server.grace-timeout".to_string(),
&GlusterOption::ServerSsl(_) => "server.ssl".to_string(),
&GlusterOption::ServerStatedumpPath(_) => "server.statedump-path".to_string(),
&GlusterOption::SslAllow(_) => "auth.ssl-allow".to_string(),
&GlusterOption::SslCertificateDepth(_) => "ssl.certificate-depth".to_string(),
&GlusterOption::SslCipherList(_) => "ssl.cipher-list".to_string(),
&GlusterOption::StorageHealthCheckInterval(_) => {
"storage.health-check-interval".to_string()
}
}
}
fn value(&self) -> String {
match self {
&GlusterOption::AuthAllow(ref val) => val.to_string(),
&GlusterOption::AuthReject(ref val) => val.to_string(),
&GlusterOption::ClientGraceTimeout(val) => val.to_string(),
&GlusterOption::ClientSsl(ref val) => val.to_string(),
&GlusterOption::ClusterSelfHealWindowSize(val) => val.to_string(),
&GlusterOption::ClusterDataSelfHealAlgorithm(ref val) => val.to_string(),
&GlusterOption::ClusterMinFreeDisk(val) => val.to_string(),
&GlusterOption::ClusterStripeBlockSize(val) => val.to_string(),
&GlusterOption::ClusterSelfHealDaemon(ref val) => val.to_string(),
&GlusterOption::ClusterEnsureDurability(ref val) => val.to_string(),
&GlusterOption::DiagnosticsBrickLogLevel(val) => val.to_string(),
&GlusterOption::DiagnosticsClientLogLevel(val) => val.to_string(),
&GlusterOption::DiagnosticsLatencyMeasurement(ref val) => val.to_string(),
&GlusterOption::DiagnosticsDumpFdStats(ref val) => val.to_string(),
&GlusterOption::DiagnosticsFopSampleInterval(ref val) => val.to_string(),
&GlusterOption::DiagnosticsFopSampleBufSize(ref val) => val.to_string(),
&GlusterOption::DiagnosticsCountFopHits(ref val) => val.to_string(),
&GlusterOption::DiagnosticsStatsDumpInterval(ref val) => val.to_string(),
&GlusterOption::DiagnosticsStatsDnscacheTtlSec(ref val) => val.to_string(),
&GlusterOption::FavoriteChildPolicy(ref val) => val.to_string(),
&GlusterOption::FeaturesReadOnly(ref val) => val.to_string(),
&GlusterOption::FeaturesLockHeal(ref val) => val.to_string(),
&GlusterOption::FeaturesQuotaTimeout(val) => val.to_string(),
&GlusterOption::GeoReplicationIndexing(ref val) => val.to_string(),
&GlusterOption::NetworkFrameTimeout(val) => val.to_string(),
&GlusterOption::NfsEnableIno32(ref val) => val.to_string(),
&GlusterOption::NfsVolumeAccess(ref val) => val.to_string(),
&GlusterOption::NfsTrustedWrite(ref val) => val.to_string(),
&GlusterOption::NfsTrustedSync(ref val) => val.to_string(),
&GlusterOption::NfsExportDir(ref val) => val.to_string(),
&GlusterOption::NfsExportVolumes(ref val) => val.to_string(),
&GlusterOption::NfsRpcAuthUnix(ref val) => val.to_string(),
&GlusterOption::NfsRpcAuthNull(ref val) => val.to_string(),
&GlusterOption::NfsPortsInsecure(ref val) => val.to_string(),
&GlusterOption::NfsAddrNamelookup(ref val) => val.to_string(),
&GlusterOption::NfsRegisterWithPortmap(ref val) => val.to_string(),
&GlusterOption::NfsDisable(ref val) => val.to_string(),
&GlusterOption::PerformanceWriteBehindWindowSize(val) => val.to_string(),
&GlusterOption::PerformanceIoThreadCount(val) => val.to_string(),
&GlusterOption::PerformanceFlushBehind(ref val) => val.to_string(),
&GlusterOption::PerformanceCacheMaxFileSize(val) => val.to_string(),
&GlusterOption::PerformanceCacheMinFileSize(val) => val.to_string(),
&GlusterOption::PerformanceCacheRefreshTimeout(val) => val.to_string(),
&GlusterOption::PerformanceCacheSize(val) => val.to_string(),
&GlusterOption::PerformanceReadDirAhead(ref val) => val.to_string(),
&GlusterOption::PerformanceParallelReadDir(ref val) => val.to_string(),
&GlusterOption::PerformanceReadDirAheadCacheLimit(val) => val.to_string(),
&GlusterOption::ServerAllowInsecure(ref val) => val.to_string(),
&GlusterOption::ServerGraceTimeout(val) => val.to_string(),
&GlusterOption::ServerSsl(ref val) => val.to_string(),
&GlusterOption::SslAllow(ref val) => val.to_string(),
&GlusterOption::SslCertificateDepth(val) => val.to_string(),
&GlusterOption::SslCipherList(ref val) => val.to_string(),
&GlusterOption::ServerStatedumpPath(ref val) => val.to_string_lossy().into_owned(),
&GlusterOption::StorageHealthCheckInterval(val) => val.to_string(),
}
}
pub fn from_str(s: &str, value: String) -> Result<GlusterOption, GlusterError> {
match s {
"auth-allow" => {
return Ok(GlusterOption::AuthAllow(value));
}
"auth-reject" => {
return Ok(GlusterOption::AuthReject(value));
}
"auth.ssl-allow" => {
return Ok(GlusterOption::SslAllow(value));
}
"client.ssl" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::ClientSsl(t));
}
"cluster.favorite-child-policy" => {
let policy = SplitBrainPolicy::from_str(&value)?;
return Ok(GlusterOption::FavoriteChildPolicy(policy));
}
"client-grace-timeout" => {
let i = try!(i64::from_str(&value));
return Ok(GlusterOption::ClientGraceTimeout(i));
}
"cluster-self-heal-window-size" => {
let i = try!(u16::from_str(&value));
return Ok(GlusterOption::ClusterSelfHealWindowSize(i));
}
"cluster-data-self-heal-algorithm" => {
let s = SelfHealAlgorithm::from_str(&value);
return Ok(GlusterOption::ClusterDataSelfHealAlgorithm(s));
}
"cluster-min-free-disk" => {
let i = try!(u8::from_str(&value));
return Ok(GlusterOption::ClusterMinFreeDisk(i));
}
"cluster-stripe-block-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::ClusterStripeBlockSize(i));
}
"cluster-self-heal-daemon" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::ClusterSelfHealDaemon(t));
}
"cluster-ensure-durability" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::ClusterEnsureDurability(t));
}
"diagnostics-brick-log-level" => {
let l = log::LogLevel::from_str(&value).unwrap_or(log::LogLevel::Debug);
return Ok(GlusterOption::DiagnosticsBrickLogLevel(l));
}
"diagnostics-client-log-level" => {
let l = log::LogLevel::from_str(&value).unwrap_or(log::LogLevel::Debug);
return Ok(GlusterOption::DiagnosticsClientLogLevel(l));
}
"diagnostics-latency-measurement" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::DiagnosticsLatencyMeasurement(t));
}
"diagnostics.count-fop-hits" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::DiagnosticsCountFopHits(t));
}
"diagnostics.stats-dump-interval" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::DiagnosticsStatsDumpInterval(i));
}
"diagnostics.fop-sample-buf-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::DiagnosticsFopSampleBufSize(i));
}
"diagnostics.fop-sample-interval" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::DiagnosticsFopSampleInterval(i));
}
"diagnostics.stats-dnscache-ttl-sec" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::DiagnosticsStatsDnscacheTtlSec(i));
}
"diagnostics-dump-fd-stats" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::DiagnosticsDumpFdStats(t));
}
"features-read-only" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::FeaturesReadOnly(t));
}
"features-lock-heal" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::FeaturesLockHeal(t));
}
"features-quota-timeout" => {
let i = try!(u16::from_str(&value));
return Ok(GlusterOption::FeaturesQuotaTimeout(i));
}
"geo-replication-indexing" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::GeoReplicationIndexing(t));
}
"network-frame-timeout" => {
let i = try!(u16::from_str(&value));
return Ok(GlusterOption::NetworkFrameTimeout(i));
}
"nfs-enable-ino32" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsEnableIno32(t));
}
"nfs-volume-access" => {
let s = AccessMode::from_str(&value);
return Ok(GlusterOption::NfsVolumeAccess(s));
}
"nfs-trusted-write" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsTrustedWrite(t));
}
"nfs-trusted-sync" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsTrustedSync(t));
}
"nfs-export-dir" => {
return Ok(GlusterOption::NfsExportDir(value));
}
"nfs-export-volumes" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsExportVolumes(t));
}
"nfs-rpc-auth-unix" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsRpcAuthUnix(t));
}
"nfs-rpc-auth-null" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsRpcAuthNull(t));
}
"nfs-ports-insecure" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsPortsInsecure(t));
}
"nfs-addr-namelookup" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsAddrNamelookup(t));
}
"nfs-register-with-portmap" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsRegisterWithPortmap(t));
}
"nfs-disable" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::NfsDisable(t));
}
"performance-write-behind-window-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::PerformanceWriteBehindWindowSize(i));
}
"performance-io-thread-count" => {
let i = try!(u8::from_str(&value));
return Ok(GlusterOption::PerformanceIoThreadCount(i));
}
"performance-flush-behind" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::PerformanceFlushBehind(t));
}
"performance-cache-max-file-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::PerformanceCacheMaxFileSize(i));
}
"performance-cache-min-file-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::PerformanceCacheMinFileSize(i));
}
"performance-cache-refresh-timeout" => {
let i = try!(u8::from_str(&value));
return Ok(GlusterOption::PerformanceCacheRefreshTimeout(i));
}
"performance-cache-size" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::PerformanceCacheSize(i));
}
"performance-readdir-ahead" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::PerformanceReadDirAhead(t));
}
"performance-parallel-readdir" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::PerformanceReadDirAhead(t));
}
"performance-readdir-cache-limit" => {
let i = try!(u64::from_str(&value));
return Ok(GlusterOption::PerformanceReadDirAheadCacheLimit(i));
}
"server.ssl" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::ServerSsl(t));
}
"server-allow-insecure" => {
let t = Toggle::from_str(&value);
return Ok(GlusterOption::ServerAllowInsecure(t));
}
"server-grace-timeout" => {
let i = try!(u16::from_str(&value));
return Ok(GlusterOption::ServerGraceTimeout(i));
}
"server-statedump-path" => {
let p = PathBuf::from(&value);
return Ok(GlusterOption::ServerStatedumpPath(p));
}
"ssl.certificate-depth" => {
let i = try!(u8::from_str(&value));
return Ok(GlusterOption::SslCertificateDepth(i));
}
"ssl.cipher-list" => {
return Ok(GlusterOption::SslCipherList(value));
}
"storage-health-check-interval" => {
let i = try!(u16::from_str(&value));
return Ok(GlusterOption::StorageHealthCheckInterval(i));
}
_ => {
return Err(GlusterError::new(format!("Unknown option: {}", s)));
}
}
}
}
#[derive(Debug)]
pub enum GlusterError {
AddrParseError(std::net::AddrParseError),
FromUtf8Error(std::string::FromUtf8Error),
IoError(io::Error),
NoVolumesPresent,
ParseError(uuid::ParseError),
ParseBoolErr(std::str::ParseBoolError),
ParseIntError(std::num::ParseIntError),
RegexError(regex::Error),
SerdeError(serde_json::Error),
}
impl GlusterError {
pub fn new(err: String) -> GlusterError {
GlusterError::IoError(io::Error::new(std::io::ErrorKind::Other, err))
}
pub fn to_string(&self) -> String {
match *self {
GlusterError::IoError(ref err) => err.description().to_string(),
GlusterError::FromUtf8Error(ref err) => err.description().to_string(),
GlusterError::ParseError(ref err) => err.description().to_string(),
GlusterError::AddrParseError(ref err) => err.description().to_string(),
GlusterError::ParseIntError(ref err) => err.description().to_string(),
GlusterError::ParseBoolErr(ref err) => err.description().to_string(),
GlusterError::RegexError(ref err) => err.description().to_string(),
GlusterError::NoVolumesPresent => "No volumes present".to_string(),
GlusterError::SerdeError(ref err) => err.description().to_string(),
}
}
}
impl From<io::Error> for GlusterError {
fn from(err: io::Error) -> GlusterError {
GlusterError::IoError(err)
}
}
impl From<std::string::FromUtf8Error> for GlusterError {
fn from(err: std::string::FromUtf8Error) -> GlusterError {
GlusterError::FromUtf8Error(err)
}
}
impl From<uuid::ParseError> for GlusterError {
fn from(err: uuid::ParseError) -> GlusterError {
GlusterError::ParseError(err)
}
}
impl From<std::net::AddrParseError> for GlusterError {
fn from(err: std::net::AddrParseError) -> GlusterError {
GlusterError::AddrParseError(err)
}
}
impl From<std::num::ParseIntError> for GlusterError {
fn from(err: std::num::ParseIntError) -> GlusterError {
GlusterError::ParseIntError(err)
}
}
impl From<std::str::ParseBoolError> for GlusterError {
fn from(err: std::str::ParseBoolError) -> GlusterError {
GlusterError::ParseBoolErr(err)
}
}
impl From<regex::Error> for GlusterError {
fn from(err: regex::Error) -> GlusterError {
GlusterError::RegexError(err)
}
}
impl From<serde_json::Error> for GlusterError {
fn from(err: serde_json::Error) -> GlusterError {
GlusterError::SerdeError(err)
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct BrickStatus {
pub brick: Brick,
pub tcp_port: u16,
pub rdma_port: u16,
pub online: bool,
pub pid: u16,
}
impl Ord for BrickStatus {
fn cmp(&self, other: &BrickStatus) -> Ordering {
self.brick.peer.cmp(&other.brick.peer)
}
}
impl PartialOrd for BrickStatus {
fn partial_cmp(&self, other: &BrickStatus) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Quota {
pub path: PathBuf,
pub limit: u64,
pub used: u64,
}
fn process_output(output: std::process::Output) -> Result<i32, GlusterError> {
let status = output.status;
if status.success() {
return Ok(0);
} else {
return Err(GlusterError::new(try!(String::from_utf8(output.stderr))));
}
}
fn run_command<T>(
command: &str,
arg_list: &Vec<T>,
as_root: bool,
script_mode: bool,
) -> std::process::Output
where
T: AsRef<OsStr>,
{
if as_root {
let mut cmd = std::process::Command::new("sudo");
cmd.arg(command);
if script_mode {
cmd.arg("--mode=script");
}
for arg in arg_list {
cmd.arg(&arg);
}
debug!("About to run command: {:?}", cmd);
let output = cmd.output().unwrap_or_else(
|e| panic!("failed to execute process: {} ", e),
);
return output;
} else {
let mut cmd = std::process::Command::new(command);
if script_mode {
cmd.arg("--mode=script");
}
for arg in arg_list {
cmd.arg(&arg);
}
debug!("About to run command: {:?}", cmd);
let output = cmd.output().unwrap_or_else(
|e| panic!("failed to execute process: {} ", e),
);
return output;
}
}
pub fn get_local_ip() -> Result<IpAddr, GlusterError> {
let mut default_route: Vec<String> = Vec::new();
default_route.push("route".to_string());
default_route.push("show".to_string());
default_route.push("0.0.0.0/0".to_string());
let cmd_output = run_command("ip", &default_route, false, false);
let default_route_stdout: String = try!(String::from_utf8(cmd_output.stdout));
let addr_regex = try!(Regex::new(r"(?P<addr>via \S+)"));
let default_route_parse = match addr_regex.captures(&default_route_stdout) {
Some(a) => a,
None => {
return Err(GlusterError::new(format!(
"Unable to parse default route from: {}",
&default_route_stdout
)));
}
};
let addr_raw = match default_route_parse.name("addr") {
Some(a) => a,
None => {
return Err(GlusterError::new(format!(
"Unable to find addr default route from: {}",
&default_route_stdout
)));
}
};
let addr: Vec<&str> = addr_raw.split(" ").skip(1).collect();
let mut arg_list: Vec<String> = Vec::new();
arg_list.push("route".to_string());
arg_list.push("get".to_string());
arg_list.push(addr[0].to_string());
let src_address_output = run_command("ip", &arg_list, false, false);
let local_address_stdout = try!(String::from_utf8(src_address_output.stdout));
let src_regex = try!(Regex::new(r"(?P<src>src \S+)"));
let capture_output = match src_regex.captures(&local_address_stdout) {
Some(a) => a,
None => {
return Err(GlusterError::new(format!(
"Unable to parse local_address from: {}",
&local_address_stdout
)));
}
};
let local_address_src = match capture_output.name("src") {
Some(a) => a,
None => {
return Err(GlusterError::new(format!(
"Unable to parse src from: {}",
&local_address_stdout
)));
}
};
let local_ip: Vec<&str> = local_address_src.split(" ").skip(1).collect();
let ip_addr = try!(local_ip[0].trim().parse::<IpAddr>());
return Ok(ip_addr);
}
pub fn resolve_to_ip(address: &str) -> Result<String, String> {
if cfg!(test) {
return Ok("test_ip".to_string());
}
if address == "localhost" {
let local_ip = try!(get_local_ip().map_err(|e| e.to_string()));
debug!(
"hostname is localhost. Resolving to local ip {}",
&local_ip.to_string()
);
return Ok(local_ip.to_string());
}
let mut arg_list: Vec<String> = Vec::new();
arg_list.push("+short".to_string());
arg_list.push(address.trim().to_string());
let output = run_command("dig", &arg_list, false, false);
let status = output.status;
if status.success() {
let output_str = try!(String::from_utf8(output.stdout).map_err(|e| e.to_string()));
let trimmed = output_str.trim().trim_right_matches(".");
return Ok(trimmed.to_string());
} else {
return Err(try!(
String::from_utf8(output.stderr).map_err(|e| e.to_string())
));
}
}
pub fn get_local_hostname() -> Result<String, GlusterError> {
let mut f = try!(File::open("/etc/hostname"));
let mut s = String::new();
try!(f.read_to_string(&mut s));
return Ok(s.trim().to_string());
}
pub fn translate_to_bytes<T>(value: &str) -> Option<T>
where
T: FromStr + ::std::ops::Mul<Output = T> + Copy,
{
let k = match T::from_str("1024") {
Ok(n) => n,
Err(_) => return None,
};
if value.ends_with("PB") {
match value.trim_right_matches("PB").parse::<T>() {
Ok(n) => return Some(n * k * k * k * k * k),
Err(_) => return None,
};
} else if value.ends_with("TB") {
match value.trim_right_matches("TB").parse::<T>() {
Ok(n) => return Some(n * k * k * k * k),
Err(_) => return None,
};
} else if value.ends_with("GB") {
match value.trim_right_matches("GB").parse::<T>() {
Ok(n) => return Some(n * k * k * k),
Err(_) => return None,
};
} else if value.ends_with("MB") {
match value.trim_right_matches("MB").parse::<T>() {
Ok(n) => return Some(n * k * k),
Err(_) => return None,
};
} else if value.ends_with("KB") {
match value.trim_right_matches("KB").parse::<T>() {
Ok(n) => return Some(n * k),
Err(_) => return None,
};
} else if value.ends_with("Bytes") {
match value.trim_right_matches("Bytes").parse::<T>() {
Ok(n) => return Some(n),
Err(_) => return None,
};
} else {
return None;
}
}
pub fn get_local_bricks(volume: &str) -> Result<Vec<Brick>, GlusterError> {
let vol_info = volume_info(volume)?;
let local_ip = get_local_ip()?.to_string();
let bricks: Vec<Brick> = vol_info
.bricks
.iter()
.filter(|brick| brick.peer.hostname == local_ip)
.map(|brick| brick.clone())
.collect();
Ok(bricks)
}