bmc-snmp-proxy 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #!/bin/sh
  2. #############################################################################
  3. #
  4. # bmc-snmp-proxy: Set SNMP proxy to BMC (Baseboard Management Controller)
  5. #
  6. # version: 0.62
  7. #
  8. # Authors: Charles Rose <charles_rose@dell.com>
  9. # Jordan Hargrave <jordan_hargrave@dell.com>
  10. #
  11. # Description: Script to set snmp proxy to the BMC for certain OID
  12. # See here for details:
  13. # https://fedoraproject.org/wiki/Features/AgentFreeManagement
  14. #
  15. # Assumptions: This script will work only when /etc/snmp/ is writable.
  16. #
  17. #############################################################################
  18. # GLOBALS
  19. #############################################################################
  20. SYSCONF_DIR="/etc/sysconfig"
  21. CONFIG="${SYSCONF_DIR}/bmc-snmp-proxy"
  22. SNMPD_BMC_CONF_DIR="/etc/snmp/bmc"
  23. SNMPD_BMC_CONF="${SNMPD_BMC_CONF_DIR}/snmpd.local.conf"
  24. TRAPD_BMC_CONF="${SNMPD_BMC_CONF_DIR}/snmptrapd.local.conf"
  25. TRAPD_CONF="/etc/snmp/snmptrapd.conf"
  26. LOCKFILE="/var/lock/subsys/bmc-snmp-proxy"
  27. BMC_INFO="/var/run/bmc-info"
  28. IPMITOOL=`which ipmitool`
  29. #Default config
  30. BMC_COMMUNITY="public"
  31. BMC_OID=".1.3.6.1.4.1.674.10892.2" # Dell iDRAC
  32. TRAP_FORWARD="no"
  33. RELOAD_SERVICES="yes"
  34. #############################################################################
  35. #TODO: Use inotify and daemonize when $BMC_INFO changes
  36. # source config
  37. [ -r ${CONFIG} ] && . ${CONFIG}
  38. . gettext.sh
  39. SCRIPT_NAME=$(basename $0)
  40. RETVAL=0
  41. # Check if bmc-info created by exchange-bmc-os-info
  42. bmc_info_exists()
  43. {
  44. if [ -r "${BMC_INFO}" ]; then
  45. . ${BMC_INFO}
  46. else
  47. RETVAL=2
  48. fi
  49. return $RETVAL
  50. }
  51. check_snmp()
  52. {
  53. if [ ! -d /etc/snmp ] || [ ! -x /usr/sbin/snmpd ]; then
  54. RETVAL=12
  55. fi
  56. return $RETVAL
  57. }
  58. #############################################################################
  59. # configure SNMP proxy
  60. #############################################################################
  61. write_snmp_conf()
  62. {
  63. # SNMPv3 security: bmcview, bmc_ctx, bmc_sec, bmc_grp, bmc_cmty
  64. printf "###############################################\n"
  65. printf "# Automatically created by %s #\n" "${SCRIPT_NAME}"
  66. printf "###############################################\n"
  67. printf "#view bmcview included %s 80\n" "${BMC_OID}"
  68. printf "#com2sec -Cn bmc_ctx bmc_sec default bmc_cmty\n"
  69. printf "#group bmc_grp v1 bmc_sec\n"
  70. printf "#access bmc_grp bmc_ctx any noauth exact bmcview none none\n"
  71. printf "#proxy -Cn bmc_ctx -v 1 %s\n" "${PROXY_TOKEN}"
  72. printf "proxy -v 1 %s\n" "${PROXY_TOKEN}"
  73. printf "###############################################\n"
  74. }
  75. valid_ip()
  76. {
  77. #Thanks to mkyong.com
  78. octet="([01]?[[:digit:]][[:digit:]]?|2[0-4][[:digit:]]|25[0-5])"
  79. printf -- "%s" "${1}"| grep -Eq \
  80. "^${octet}\\.${octet}\\.${octet}\\.${octet}$"
  81. return $?
  82. }
  83. check_vars()
  84. {
  85. [ -z ${BMC_COMMUNITY} ] && BMC_COMMUNITY="public"
  86. [ -z ${BMC_OID} ] && return 1
  87. if [ -n "${BMC_IPv4}" ] && valid_ip ${BMC_IPv4}; then
  88. return 0
  89. else
  90. return 1
  91. fi
  92. }
  93. set_snmp_proxy()
  94. {
  95. if check_vars; then
  96. PROXY_TOKEN="-c ${BMC_COMMUNITY} ${BMC_IPv4} ${BMC_OID}"
  97. if [ -d ${SNMPD_BMC_CONF_DIR} ]; then
  98. write_snmp_conf > ${SNMPD_BMC_CONF} || RETVAL=4
  99. fi
  100. else
  101. RETVAL=3
  102. fi
  103. }
  104. set_snmpd_conf_path()
  105. {
  106. if [ ! -d ${SNMPD_BMC_CONF_DIR} ]; then
  107. mkdir ${SNMPD_BMC_CONF_DIR} || RETVAL=7
  108. fi
  109. # We need SNMPCONFPATH set for both snmpd and snmptrapd
  110. for sysconf in ${SYSCONF_DIR}/snmp*d;
  111. do
  112. if ! grep -q "^SNMPCONFPATH.*${SNMPD_BMC_CONF_DIR}" \
  113. "${sysconf}" > /dev/null 2>&1; then
  114. printf "SNMPCONFPATH=/etc/snmp:%s\n" \
  115. "${SNMPD_BMC_CONF_DIR}" >> ${sysconf} || \
  116. RETVAL=7
  117. fi
  118. done
  119. return $RETVAL
  120. }
  121. disable_snmp_proxy()
  122. {
  123. if [ -f ${SNMPD_BMC_CONF} ]; then
  124. rm -f ${SNMPD_BMC_CONF} || RETVAL=5
  125. fi
  126. }
  127. #############################################################################
  128. # Trap Forwarding
  129. #############################################################################
  130. pick_alert_dest()
  131. {
  132. test_ip="$1"
  133. # We have 4 IPv4 and 4 IPv6 alert dest. We will set IPv4 for now.
  134. for ALERT_DEST in `seq 1 4`
  135. do
  136. temp_ip=$(${IPMITOOL} lan alert print ${CHANNEL} ${ALERT_DEST}\
  137. 2>/dev/null| sed -n "s#^Alert IP Address.*: ##p")
  138. [ "${temp_ip}" = "${test_ip}" ] && return 0
  139. done
  140. return 1
  141. }
  142. set_alert_dest_ip()
  143. {
  144. ${IPMITOOL} lan alert set ${CHANNEL} ${ALERT_DEST} ipaddr ${1} \
  145. retry 4 type pet >/dev/null 2>&1 || RETVAL=8
  146. }
  147. config_bmc_alert_dest()
  148. {
  149. # call with enable|disable
  150. # Pick the first active LAN channel
  151. for CHANNEL in `seq 1 14`
  152. do
  153. [ $(${IPMITOOL} -I open channel info ${CHANNEL} 2>/dev/null \
  154. | grep -q "802\.3") ] || break
  155. done
  156. # If TRAPD_IP is already set as an alert dest,
  157. if pick_alert_dest "${TRAPD_IP}"; then
  158. # disable: reset it if we are called with disable
  159. [ "${1}" = "disable" ] && \
  160. set_alert_dest_ip "0.0.0.0"
  161. # else, find the next free alert dest,
  162. elif pick_alert_dest "0.0.0.0"; then
  163. [ "${1}" = "disable" ] && \
  164. return $RETVAL
  165. # set: the TRAPD_IP
  166. set_alert_dest_ip "${TRAPD_IP}"
  167. else
  168. # No free alert destinations
  169. RETVAL=9
  170. fi
  171. return $RETVAL
  172. }
  173. set_ipmi_pef()
  174. {
  175. # Needs ipmitool-1.8.13 + patches
  176. ${IPMITOOL} pef policy set ${ALERT_DEST} "${1}" >/dev/null 2>&1 || \
  177. RETVAL=10
  178. }
  179. get_host_ip()
  180. {
  181. # Get host's IP that the BMC can reach. This is at best a hack.
  182. IFACE=$(/usr/sbin/ip -o -f inet address |awk '!/: lo/ {print $2}')
  183. for dev in ${IFACE}
  184. do
  185. temp_ping=$(ping -c 1 -I ${dev} ${BMC_IPv4})
  186. [ $? -ne 0 ] && continue
  187. printf -- "%s" "$temp_ping"| awk 'NR==1{print $5}' && break
  188. done
  189. }
  190. config_bmc_alert()
  191. {
  192. # Do two things
  193. # Set/Reset TRAP IP in BMC
  194. # Enable/Disable PEF alerting in BMC for TRAP
  195. # Get Host's IP that the BMC can send traps to
  196. TRAPD_IP=$(get_host_ip)
  197. # Set Host's IP as the alert destination in the BMC
  198. valid_ip ${TRAPD_IP} && config_bmc_alert_dest "${ACTION}"
  199. # Enable/Disable alerting on the LAN channel
  200. [ $RETVAL -eq 0 ] && set_ipmi_pef "${ACTION}"
  201. return $RETVAL
  202. }
  203. write_trapd_conf()
  204. {
  205. printf "###############################################\n"
  206. printf "# Automatically created by %s #\n" "${SCRIPT_NAME}"
  207. printf "forward default %s\n" "${FORWARD_HOST}"
  208. printf "###############################################\n"
  209. }
  210. config_trapd()
  211. {
  212. # Proceed only if snmptrapd is available on the system
  213. if [ -f ${TRAPD_CONF} ]; then
  214. write_trapd_conf > ${TRAPD_BMC_CONF} || RETVAL=11
  215. else
  216. RETVAL=11
  217. fi
  218. }
  219. trap_sink_exists()
  220. {
  221. # TODO: We only set the first match. We should be able to set
  222. # multiple
  223. FORWARD_HOST=$(awk '/^trap.*sink/{print $2}; /^informsink/{print $2}' \
  224. /etc/snmp/snmpd*conf | head -1)
  225. if [ -z "${FORWARD_HOST}" ]; then
  226. # there is no trapsink setup.
  227. return 1
  228. else
  229. return 0
  230. fi
  231. }
  232. # Forward SNMP traps from the BMC to trapsink.
  233. trap_forward()
  234. {
  235. NO_TRAP=0
  236. ACTION=${1} # enable or disable
  237. if [ "${ACTION}" = "enable" ]; then
  238. # Get trapd config,
  239. if trap_sink_exists; then
  240. config_bmc_alert && config_trapd
  241. else
  242. # exit silently if there is no sink
  243. NO_TRAP=1
  244. fi
  245. else
  246. if [ -f ${TRAPD_BMC_CONF} ]; then
  247. rm -f ${TRAPD_BMC_CONF} >/dev/null 2>&1
  248. config_bmc_alert
  249. else
  250. NO_TRAP=1
  251. fi
  252. fi
  253. }
  254. #############################################################################
  255. service_reload()
  256. {
  257. #TODO: do this in systemd
  258. if [ ${RETVAL} -eq 0 ] && [ "${RELOAD_SERVICES}" = "yes" ]; then
  259. service $1 reload
  260. [ $? -ne 0 ] && RETVAL=6
  261. fi
  262. }
  263. #############################################################################
  264. start()
  265. {
  266. if bmc_info_exists && check_snmp; then
  267. touch ${LOCKFILE}
  268. set_snmpd_conf_path && set_snmp_proxy
  269. [ $RETVAL -eq 0 ] && service_reload snmpd
  270. if [ "${TRAP_FORWARD}" = "yes" ]; then
  271. trap_forward "enable"
  272. [ $RETVAL -eq 0 ] && [ $NO_TRAP -eq 0 ] && \
  273. service_reload snmptrapd
  274. fi
  275. fi
  276. }
  277. #############################################################################
  278. stop()
  279. {
  280. [ ! -f ${LOCKFILE} ] && return
  281. if bmc_info_exists && check_snmp; then
  282. disable_snmp_proxy
  283. [ $RETVAL -eq 0 ] && service_reload snmpd
  284. if [ "${TRAP_FORWARD}" = "yes" ]; then
  285. trap_forward "disable"
  286. [ $RETVAL -eq 0 ] && [ $NO_TRAP -eq 0 ] && \
  287. service_reload snmptrapd
  288. fi
  289. rm -f ${LOCKFILE}
  290. fi
  291. }
  292. #############################################################################
  293. status()
  294. {
  295. eval_gettext "${SCRIPT_NAME}: snmp proxy to BMC is "
  296. # Checking for lockfile is better.
  297. #if grep -q "^proxy" "${SNMPD_BMC_CONF}" > /dev/null 2>&1 ; then
  298. if [ -f ${LOCKFILE} ]; then
  299. eval_gettext "set"
  300. else
  301. eval_gettext "not set"
  302. fi
  303. echo
  304. RETVAL=0
  305. }
  306. #############################################################################
  307. usage()
  308. {
  309. eval_gettext "Usage: $0 {start|stop|status}"; echo 1>&2
  310. RETVAL=1
  311. }
  312. #############################################################################
  313. # MAIN
  314. #############################################################################
  315. case "$1" in
  316. start) start ;;
  317. stop) stop ;;
  318. status) status ;;
  319. *) usage ;;
  320. esac
  321. case "$RETVAL" in
  322. 0|1) ;;
  323. 2) eval_gettext "${SCRIPT_NAME}: failed to read ${BMC_INFO} " 1>&2 ;;
  324. 3) eval_gettext "${SCRIPT_NAME}: failed to get proxy config." 1>&2 ;;
  325. 4) eval_gettext "${SCRIPT_NAME}: failed to set ${SNMPD_BMC_CONF}." 1>&2 ;;
  326. 5) eval_gettext "${SCRIPT_NAME}: failed to disable snmp proxy." 1>&2 ;;
  327. 6) eval_gettext "${SCRIPT_NAME}: failed to reload snmpd." 1>&2 ;;
  328. 7) eval_gettext "${SCRIPT_NAME}: failed to set snmpd config." 1>&2 ;;
  329. 8) eval_gettext "${SCRIPT_NAME}: failed to set IPMI alert dest." 1>&2 ;;
  330. 9) eval_gettext "${SCRIPT_NAME}: no free IPMI alert dest." 1>&2 ;;
  331. 10) eval_gettext "${SCRIPT_NAME}: failed to set IPMI PEF." 1>&2 ;;
  332. 11) eval_gettext "${SCRIPT_NAME}: failed to write snmptrapd.conf." 1>&2 ;;
  333. 12) eval_gettext "${SCRIPT_NAME}: snmpd not found." 1>&2 ;;
  334. *) eval_gettext "${SCRIPT_NAME}: unknown error." 1>&2 ;;
  335. esac
  336. if [ ${RETVAL} -gt 1 ]; then
  337. eval_gettext " Return code: ${RETVAL}"; echo
  338. fi
  339. exit ${RETVAL}
  340. #############################################################################
  341. # end of file
  342. #############################################################################