Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
Finish first draft
Browse files Browse the repository at this point in the history
Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Update the 'mounted' column to bool instead of Option<bool>

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Add sqlx data file

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Fixups

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

sqlx data

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Fixup in gui

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Fix issue where snapshot mount status is not being updated.

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Update sqlx

Signed-off-by: johnsonw <wjohnson@whamcloud.com>
  • Loading branch information
johnsonw authored and jgrund committed Nov 11, 2020
1 parent 85bc5e1 commit f1abce0
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 126 deletions.
144 changes: 121 additions & 23 deletions iml-agent/src/action_plugins/lustre/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,62 @@

use crate::{agent_error::ImlAgentError, device_scanner_client, lustre::lctl};
use chrono::{DateTime, TimeZone, Utc};
use futures::{future::try_join_all, TryFutureExt};
use iml_wire_types::snapshot::{Create, Destroy, List, Mount, Snapshot, Unmount};

async fn get_snapshot_fsname_and_status<'a>(
snapshot_name: String,
target: &'a str,
filesystem_name: String,
create_time: DateTime<Utc>,
modify_time: DateTime<Utc>,
comment: Option<String>,
mounts: &[device_types::mount::Mount],
) -> Result<
Option<(
String,
String,
DateTime<Utc>,
DateTime<Utc>,
Option<String>,
String,
bool,
)>,
ImlAgentError,
> {
let snapshot_fsname = get_snapshot_label(&snapshot_name, &target).await?;

let snapshot_fsname = if let Some(name) = snapshot_fsname {
name
} else {
return Ok(None);
};

let mounted: bool = mounts
.iter()
.filter(|x| x.opts.0.split(',').any(|x| x == "nomgs"))
.filter(|x| x.fs_type.0 == "lustre")
.find_map(|x| {
let s = x.opts.0.split(',').find(|x| x.starts_with("svname="))?;

let s = s.split('=').nth(1)?.split('-').next()?;

Some(s.to_string())
})
.map(|x| x == snapshot_fsname)
.unwrap_or_else(|| false);

Ok(Some((
snapshot_name,
filesystem_name,
create_time,
modify_time,
comment,
snapshot_fsname,
mounted,
)))
}

