Backblaze storage pods » History » Version 1
Charles Atkinson, 10/02/2022 11:32
Creation
1 | 1 | Charles Atkinson | h1. Backblaze storage pods |
---|---|---|---|
2 | 1 | Charles Atkinson | |
3 | 1 | Charles Atkinson | In case of storage pod hard disk problems it can be difficult to identify the disk from the error messages. Linux error messages identify disks by ATA number or by sdX such as sdc. For hardware maintenance, disks need to be identified by backplane number and slot. |
4 | 1 | Charles Atkinson | |
5 | 1 | Charles Atkinson | A report like this allows error messages to be translated to physical location: |
6 | 1 | Charles Atkinson | <pre> |
7 | 1 | Charles Atkinson | Backplane Socket sdx ata Serial |
8 | 1 | Charles Atkinson | 1 1 sdc ata7.00 Y6N1KE53FTMB |
9 | 1 | Charles Atkinson | 2 1 sdd ata8.00 WD-WMC1T1802712 |
10 | 1 | Charles Atkinson | 3 1 sde ata9.00 WD-WCC4ELZ72L40 |
11 | 1 | Charles Atkinson | 5 1 sdf ata11.00 Y6N1KE56FTMB |
12 | 1 | Charles Atkinson | 7 1 sdg ata13.00 VDGKJ03D |
13 | 1 | Charles Atkinson | 8 1 sdh ata14.00 WD-WX21D25R5PP4 |
14 | 1 | Charles Atkinson | 10 1 sdi ata16.00 19P1K5R6FTMB |
15 | 1 | Charles Atkinson | </pre>The report is generated by this bash function. msg is a messaging function which terminates the script when called with E for error |
16 | 1 | Charles Atkinson | <pre> |
17 | 1 | Charles Atkinson | #-------------------------- |
18 | 1 | Charles Atkinson | # Name: generate_report |
19 | 1 | Charles Atkinson | # Purpose: |
20 | 1 | Charles Atkinson | # * Generates SATA backplane usage report |
21 | 1 | Charles Atkinson | # Usage: generate_report |
22 | 1 | Charles Atkinson | # Global variable set: none |
23 | 1 | Charles Atkinson | # Outputs: writes dated report file; removes if same as last one |
24 | 1 | Charles Atkinson | # Returns: |
25 | 1 | Charles Atkinson | # 0 on success and warning. Does not return on error |
26 | 1 | Charles Atkinson | #-------------------------- |
27 | 1 | Charles Atkinson | function generate_report { |
28 | 1 | Charles Atkinson | local buf cmd last_out_fn oIFS out out_dir out_fn |
29 | 1 | Charles Atkinson | declare -A ata |
30 | 1 | Charles Atkinson | |
31 | 1 | Charles Atkinson | # Get the ATA number for each sdX |
32 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
33 | 1 | Charles Atkinson | # Based on syntaxerror's script in |
34 | 1 | Charles Atkinson | # https://serverfault.com/questions/244944/linux-ata-errors-translating-to-a-device-name |
35 | 1 | Charles Atkinson | oIFS=$IFS |
36 | 1 | Charles Atkinson | while IFS=' ' read Path HostFull sdx |
37 | 1 | Charles Atkinson | do |
38 | 1 | Charles Atkinson | IFS=: h=($HostFull) |
39 | 1 | Charles Atkinson | HostMain=${h[0]}; HostMid=${h[1]}; HostSub=${h[2]} |
40 | 1 | Charles Atkinson | if echo $Path | grep -q '/usb[0-9]*/'; then |
41 | 1 | Charles Atkinson | msg I "Device $sdx is not an ATA device, it is a USB device" |
42 | 1 | Charles Atkinson | else |
43 | 1 | Charles Atkinson | ata["$sdx"]=ata$(< "$Path/host$HostMain/scsi_host/host$HostMain/unique_id").$HostMid$HostSub |
44 | 1 | Charles Atkinson | fi |
45 | 1 | Charles Atkinson | done < <( |
46 | 1 | Charles Atkinson | for i in /sys/block/sd* |
47 | 1 | Charles Atkinson | do |
48 | 1 | Charles Atkinson | readlink $i \ |
49 | 1 | Charles Atkinson | | sed \ |
50 | 1 | Charles Atkinson | -e 's|\.\./devices|/sys/devices|' \ |
51 | 1 | Charles Atkinson | -e 's|/host[0-9]\{1,2\}/target| |' \ |
52 | 1 | Charles Atkinson | -e 's|/[0-9]\{1,2\}\(:[0-9]\)\{3\}/block/| |' |
53 | 1 | Charles Atkinson | done |
54 | 1 | Charles Atkinson | ) |
55 | 1 | Charles Atkinson | IFS=$oIFS |
56 | 1 | Charles Atkinson | |
57 | 1 | Charles Atkinson | # Generate report data |
58 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~ |
59 | 1 | Charles Atkinson | out=$'Backplane Socket sdx ata Serial\n' |
60 | 1 | Charles Atkinson | out+=$( |
61 | 1 | Charles Atkinson | while read backplane socket sdx serno |
62 | 1 | Charles Atkinson | do |
63 | 1 | Charles Atkinson | msg D "backplane: $backplane, socket: $socket, sdx: $sdx, serno: $serno" |
64 | 1 | Charles Atkinson | ((backplane=backplane-6+1)) |
65 | 1 | Charles Atkinson | ((socket++)) |
66 | 1 | Charles Atkinson | printf '%9s %6s %4s %8s %s\n' $backplane $socket $sdx ${ata[$sdx]} $serno |
67 | 1 | Charles Atkinson | done < <( |
68 | 1 | Charles Atkinson | lshw -class disk 2>&1 \ |
69 | 1 | Charles Atkinson | | grep -E '^ (bus info|logical name|serial)' \ |
70 | 1 | Charles Atkinson | | sed -e 's/^[[:space:]]*//' \ |
71 | 1 | Charles Atkinson | | xargs -L 3 \ |
72 | 1 | Charles Atkinson | | grep -Ev 'scsi@(0|1):0.0.0' \ |
73 | 1 | Charles Atkinson | | sed -e 's/bus info: scsi@//' -e 's|logical name: /dev/||' \ |
74 | 1 | Charles Atkinson | | sed -e 's/serial: //' -e 's/:/ /' -e 's/\.0\.0//' \ |
75 | 1 | Charles Atkinson | | sort -n |
76 | 1 | Charles Atkinson | ) |
77 | 1 | Charles Atkinson | ) |
78 | 1 | Charles Atkinson | |
79 | 1 | Charles Atkinson | # Check reports directory |
80 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~~~~ |
81 | 1 | Charles Atkinson | out_dir=/var/backup/sata_backplane_usage |
82 | 1 | Charles Atkinson | buf=$(ck_file "$out_dir" d:rwx 2>&1) |
83 | 1 | Charles Atkinson | [[ $buf != '' ]] && msg E "$buf" |
84 | 1 | Charles Atkinson | |
85 | 1 | Charles Atkinson | # Get name of most recent report |
86 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
87 | 1 | Charles Atkinson | last_out_fn=$(ls -1rt "$out_dir" | tail -1) |
88 | 1 | Charles Atkinson | [[ $last_out_fn != '' ]] && last_out_fn=$out_dir/$last_out_fn |
89 | 1 | Charles Atkinson | |
90 | 1 | Charles Atkinson | # Write report to file |
91 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~ |
92 | 1 | Charles Atkinson | out_fn=$out_dir/$(date +%Y-%m-%d@%H:%M:%S).report |
93 | 1 | Charles Atkinson | msg I "Writing report $out_fn" |
94 | 1 | Charles Atkinson | buf=$(echo "$out" > "$out_fn" 2>&1) |
95 | 1 | Charles Atkinson | [[ $buf != '' ]] && msg E "Writing report: $buf" |
96 | 1 | Charles Atkinson | |
97 | 1 | Charles Atkinson | # Remove report file if same as previous one |
98 | 1 | Charles Atkinson | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
99 | 1 | Charles Atkinson | if [[ $last_out_fn != '' ]]; then |
100 | 1 | Charles Atkinson | cmd=(diff --brief "$last_out_fn" "$out_fn") |
101 | 1 | Charles Atkinson | buf=$("${cmd[@]}" 2>&1) |
102 | 1 | Charles Atkinson | if (($?==0)); then |
103 | 1 | Charles Atkinson | msg I "Removing report $out_fn because identical to the last report" |
104 | 1 | Charles Atkinson | buf=$(rm "$out_fn" 2>&1) |
105 | 1 | Charles Atkinson | [[ $buf != '' ]] && msg E "Removing $out_fn: $buf" |
106 | 1 | Charles Atkinson | elif (($?==1)); then |
107 | 1 | Charles Atkinson | msg W "SATA backplane usage changed. Reports in $out_dir" |
108 | 1 | Charles Atkinson | elif (($?==2)); then |
109 | 1 | Charles Atkinson | msg E "${cmd[*]}: $buf" |
110 | 1 | Charles Atkinson | fi |
111 | 1 | Charles Atkinson | fi |
112 | 1 | Charles Atkinson | |
113 | 1 | Charles Atkinson | return 0 |
114 | 1 | Charles Atkinson | } # end of function generate_report |
115 | 1 | Charles Atkinson | </pre>The full script is available at document:"A Backblaze storage pod storage management utility for Linux" |