@@ -1186,6 +1186,32 @@ config files for external use, eg. docker, etc. | |||
username: 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 | |||
===== |
@@ -0,0 +1,136 @@ | |||
#!/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 |
@@ -0,0 +1,22 @@ | |||
{%- 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 %} |
@@ -80,3 +80,6 @@ include: | |||
{%- if system.sudo is defined %} | |||
- linux.system.sudo | |||
{%- endif %} | |||
{%- if system.netconsole is defined %} | |||
- linux.system.netconsole | |||
{%- endif %} |
@@ -0,0 +1,43 @@ | |||
{% 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 %} |
@@ -0,0 +1,14 @@ | |||
## 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 |
@@ -265,3 +265,13 @@ linux: | |||
- host1 | |||
- host2 | |||
- .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 |