pub async fn list(l: List) -> Result<Vec<Snapshot>, ImlAgentError> {
let mut args = vec!["--device", &l.target, "snapshot", "-l"];
if let Some(name) = &l.name {
Expand All @@ -18,37 +72,81 @@ pub async fn list(l: List) -> Result<Vec<Snapshot>, ImlAgentError> {
return Ok(vec![]);
}

let mounts = device_scanner_client::get_mounts().await?;
let fs_name = &l.target.split('-').next().map(String::from);

for snap in parse_device_snapshots(stdout) {
let label = get_snapshot_label(&snap.0, &l.target).await?;
let filesystem_name = if let Some(name) = fs_name {
name.to_string()
} else {
return Ok(vec![]);
};

if label.is_none() {
continue;
}
let mounts = device_scanner_client::get_mounts().await?;

mounts
.iter()
.filter(|x| x.opts.0.split(',').any(|x| x == "nomgs"))
.filter(|x| x.fs_type.0 == "lustre")
.find_map(|x| {
let s = x.opts.0.split(',').find(|x| x.starts_with("svname="))?;
let xs = parse_device_snapshots(stdout).into_iter().map(
|(snapshot_name, create_time, modify_time, comment)| {
let filesystem_name = filesystem_name.to_string();

let xs = get_snapshot_fsname_and_status(
snapshot_name.to_string(),
&l.target,
filesystem_name.to_string(),
create_time,
modify_time,
comment,
&mounts,
)
.map_ok(|x| {
x.map(
|(
snapshot_name,
filesystem_name,
create_time,
modify_time,
comment,
snapshot_fsname,
mounted,
)| Snapshot {
filesystem_name,
snapshot_name,
create_time,
modify_time,
comment,
snapshot_fsname,
mounted,
},
)
});

let s = s.split('=').nth(1)?;
xs
},
);

Some(s.to_string())
});
}
let snapshots = try_join_all(xs)
.await?
.into_iter()
.filter_map(|x| x)
.collect::<Vec<Snapshot>>();

return Ok(vec![]);
return Ok(snapshots);
}

async fn get_snapshot_label(name: &str, target: &str) -> Result<Option<String>, ImlAgentError> {
let x = lctl(vec!["--device", target, "snapshot", "--get_label", name]).await?;

match x.trim() {
"" => Ok(None),
_ => Ok(Some(x)),
async fn get_snapshot_label(
snapshot_name: &str,
target: &str,
) -> Result<Option<String>, ImlAgentError> {
let x = lctl(vec![
"--device",
target,
"snapshot",
"--get_label",
snapshot_name,
])
.await?;
let x = x.trim().split('-').next();

match x {
None => Ok(None),
Some(label) => Ok(Some(label.to_string())),
}
}

Expand Down
123 changes: 78 additions & 45 deletions iml-agent/src/daemon_plugins/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ use crate::{
action_plugins::lustre::snapshot,
agent_error::ImlAgentError,
daemon_plugins::{DaemonPlugin, Output},
lustre::{lctl, list_mdt0s},
device_scanner_client,
lustre::list_mdt0s,
};
use async_trait::async_trait;
use futures::{
future::{join_all, AbortHandle, Abortable},
future::{try_join_all, AbortHandle, Abortable},
lock::Mutex,
Future, FutureExt,
};
use iml_wire_types::snapshot::{List, Snapshot};
use std::collections::BTreeSet;
use std::{pin::Pin, sync::Arc, time::Duration};
use std::{
collections::{HashMap, HashSet},
pin::Pin,
sync::Arc,
time::Duration,
};
use tokio::time::delay_for;

struct State {
Expand All @@ -46,48 +51,70 @@ pub(crate) fn create() -> SnapshotList {
}
}

async fn list() -> Result<Vec<Snapshot>, ()> {
let xs = list_mdt0s().await;
async fn list() -> Result<Option<HashMap<String, Vec<Snapshot>>>, ImlAgentError> {
// list the mounts
// remove any mdt0's that are snapshots
let snapshot_mounts = device_scanner_client::get_snapshot_mounts()
.await?
.into_iter()
.map(|x| {
let s = x
.opts
.0
.split(',')
.find(|x| x.starts_with("svname="))
.unwrap_or_else(|| "");

let s = s.split('=').nth(1).unwrap_or_else(|| "");

s.to_string()
})
.filter(|x| x != "")
.collect::<HashSet<String>>();
tracing::debug!("snapshot mounts {:?}", snapshot_mounts);

let xs = list_mdt0s().await.into_iter().collect::<HashSet<String>>();
let xs = xs
.difference(&snapshot_mounts)
.map(|x| x.to_string())
.collect::<Vec<String>>();

tracing::debug!("mdt0s: {:?}", &xs);

xs.into_iter().map(|x| async move {});

Ok(vec![])

// let futs = fss.into_iter().map(|fs| async move {
// snapshot::list(List {
// fsname: fs.clone(),
// name: None,
// })
// .await
// .map_err(|e| (fs, e))
// });

// let (oks, errs): (Vec<_>, Vec<_>) = join_all(futs).await.into_iter().partition(Result::is_ok);

// let snaps = oks
// .into_iter()
// .map(|x| x.unwrap())
// .flatten()
// .collect::<Vec<Snapshot>>();

// let snapshot_fsnames = snaps
// .iter()
// .map(|s| &s.snapshot_fsname)
// .collect::<BTreeSet<&String>>();

// let really_failed_fss = errs
// .into_iter()
// .map(|x| x.unwrap_err())
// .filter(|x| !snapshot_fsnames.contains(&x.0))
// .collect::<Vec<_>>();

// if !really_failed_fss.is_empty() {
// // XXX debug because of false positives
// tracing::debug!("listing failed: {:?}", really_failed_fss);
// }
// Ok(snaps)
if xs.is_empty() {
tracing::debug!("No mdt0's. Returning none.");
return Ok(None);
}

let xs = xs.into_iter().map(|x| async move {
let fs_name = x.split('-').next();
tracing::debug!("fs_name is: {:?}", fs_name);

if let Some(fs_name) = fs_name {
snapshot::list(List {
target: x.to_string(),
name: None,
})
.await
.map(|x| (fs_name.to_string(), x))
.map_err(|x| {
tracing::debug!("Error calling snapshot list: {:?}", x);
x
})
} else {
tracing::debug!("No fs_name. Returning MarkerNotFound error.");
Err(ImlAgentError::MarkerNotFound)
}
});

let snapshots = try_join_all(xs)
.await?
.into_iter()
.collect::<HashMap<String, Vec<Snapshot>>>();

tracing::debug!("snapshots: {:?}", snapshots);

Ok(Some(snapshots))
}

#[async_trait]
Expand All @@ -105,14 +132,20 @@ impl DaemonPlugin for SnapshotList {
async move {
loop {
if let Ok(snapshots) = list().await {
tracing::debug!("snapshots ({}): {:?}", snapshots.len(), &snapshots);
let output = snapshots
.map(|xs| serde_json::to_value(xs))
.transpose()
.unwrap();

let output = serde_json::to_value(snapshots).map(Some).unwrap();
let mut lock = state.lock().await;

if lock.output != output {
tracing::debug!("Snapshot output changed. Updating.");
lock.output = output;
lock.updated = true;
}
} else {
tracing::debug!("Error calling list(). Not processing snapshots.");
}
delay_for(Duration::from_secs(10)).await;
}
Expand Down
5 changes: 2 additions & 3 deletions iml-gui/crate/src/page/snapshot/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,8 @@ pub fn view(model: &Model, cache: &ArcCache) -> Node<Msg> {
x.comment.as_deref().unwrap_or("---")
],
table::td_center(plain![match &x.mounted {
Some(true) => "mounted",
Some(false) => "unmounted",
None => "unknown",
true => "mounted",
false => "unmounted",
}]),
]
})]
Expand Down
5 changes: 2 additions & 3 deletions iml-manager-cli/src/display_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,8 @@ impl IntoTable for Vec<Snapshot> {
s.snapshot_name,
s.create_time.to_rfc2822(),
match s.mounted {
Some(true) => "mounted",
Some(false) => "unmounted",
None => "---",
true => "mounted",
false => "unmounted",
}
.to_string(),
s.comment.unwrap_or_else(|| "---".to_string()),
Expand Down
Loading

0 comments on commit f1abce0

Please sign in to comment.