username: test | username: test | ||||
password: test | password: test | ||||
Netconsole Remote Kernel Logging | |||||
-------------------------------- | |||||
Netconsole logger could be configured for configfs-enabled kernels | |||||
(`CONFIG_NETCONSOLE_DYNAMIC` should be enabled). Configuration applies both in | |||||
runtime (if network is already configured), and on-boot after interface | |||||
initialization. Notes: | |||||
* receiver could be located only in same L3 domain | |||||
(or you need to configure gateway MAC manually) | |||||
* receiver's MAC is detected only on configuration time | |||||
* using broadcast MAC is not recommended | |||||
.. code-block:: yaml | |||||
parameters: | |||||
linux: | |||||
system: | |||||
netconsole: | |||||
enabled: true | |||||
port: 514 (optional) | |||||
loglevel: debug (optional) | |||||
target: | |||||
192.168.0.1: | |||||
interface: bond0 | |||||
mac: "ff:ff:ff:ff:ff:ff" (optional) | |||||
Usage | Usage | ||||
===== | ===== |
#!/bin/sh | |||||
SYSFS_NETCONSOLE="/sys/kernel/config/netconsole" | |||||
NETCONSOLE_CONF="/etc/default/netconsole.conf" | |||||
NETCONSOLE_PORT="514" | |||||
netconsole_remove() { | |||||
for sysfsnc in "${SYSFS_NETCONSOLE}/${interface:-}-"* | |||||
do | |||||
if [ -e "${sysfsnc}" ] | |||||
then | |||||
logger -t netconsole "remove ${sysfsnc}" | |||||
rmdir "${sysfsnc}" | |||||
fi | |||||
done | |||||
} | |||||
netconsole_remote_mac() | |||||
{ | |||||
neigh() | |||||
{ | |||||
ip -4 -o neigh show to "${remote_ip}" dev "${interface}" | cut -d\ -f3 | |||||
} | |||||
remote_mac="$(neigh)" | |||||
if [ -n "${remote_mac:-}" ] && [ "${remote_mac:-}" != "INCOMPLETE" ] | |||||
then | |||||
if [ "${remote_mac:-}" != "FAILED" ] | |||||
then | |||||
echo "${remote_mac:-}" | |||||
return 0 | |||||
fi | |||||
else | |||||
if ping -n -q -c 1 -w 1 -I "${interface}" "${remote_ip}" >/dev/null && remote_mac="$(neigh)" && [ -n "${remote_mac:-}" ] | |||||
then | |||||
echo "${remote_mac:-}" | |||||
return 0 | |||||
fi | |||||
fi | |||||
return 1 | |||||
} | |||||
netconsole_add() { | |||||
netconsole() { | |||||
iface="${1:-}" | |||||
remote_ip="${2:-}" | |||||
remote_mac="${3:-}" | |||||
if [ "${iface:-}" = "${interface:-}" ] && [ -n "${remote_ip:-}" ] | |||||
then | |||||
logger -t netconsole "from ${new_ip_address:-}@${interface:-}" | |||||
else | |||||
return 1 | |||||
fi | |||||
if [ -n "${remote_mac}" ] || remote_mac="$(netconsole_remote_mac)" | |||||
then | |||||
logger -t netconsole "to ${remote_ip} ${remote_mac}" | |||||
else | |||||
return 1 | |||||
fi | |||||
sysfsnc="${SYSFS_NETCONSOLE}/${interface}-${remote_ip}" | |||||
if [ -e "${sysfsnc}" ] && [ -z "${old_ip_address:-}" ] | |||||
then | |||||
old_ip_address="$(cat "${sysfsnc}/local_ip")" | |||||
fi | |||||
if [ "${old_ip_address:-}" != "${new_ip_address:-}" ] || ! [ -e "${sysfsnc}" ] | |||||
then | |||||
logger -t netconsole "setup netconsole" | |||||
else | |||||
return 1 | |||||
fi | |||||
mkdir -p "${sysfsnc}" | |||||
if [ "$(cat "${sysfsnc}/enabled")" != "0" ] | |||||
then | |||||
echo "0" > "${sysfsnc}/enabled" | |||||
fi | |||||
if [ -n "${new_ip_address:-}" ] | |||||
then | |||||
echo "${new_ip_address}" > "${sysfsnc}/local_ip" | |||||
fi | |||||
echo "${interface}" > "${sysfsnc}/dev_name" | |||||
echo "${remote_mac}" > "${sysfsnc}/remote_mac" | |||||
echo "${remote_ip}" > "${sysfsnc}/remote_ip" | |||||
echo "${PORT:-${NETCONSOLE_PORT}}" > "${sysfsnc}/remote_port" | |||||
echo "1" > "${sysfsnc}/enabled" | |||||
return 0 | |||||
} | |||||
if [ -f "${NETCONSOLE_CONF}" ] | |||||
then | |||||
modprobe netconsole | |||||
mountpoint -q /sys/kernel/config || mount none -t configfs /sys/kernel/config | |||||
if [ -e "${SYSFS_NETCONSOLE}" ] | |||||
then | |||||
( | |||||
set -x | |||||
set +e | |||||
. "${NETCONSOLE_CONF}" | |||||
) ||: | |||||
fi | |||||
fi | |||||
} | |||||
netconsole_setup() { | |||||
case ${reason:-} in | |||||
BOUND|RENEW|REBIND|REBOOT) | |||||
netconsole_add | |||||
;; | |||||
EXPIRE|FAIL|RELEASE|STOP) | |||||
netconsole_remove | |||||
;; | |||||
PREINIT) : ;; | |||||
*) | |||||
if [ "${ADDRFAM:-}" = "inet" ] && [ "${METHOD:-}" = "static" ] | |||||
then | |||||
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin | |||||
interface="${IFACE:-}" | |||||
new_ip_address="${IF_ADDRESS:-}" | |||||
case ${MODE:-} in | |||||
start) | |||||
netconsole_add | |||||
;; | |||||
stop) | |||||
netconsole_remove | |||||
;; | |||||
*) : ;; | |||||
esac | |||||
fi | |||||
esac | |||||
} | |||||
netconsole_setup |
{%- from "linux/map.jinja" import system with context %} | |||||
# default port is 514 | |||||
#PORT=6666 | |||||
{%- if system.netconsole is mapping and system.netconsole.port is defined %} | |||||
PORT="{{ system.netconsole.port }}" | |||||
{%- endif %} | |||||
# unicast, could be multiline | |||||
#netconsole ens3 192.168.1.32 fa:16:3e:8d:f6:d0 | |||||
{%- if system.netconsole is mapping and system.netconsole.target is mapping %} | |||||
{%- for target, data in system.netconsole.target.iteritems() %} | |||||
{%- if data is mapping %} | |||||
netconsole "{{ data.get('interface', '${interface}') }}" "{{ target }}" "{{ data.get('mac', '') }}" | |||||
{%- endif %} | |||||
{%- endfor %} | |||||
{%- endif %} | |||||
# set up dmesg log level | |||||
# dmesg -n info | |||||
{%- if system.netconsole is mapping and system.netconsole.loglevel is defined %} | |||||
dmesg -n "{{ system.netconsole.loglevel }}" | |||||
{%- endif %} |
{%- if system.sudo is defined %} | {%- if system.sudo is defined %} | ||||
- linux.system.sudo | - linux.system.sudo | ||||
{%- endif %} | {%- endif %} | ||||
{%- if system.netconsole is defined %} | |||||
- linux.system.netconsole | |||||
{%- endif %} |
{% from "linux/map.jinja" import system with context %} | |||||
{% if system.enabled and system.netconsole is mapping and system.netconsole.enabled %} | |||||
/etc/dhcp/dhclient-exit-hooks.d/netconsole: | |||||
file.managed: | |||||
- source: salt://linux/files/netconsole | |||||
- makedirs: True | |||||
/etc/network/if-up.d/netconsole: | |||||
file.managed: | |||||
- source: salt://linux/files/netconsole | |||||
- mode: 755 | |||||
/etc/network/if-down.d/netconsole: | |||||
file.managed: | |||||
- source: salt://linux/files/netconsole | |||||
- mode: 755 | |||||
/etc/default/netconsole.conf: | |||||
file.managed: | |||||
- source: salt://linux/files/netconsole.conf | |||||
- template: jinja | |||||
{% if system.netconsole is mapping and system.netconsole.target is mapping %} | |||||
{% for target, data in system.netconsole.target.iteritems() %} | |||||
{% if data is mapping and data.interface is defined %} | |||||
/etc/network/if-up.d/netconsole {{ target }} {{ data.interface }}: | |||||
cmd.run: | |||||
- name: /etc/network/if-up.d/netconsole | |||||
- env: | |||||
- IFACE: {{ data.interface }} | |||||
- METHOD: static | |||||
- ADDRFAM: inet | |||||
- MODE: start | |||||
- onchanges: | |||||
- file: /etc/default/netconsole.conf | |||||
- require: | |||||
- file: /etc/network/if-up.d/netconsole | |||||
{% endif %} | |||||
{% endfor %} | |||||
{% endif %} | |||||
{% endif %} |
## NETCONSOLE | |||||
# | |||||
describe file('/etc/default/netconsole.conf') do | |||||
it('should exist') | |||||
its('content') { should match /^PORT="514"/} | |||||
its('content') { should match /^netconsole "bond0" "192.168.0.1" "ff:ff:ff:ff:ff:ff"/} | |||||
its('content') { should match /^dmesg -n "debug"/} | |||||
end | |||||
describe file('/etc/dhcp/dhclient-exit-hooks.d/netconsole') do | |||||
it('should exist') | |||||
its('content') { should match /netconsole_setup/} | |||||
end |
- host1 | - host1 | ||||
- host2 | - host2 | ||||
- .local | - .local | ||||
# pillars for netconsole setup | |||||
netconsole: | |||||
enabled: true | |||||
port: 514 | |||||
loglevel: debug | |||||
target: | |||||
192.168.0.1: | |||||
mac: "ff:ff:ff:ff:ff:ff" | |||||
interface: bond0 |