1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use des::to_f64;

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct OsdMap {
    pub pool_max: i32,
    pub max_osd: i32,
    pub created: String,
    pub modified: String,
    pub osd_xinfo: Vec<OsdXinfo>,
    pub osds: Vec<Osds>,
    pub epoch: i32,
    pub flags: String,
    pub cluster_snapshot: String,
    pub pools: Vec<Pools>,
    pub fsid: String,
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Default {
    pub k: String,
    pub technique: String,
    pub m: String,
    pub plugin: String,
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Osds {
    pub heartbeat_back_addr: String,
    pub uuid: String,
    #[serde(deserialize_with = "to_f64")]
    pub weight: f64,
    pub up_from: i32,
    pub heartbeat_front_addr: String,
    pub down_at: i32,
    pub up: i32,
    pub lost_at: i32,
    #[serde(deserialize_with = "to_f64")]
    pub primary_affinity: f64,
    pub state: Vec<String>,
    pub last_clean_begin: i32,
    pub last_clean_end: i32,
    pub public_addr: String,
    pub up_thru: i32,
    pub cluster_addr: String,
    pub osd: i32,
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct OsdXinfo {
    #[serde(deserialize_with = "to_f64")]
    pub laggy_probability: f64,
    pub laggy_interval: i32,
    pub features: u64,
    pub old_weight: Option<i32>,
    pub down_stamp: String,
    pub osd: i32,
}

#[derive(Deserialize, Debug, PartialEq, Clone)]
pub struct Pools {
    pub cache_target_full_ratio_micro: i32,
    pub fast_read: Option<bool>,
    pub stripe_width: i32,
    pub flags_names: String,
    pub tier_of: i32,
    pub hit_set_grade_decay_rate: Option<i32>,
    pub pg_placement_num: i32,
    pub use_gmt_hitset: Option<bool>,
    pub quota_max_bytes: i32,
    pub erasure_code_profile: String,
    pub expected_num_objects: Option<i32>,
    // "replicated size"
    pub size: i32,
    pub snap_seq: i32,
    pub auid: i32,
    pub cache_min_flush_age: i32,
    pub hit_set_period: i32,
    pub min_read_recency_for_promote: i32,
    pub target_max_objects: i32,
    pub pg_num: i32,
    pub crush_ruleset: Option<i32>,
    pub crush_rule: Option<i32>,
    pub pool_name: String,
    pub cache_min_evict_age: i32,
    pub snap_mode: String,
    pub cache_mode: String,
    pub min_size: i32,
    pub cache_target_dirty_high_ratio_micro: Option<i32>,
    pub crash_replay_interval: i32,
    pub object_hash: i32,
    pub write_tier: i32,
    pub cache_target_dirty_ratio_micro: i32,
    pub pool: i32,
    pub removed_snaps: String,
    pub last_force_op_resend: String,
    pub quota_max_objects: i32,
    pub hit_set_count: i32,
    pub flags: i32,
    pub target_max_bytes: i32,
    pub snap_epoch: i32,
    pub hit_set_search_last_n: Option<i32>,
    pub last_change: String,
    pub min_write_recency_for_promote: Option<i32>,
    pub read_tier: i32,
}

#[cfg(test)]
mod tests {
    use super::*;
    use from::FromFile;

    // Luminous tests
    #[test]
    #[should_panic]
    fn osdmap_from_luminous_file_panic() {
        let osdmap = OsdMap::from_file("test/luminous/osd_dump_non_safe.json").unwrap();
        // If this is safe to remove then osd's len should be min_size + 1
        assert_eq!(osdmap.osds.len(), (osdmap.pools[0].min_size + 1) as usize);
    }

    // Jewel tests
    #[test]
    #[should_panic]
    fn osdmap_from_jewel_file_panic() {
        let osdmap = OsdMap::from_file("test/jewel/osd_dump_safe.json").unwrap();
        // If this is safe to remove then osd's len should be min_size + 1
        assert_eq!(osdmap.osds.len(), 0);
    }

    #[test]
    fn osdmap_from_jewel_file() {
        let osdmap = OsdMap::from_file("test/jewel/osd_dump_safe.json").unwrap();
        // Default config for min_size is 2
        assert_eq!(osdmap.pools.first().unwrap().min_size, 2);
    }

    #[test]
    #[should_panic]
    fn osdmap_from_jewel_file_no_osd_panic() {
        let osdmap = OsdMap::from_file("test/jewel/osd_dump_no_osd.json").unwrap();
        // This has no osds so len should be 0
        assert_eq!(osdmap.osds.len(), 3);
    }

    #[test]
    fn osdmap_from_jewel_file_no_osd() {
        let osdmap = OsdMap::from_file("test/jewel/osd_dump_no_osd.json").unwrap();
        let mut osds_up: Vec<i32> = Vec::new();
        // There should be no OSDs present
        for osd in osdmap.osds {
            if osd.up == 1 {
                osds_up.push(1);
            }
        }
        assert_eq!(osds_up.len(), 0);
    }

    #[test]
    fn osdmap_from_jewel_file_non_safe() {
        let osdmap = OsdMap::from_file("test/jewel/osd_dump_non_safe.json").unwrap();
        let mut osds_up: Vec<i32> = Vec::new();
        // Since this is non-safe there should be min_size or less OSDs present
        for osd in osdmap.osds {
            if osd.up == 1 {
                osds_up.push(1);
            }
        }
        assert_eq!(osds_up.len() as i32, osdmap.pools.first().unwrap().min_size);
    }

    // Firefly tests
    #[test]
    fn osdmap_from_firefly_file() {
        let osdmap = OsdMap::from_file("test/firefly/osd_dump_safe.json").unwrap();
        assert_eq!(osdmap.pools.first().unwrap().min_size, 2);
    }

    #[test]
    #[should_panic]
    fn osdmap_from_firefly_file_panic() {
        let osdmap = OsdMap::from_file("test/firefly/osd_dump_safe.json").unwrap();
        // If this is safe to remove then osd's len should be min_size + 1
        assert_eq!(osdmap.osds.len() as i32, 0);
    }

    #[test]
    #[should_panic]
    fn osdmap_from_ceph_panic() {
        use from::FromCeph;
        let osdmap = OsdMap::from_ceph("osd dump");
        assert_eq!(osdmap.is_ok(), true);
    }
}