はじめに
ラズパイにサーバ監視ツールnetdataを導入し、
状況に応じて警告アラームをSlackで受け取ろうとしたがエラーでアラームが飛んでこなかったのを直した記事(メモ)です。
ただし、とりあえず動くように修正しただけなのでベストな改善方法ではない可能性が高いです。(多分違います)
エラー内容
alarm-notify.sh: ERROR: failed to send slack notification for: raspberrypi test.chart.test_alarm is WARNING to 'sysadmin', with HTTP error code 404.
こんな感じでエラーが…
404のエラーコードが出ているということは「Not Found」
何かリクエストの指定方法が違うのかな?
原因
下記コードはalarm-notify.shの1218行目からの抜粋です。
# slack sender
send_slack() {
    local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
    [ "${SEND_SLACK}" != "YES" ] && return 1
    case "${status}" in
        WARNING)  color="warning" ;;
        CRITICAL) color="danger" ;;
        CLEAR)    color="good" ;;
        *)        color="#777777" ;;
    esac
    for channel in ${channels}
    do
        payload="$(cat <<EOF
        {
            "channel": "#${channel}",
            "username": "netdata on ${host}",
            "icon_url": "${images_base_url}/images/seo-performance-128.png",
            "text": "${host} ${status_message}, \`${chart}\` (_${family}_), *${alarm}*",
            "attachments": [
                {
                    "fallback": "${alarm} - ${chart} (${family}) - ${info}",
                    "color": "${color}",
                    "title": "${alarm}",
                    "title_link": "${goto_url}",
                    "text": "${info}",
                    "fields": [
                        {
                            "title": "${chart}",
                            "short": true
                        },
                        {
                            "title": "${family}",
                            "short": true
                        }
                    ],
                    "thumb_url": "${image}",
                    "footer": "by <${goto_url}|${this_host}>",
                    "ts": ${when}
                }
            ]
        }
EOF
        )"
        httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}")
        if [ "${httpcode}" = "200" ]
        then
            info "sent slack notification for: ${host} ${chart}.${name} is ${status} to '${channel}'"
            sent=$((sent + 1))
        else
            error "failed to send slack notification for: ${host} ${chart}.${name} is ${status} to '${channel}', with HTTP error code ${httpcode}."
        fi
    done
    [ ${sent} -gt 0 ] && return 0
    return 1
}
この中にある…
payload="$(cat <<EOF
        {
            "channel": "#${channel}",
            "username": "netdata on ${host}",
            "icon_url": "${images_base_url}/images/seo-performance-128.png",
            "text": "${host} ${status_message}, \`${chart}\` (_${family}_), *${alarm}*",
            "attachments": [
                {
                    "fallback": "${alarm} - ${chart} (${family}) - ${info}",
                    "color": "${color}",
                    "title": "${alarm}",
                    "title_link": "${goto_url}",
                    "text": "${info}",
                    "fields": [
                        {
                            "title": "${chart}",
                            "short": true
                        },
                        {
                            "title": "${family}",
                            "short": true
                        }
                    ],
                    "thumb_url": "${image}",
                    "footer": "by <${goto_url}|${this_host}>",
                    "ts": ${when}
                }
            ]
        }
EOF
ここ
そして、EOF内にSlackのchannelを指定しているところがありますが
"channel": "#${channel}",
ここで${channel}がコメントになっており中身が入っていません。
つまり、ここでチャンネルが正常に指定されておらずNot Foundのエラーが出ていました。
解決策
下記に示すとおり、slack_sender()において、
コメントを外す + channelの項を消しました。
# slack sender
send_slack() {
    local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
    [ "${SEND_SLACK}" != "YES" ] && return 1
    case "${status}" in
        WARNING)  color="warning" ;;
        CRITICAL) color="danger" ;;
        CLEAR)    color="good" ;;
        *)        color="#777777" ;;
    esac
    for channel in ${channels}
    do
        payload="$(cat <<EOF
        {
            "username": "netdata on ${host}",
            "icon_url": "${images_base_url}/images/seo-performance-128.png",
            "text": "${host} ${status_message}, \`${chart}\` (_${family}_), *${alarm}*",
            "attachments": [
                {
                    "fallback": "${alarm} - ${chart} (${family}) - ${info}",
                    "color": "${color}",
                    "title": "${alarm}",
                    "title_link": "${goto_url}",
                    "text": "${info}",
                    "fields": [
                        {
                            "title": "${chart}",
                            "short": true
                        },
                        {
                            "title": "${family}",
                            "short": true
                        }
                    ],
                    "thumb_url": "${image}",
                    "footer": "by <${goto_url}|${this_host}>",
                    "ts": ${when}
                }
            ]
        }
EOF
        )"
        httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}")
        if [ "${httpcode}" = "200" ]
        then
            info "sent slack notification for: ${host} ${chart}.${name} is ${status} to '${channel}'"
            sent=$((sent + 1))
        else
            error "failed to send slack notification for: ${host} ${chart}.${name} is ${status} to '${channel}', with HTTP error code ${httpcode}."
        fi
    done
    [ ${sent} -gt 0 ] && return 0
    return 1
}
修正を加えたら、
$ ./alarm-notify.sh test
でテスト用のアラームを飛ばせるので、
これで確認します。
すると
根本的な原因究明は行えていませんが…
(Slack側のAPIの仕様が変わったのでしょうか)

