6
6
7
7
use camino_tempfile:: tempfile_in;
8
8
use dropshot:: HttpError ;
9
+ use futures:: StreamExt ;
10
+ use futures:: stream:: FuturesUnordered ;
9
11
use range_requests:: make_get_response;
10
- use sled_agent_config_reconciler:: InternalDisksReceiver ;
12
+ use sled_agent_config_reconciler:: AvailableDatasetsReceiver ;
11
13
use slog:: Logger ;
12
14
use slog_error_chain:: InlineErrorChain ;
13
15
use tokio:: io:: AsyncSeekExt ;
@@ -43,15 +45,15 @@ impl From<Error> for HttpError {
43
45
44
46
pub struct SupportBundleLogs < ' a > {
45
47
log : & ' a Logger ,
46
- internal_disks_rx : & ' a InternalDisksReceiver ,
48
+ available_datasets_rx : AvailableDatasetsReceiver ,
47
49
}
48
50
49
51
impl < ' a > SupportBundleLogs < ' a > {
50
52
pub fn new (
51
53
log : & ' a Logger ,
52
- internal_disks_rx : & ' a InternalDisksReceiver ,
54
+ available_datasets_rx : AvailableDatasetsReceiver ,
53
55
) -> Self {
54
- Self { log, internal_disks_rx }
56
+ Self { log, available_datasets_rx }
55
57
}
56
58
57
59
/// Get a list of zones on a sled containing logs that we want to include in
@@ -78,12 +80,53 @@ impl<'a> SupportBundleLogs<'a> {
78
80
where
79
81
Z : Into < String > ,
80
82
{
81
- // We are using an M.2 device for temporary storage to assemble a zip
82
- // file made up of all of the discovered zone's logs.
83
- let current_internal_disks = self . internal_disks_rx . current ( ) ;
84
- let mut m2_debug_datasets = current_internal_disks. all_debug_datasets ( ) ;
85
- let tempdir = m2_debug_datasets. next ( ) . ok_or ( Error :: MissingStorage ) ?;
86
- let mut tempfile = tempfile_in ( tempdir) ?;
83
+ // Attempt to find a U.2 device with the most available free space
84
+ // for temporary storage to assemble a zip file made up of all of the
85
+ // discovered zone's logs.
86
+ let mounted_debug_datasets =
87
+ self . available_datasets_rx . all_mounted_debug_datasets ( ) ;
88
+ let storage_paths_to_size: Vec < _ > = mounted_debug_datasets
89
+ . into_iter ( )
90
+ . map ( |dataset_path| {
91
+ let path = dataset_path. path ;
92
+ async move {
93
+ match illumos_utils:: zfs:: Zfs :: get_value (
94
+ path. as_str ( ) ,
95
+ "available" ,
96
+ )
97
+ . await
98
+ {
99
+ Ok ( size_str) => match size_str. parse :: < usize > ( ) {
100
+ Ok ( size) => Some ( ( path, size) ) ,
101
+ Err ( e) => {
102
+ warn ! (
103
+ & self . log,
104
+ "failed to parse available size for the \
105
+ dataset at path {path}: {e}"
106
+ ) ;
107
+ None
108
+ }
109
+ } ,
110
+ Err ( e) => {
111
+ warn ! (
112
+ & self . log,
113
+ "failed to get available size for the dataset \
114
+ at path {path}: {e}"
115
+ ) ;
116
+ None
117
+ }
118
+ }
119
+ }
120
+ } )
121
+ . collect :: < FuturesUnordered < _ > > ( )
122
+ . collect ( )
123
+ . await ;
124
+ let ( largest_avail_space, _) = storage_paths_to_size
125
+ . into_iter ( )
126
+ . flatten ( )
127
+ . max_by_key ( |( _, size) | * size)
128
+ . ok_or ( Error :: MissingStorage ) ?;
129
+ let mut tempfile = tempfile_in ( largest_avail_space) ?;
87
130
88
131
let log = self . log . clone ( ) ;
89
132
let zone = zone. into ( ) ;
0 commit comments