pub mod fop;
pub mod heal;
pub mod peer;
mod rpc;
pub mod volume;
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 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::{volume_info, Brick};
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),
DiagnosticsBrickLevel(log::Level),
DiagnosticsClientLevel(log::Level),
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::DiagnosticsBrickLevel(_) => "diagnostics.brick-log-level".to_string(),
GlusterOption::DiagnosticsClientLevel(_) => "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::DiagnosticsBrickLevel(val) => val.to_string(),
GlusterOption::DiagnosticsClientLevel(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" => Ok(GlusterOption::AuthAllow(value)),
"auth-reject" => Ok(GlusterOption::AuthReject(value)),
"auth.ssl-allow" => Ok(GlusterOption::SslAllow(value)),
"client.ssl" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::ClientSsl(t))
}
"cluster.favorite-child-policy" => {
let policy = SplitBrainPolicy::from_str(&value)?;
Ok(GlusterOption::FavoriteChildPolicy(policy))
}
"client-grace-timeout" => {
let i = i64::from_str(&value)?;
Ok(GlusterOption::ClientGraceTimeout(i))
}
"cluster-self-heal-window-size" => {
let i = u16::from_str(&value)?;
Ok(GlusterOption::ClusterSelfHealWindowSize(i))
}
"cluster-data-self-heal-algorithm" => {
let s = SelfHealAlgorithm::from_str(&value);
Ok(GlusterOption::ClusterDataSelfHealAlgorithm(s))
}
"cluster-min-free-disk" => {
let i = u8::from_str(&value)?;
Ok(GlusterOption::ClusterMinFreeDisk(i))
}
"cluster-stripe-block-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::ClusterStripeBlockSize(i))
}
"cluster-self-heal-daemon" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::ClusterSelfHealDaemon(t))
}
"cluster-ensure-durability" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::ClusterEnsureDurability(t))
}
"diagnostics-brick-log-level" => {
let l = log::Level::from_str(&value).unwrap_or(log::Level::Debug);
Ok(GlusterOption::DiagnosticsBrickLevel(l))
}
"diagnostics-client-log-level" => {
let l = log::Level::from_str(&value).unwrap_or(log::Level::Debug);
Ok(GlusterOption::DiagnosticsClientLevel(l))
}
"diagnostics-latency-measurement" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::DiagnosticsLatencyMeasurement(t))
}
"diagnostics.count-fop-hits" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::DiagnosticsCountFopHits(t))
}
"diagnostics.stats-dump-interval" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::DiagnosticsStatsDumpInterval(i))
}
"diagnostics.fop-sample-buf-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::DiagnosticsFopSampleBufSize(i))
}
"diagnostics.fop-sample-interval" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::DiagnosticsFopSampleInterval(i))
}
"diagnostics.stats-dnscache-ttl-sec" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::DiagnosticsStatsDnscacheTtlSec(i))
}
"diagnostics-dump-fd-stats" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::DiagnosticsDumpFdStats(t))
}
"features-read-only" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::FeaturesReadOnly(t))
}
"features-lock-heal" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::FeaturesLockHeal(t))
}
"features-quota-timeout" => {
let i = u16::from_str(&value)?;
Ok(GlusterOption::FeaturesQuotaTimeout(i))
}
"geo-replication-indexing" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::GeoReplicationIndexing(t))
}
"network-frame-timeout" => {
let i = u16::from_str(&value)?;
Ok(GlusterOption::NetworkFrameTimeout(i))
}
"nfs-enable-ino32" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsEnableIno32(t))
}
"nfs-volume-access" => {
let s = AccessMode::from_str(&value);
Ok(GlusterOption::NfsVolumeAccess(s))
}
"nfs-trusted-write" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsTrustedWrite(t))
}
"nfs-trusted-sync" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsTrustedSync(t))
}
"nfs-export-dir" => Ok(GlusterOption::NfsExportDir(value)),
"nfs-export-volumes" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsExportVolumes(t))
}
"nfs-rpc-auth-unix" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsRpcAuthUnix(t))
}
"nfs-rpc-auth-null" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsRpcAuthNull(t))
}
"nfs-ports-insecure" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsPortsInsecure(t))
}
"nfs-addr-namelookup" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsAddrNamelookup(t))
}
"nfs-register-with-portmap" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsRegisterWithPortmap(t))
}
"nfs-disable" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::NfsDisable(t))
}
"performance-write-behind-window-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::PerformanceWriteBehindWindowSize(i))
}
"performance-io-thread-count" => {
let i = u8::from_str(&value)?;
Ok(GlusterOption::PerformanceIoThreadCount(i))
}
"performance-flush-behind" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::PerformanceFlushBehind(t))
}
"performance-cache-max-file-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::PerformanceCacheMaxFileSize(i))
}
"performance-cache-min-file-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::PerformanceCacheMinFileSize(i))
}
"performance-cache-refresh-timeout" => {
let i = u8::from_str(&value)?;
Ok(GlusterOption::PerformanceCacheRefreshTimeout(i))
}
"performance-cache-size" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::PerformanceCacheSize(i))
}
"performance-readdir-ahead" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::PerformanceReadDirAhead(t))
}
"performance-parallel-readdir" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::PerformanceReadDirAhead(t))
}
"performance-readdir-cache-limit" => {
let i = u64::from_str(&value)?;
Ok(GlusterOption::PerformanceReadDirAheadCacheLimit(i))
}
"server.ssl" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::ServerSsl(t))
}
"server-allow-insecure" => {
let t = Toggle::from_str(&value);
Ok(GlusterOption::ServerAllowInsecure(t))
}
"server-grace-timeout" => {
let i = u16::from_str(&value)?;
Ok(GlusterOption::ServerGraceTimeout(i))
}
"server-statedump-path" => {
let p = PathBuf::from(&value);
Ok(GlusterOption::ServerStatedumpPath(p))
}
"ssl.certificate-depth" => {
let i = u8::from_str(&value)?;
Ok(GlusterOption::SslCertificateDepth(i))
}
"ssl.cipher-list" => Ok(GlusterOption::SslCipherList(value)),
"storage-health-check-interval" => {
let i = u16::from_str(&value)?;
Ok(GlusterOption::StorageHealthCheckInterval(i))
}
_ => 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::parser::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::parser::ParseError> for GlusterError {
fn from(err: uuid::parser::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() {
Ok(0)
} else {
Err(GlusterError::new(String::from_utf8(output.stderr)?))
}
}
fn run_command<T>(
command: &str,
arg_list: &[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);
cmd.output()
.unwrap_or_else(|e| panic!("failed to execute process: {} ", e))
} 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);
cmd.output()
.unwrap_or_else(|e| panic!("failed to execute process: {} ", e))
}
}
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 = String::from_utf8(cmd_output.stdout)?;
let default_addr = default_route_stdout
.split_whitespace()
.collect::<Vec<&str>>();
let arg_list = vec![
"route".to_string(),
"get".to_string(),
default_addr[2].to_string(),
];
let src_address_output = run_command("ip", &arg_list, false, false);
let src_addr_output: String = String::from_utf8(src_address_output.stdout)?;
let local_ip = src_addr_output.split_whitespace().collect::<Vec<&str>>();
let ip_addr = local_ip[4].trim().parse::<IpAddr>()?;
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 = 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 = String::from_utf8(output.stdout).map_err(|e| e.to_string())?;
let trimmed = output_str.trim().trim_right_matches('.');
Ok(trimmed.to_string())
} else {
Err(String::from_utf8(output.stderr).map_err(|e| e.to_string())?)
}
}
pub fn get_local_hostname() -> Result<String, GlusterError> {
let mut f = File::open("/etc/hostname")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
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) => Some(n * k * k * k * k * k),
Err(_) => None,
}
} else if value.ends_with("TB") {
match value.trim_right_matches("TB").parse::<T>() {
Ok(n) => Some(n * k * k * k * k),
Err(_) => None,
}
} else if value.ends_with("GB") {
match value.trim_right_matches("GB").parse::<T>() {
Ok(n) => Some(n * k * k * k),
Err(_) => None,
}
} else if value.ends_with("MB") {
match value.trim_right_matches("MB").parse::<T>() {
Ok(n) => Some(n * k * k),
Err(_) => None,
}
} else if value.ends_with("KB") {
match value.trim_right_matches("KB").parse::<T>() {
Ok(n) => Some(n * k),
Err(_) => None,
}
} else if value.ends_with("Bytes") {
match value.trim_right_matches("Bytes").parse::<T>() {
Ok(n) => Some(n),
Err(_) => None,
}
} else {
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)
.cloned()
.collect();
Ok(bricks)
}