|
21 | 21 | import btrfs |
22 | 22 | import os |
23 | 23 | import sys |
| 24 | +from math import floor |
| 25 | + |
| 26 | +def calculate_munin_values(fs): |
| 27 | + # Get detailed usage statistics. |
| 28 | + usage = fs.usage() |
| 29 | + |
| 30 | + # Whatever happens, we should not stack the graph above this. IOW, the |
| 31 | + # unallocated bytes we end up with is just whatever is left over after |
| 32 | + # doing all other things. |
| 33 | + left = usage.total |
| 34 | + |
| 35 | + if not fs.mixed_groups(): |
| 36 | + data_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_DATA].used |
| 37 | + data_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_DATA].allocated |
| 38 | + metadata_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_METADATA].used |
| 39 | + metadata_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_METADATA].allocated |
| 40 | + left = left - data_allocated - metadata_allocated |
| 41 | + usage_info = { |
| 42 | + 'data_used': data_used, |
| 43 | + 'data_allocated': data_allocated, |
| 44 | + 'data_unused': data_allocated - data_used, |
| 45 | + 'metadata_used': metadata_used, |
| 46 | + 'metadata_allocated': metadata_allocated, |
| 47 | + 'metadata_unused': metadata_allocated - metadata_used, |
| 48 | + } |
| 49 | + else: |
| 50 | + mixed_type = btrfs.BLOCK_GROUP_DATA | btrfs.BLOCK_GROUP_METADATA |
| 51 | + used = usage.block_group_type_usage[mixed_type].used |
| 52 | + allocated = usage.block_group_type_usage[mixed_type].allocated |
| 53 | + left -= allocated |
| 54 | + usage_info = { |
| 55 | + 'data_metadata_used': used, |
| 56 | + 'data_metadata_unused': allocated-used, |
| 57 | + } |
| 58 | + system_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_SYSTEM].used |
| 59 | + usage_info['system_used'] = system_used |
| 60 | + system_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_SYSTEM].allocated |
| 61 | + usage_info['system_unused'] = system_allocated - system_used |
| 62 | + left -= system_allocated |
| 63 | + |
| 64 | + usage_info['parity'] = usage.parity |
| 65 | + left -= usage.parity |
| 66 | + usage_info['non_alloc_reclaimable'] = usage.unallocatable_reclaimable |
| 67 | + left -= usage.unallocatable_reclaimable |
| 68 | + usage_info['non_alloc'] = usage.unallocatable_hard |
| 69 | + usage_info['unallocated'] = max(left - usage.unallocatable_hard, 0) |
| 70 | + usage_info['total'] = usage.total |
| 71 | + |
| 72 | + return usage_info |
24 | 73 |
|
25 | 74 |
|
26 | 75 | def munin_config(fs): |
@@ -48,6 +97,14 @@ def munin_config(fs): |
48 | 97 | print("metadata_unused.draw STACK") |
49 | 98 | print("metadata_unused.info Unused Metadata") |
50 | 99 | print("metadata_unused.colour 0000CC") |
| 100 | + |
| 101 | + usage_info = calculate_munin_values(fs) |
| 102 | + #Assuming metadata is allocated by 256MB chunks |
| 103 | + available_unallocated_for_metadata = floor(usage_info['unallocated'] / (2**28)) * (2**28) |
| 104 | + metadata_warning = int((usage_info['metadata_allocated'] * 0.15) - available_unallocated_for_metadata) |
| 105 | + metadata_critical = int((usage_info['metadata_allocated'] * 0.10) - available_unallocated_for_metadata) |
| 106 | + print("metadata_unused.warning {}:".format(metadata_warning)) |
| 107 | + print("metadata_unused.critical {}:".format(metadata_critical)) |
51 | 108 | else: |
52 | 109 | print("data_metadata_used.label Used Data+Metadata") |
53 | 110 | print("data_metadata_used.draw AREA") |
@@ -94,46 +151,28 @@ def munin_config(fs): |
94 | 151 | def munin_values(fs): |
95 | 152 | print("multigraph btrfs_usage_{0}".format(str(fs.fsid).replace('-', '_'))) |
96 | 153 |
|
97 | | - # Get detailed usage statistics. |
98 | | - usage = fs.usage() |
99 | | - |
100 | | - # Whatever happens, we should not stack the graph above this. IOW, the |
101 | | - # unallocated bytes we end up with is just whatever is left over after |
102 | | - # doing all other things. |
103 | | - left = usage.total |
| 154 | + usage_info = calculate_munin_values(fs) |
104 | 155 |
|
105 | 156 | if not fs.mixed_groups(): |
106 | | - data_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_DATA].used |
107 | | - data_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_DATA].allocated |
108 | | - metadata_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_METADATA].used |
109 | | - metadata_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_METADATA].allocated |
110 | | - print("data_used.value {}".format(data_used)) |
111 | | - print("data_unused.value {}".format(data_allocated - data_used)) |
112 | | - print("metadata_used.value {}".format(metadata_used)) |
113 | | - print("metadata_unused.value {}".format(metadata_allocated - metadata_used)) |
114 | | - left = left - data_allocated - metadata_allocated |
| 157 | + template = ( |
| 158 | + "data_used.value {data_used}\n" |
| 159 | + "data_unused.value {data_unused}\n" |
| 160 | + "metadata_used.value {metadata_used}\n" |
| 161 | + "metadata_unused.value {metadata_unused}\n") |
115 | 162 | else: |
116 | | - mixed_type = btrfs.BLOCK_GROUP_DATA | btrfs.BLOCK_GROUP_METADATA |
117 | | - used = usage.block_group_type_usage[mixed_type].used |
118 | | - allocated = usage.block_group_type_usage[mixed_type].allocated |
119 | | - print("data_metadata_used.value {}".format(used)) |
120 | | - print("data_metadata_unused.value {}".format(allocated - used)) |
121 | | - left -= allocated |
122 | | - system_used = usage.block_group_type_usage[btrfs.BLOCK_GROUP_SYSTEM].used |
123 | | - system_allocated = usage.block_group_type_usage[btrfs.BLOCK_GROUP_SYSTEM].allocated |
124 | | - print("system_used.value {}".format(system_used)) |
125 | | - print("system_unused.value {}".format(system_allocated - system_used)) |
126 | | - left -= system_allocated |
127 | | - |
128 | | - print("parity.value {}".format(usage.parity)) |
129 | | - left -= usage.parity |
130 | | - print("non_alloc_reclaimable.value {}".format(usage.unallocatable_reclaimable)) |
131 | | - left -= usage.unallocatable_reclaimable |
132 | | - print("non_alloc.value {}".format(usage.unallocatable_hard)) |
133 | | - left = max(left - usage.unallocatable_hard, 0) |
134 | | - print("unallocated.value {}".format(left)) |
135 | | - print("total.value {}".format(usage.total)) |
136 | | - print("") |
| 163 | + template = ( |
| 164 | + "data_metadata_used.value {data_metadata_used}\n" |
| 165 | + "data_metadata_unused.value {data_metadata_unused}\n") |
| 166 | + |
| 167 | + template += ( |
| 168 | + "system_used.value {system_used}\n" |
| 169 | + "system_unused.value {system_unused}\n" |
| 170 | + "parity.value {parity}\n" |
| 171 | + "non_alloc_reclaimable.value {non_alloc_reclaimable}\n" |
| 172 | + "non_alloc.value {non_alloc}\n" |
| 173 | + "unallocated.value {unallocated}\n" |
| 174 | + "total.value {total}\n") |
| 175 | + print(template.format(**usage_info)) |
137 | 176 |
|
138 | 177 |
|
139 | 178 | def filter_env_mounts(mounts): |
|
0 commit comments