Project

General

Profile

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"