From 721b98cf4ca59bedc8809648ee0c86ce50e8b4ed Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Sun, 2 Jul 2023 02:57:21 +0530 Subject: [PATCH 1/9] Packaging of NFS and CIFS diagnostic scripts. * Created Makefile to generate .deb and .rpm packages for these scripts. * Created single wrapper file to invoke both NFS and CIFS scripts. --- NfsDiagnostics/trace-nfsbpf | 2 +- SMBDiagnostics/trace-cifsbpf | 2 +- packaging/DEBIAN/control | 5 ++++ packaging/DEBIAN/postinst | 3 ++ packaging/DEBIAN/postrm | 1 + packaging/Makefile | 55 ++++++++++++++++++++++++++++++++++++ packaging/README.md | 4 +++ packaging/RPM/spec.spec | 35 +++++++++++++++++++++++ wrapper.sh | 19 +++++++++++++ 9 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 packaging/DEBIAN/control create mode 100755 packaging/DEBIAN/postinst create mode 100755 packaging/DEBIAN/postrm create mode 100644 packaging/Makefile create mode 100644 packaging/README.md create mode 100644 packaging/RPM/spec.spec create mode 100755 wrapper.sh diff --git a/NfsDiagnostics/trace-nfsbpf b/NfsDiagnostics/trace-nfsbpf index c50f6ce..25692cd 100755 --- a/NfsDiagnostics/trace-nfsbpf +++ b/NfsDiagnostics/trace-nfsbpf @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 from bcc import BPF from bcc.utils import printb from time import sleep diff --git a/SMBDiagnostics/trace-cifsbpf b/SMBDiagnostics/trace-cifsbpf index 29e9fd7..cd88ff2 100644 --- a/SMBDiagnostics/trace-cifsbpf +++ b/SMBDiagnostics/trace-cifsbpf @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 from bcc import BPF from bcc.utils import printb from time import sleep diff --git a/packaging/DEBIAN/control b/packaging/DEBIAN/control new file mode 100644 index 0000000..55490eb --- /dev/null +++ b/packaging/DEBIAN/control @@ -0,0 +1,5 @@ +Package: $PKG_NAME +Version: $VERSION +Maintainer: Microsoft +Architecture: all +Description: Diagnostics scripts for CIFS and NFS. diff --git a/packaging/DEBIAN/postinst b/packaging/DEBIAN/postinst new file mode 100755 index 0000000..f65ab53 --- /dev/null +++ b/packaging/DEBIAN/postinst @@ -0,0 +1,3 @@ + +chown root:root $SYS_DIR/bin/wrapper.sh +chmod 454 $SYS_DIR/bin/wrapper.sh diff --git a/packaging/DEBIAN/postrm b/packaging/DEBIAN/postrm new file mode 100755 index 0000000..5c8876e --- /dev/null +++ b/packaging/DEBIAN/postrm @@ -0,0 +1 @@ +rm -rf $SYS_DIR diff --git a/packaging/Makefile b/packaging/Makefile new file mode 100644 index 0000000..e1bcef5 --- /dev/null +++ b/packaging/Makefile @@ -0,0 +1,55 @@ +export sles= +export PKG_NAME=nfs-cifs-diag +export RELEASE=1 +export VERSION=1 +export SYS_DIR=/opt/xstore +export SRC_DIR=.. +# export PKG_BUILD=$(PKG_NAME)$(sles)-$(RELEASE)-1.x86_64 +# export PKG_DIR=BUILDROOT/$(PKG_BUILD) +export PKG_DIR=$(PKG_NAME) +export DEB_PKG_DIR=$(PKG_DIR)/DEBIAN +export OPT_DIR=$(PKG_DIR)$(SYS_DIR) + +build: init + echo $(SRC_DIR) + echo hello + +init: + mkdir -p $(OPT_DIR)/bin + mkdir -p $(OPT_DIR)/lib + cp -r ../NfsDiagnostics $(OPT_DIR)/lib + cp -r ../SMBDiagnostics $(OPT_DIR)/lib + cp -r ../wrapper.sh $(OPT_DIR)/bin + +debian: init + cp -r ./DEBIAN ./$(PKG_DIR) + # sed -i "s/\$$PKG_NAME/${PKG_NAME}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst + # sed -i "s/\$$SYS_DIR/${SYS_DIR}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst + # sed -i "s/\$$VERSION/${VERSION}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst + for file in ./$(PKG_DIR)/DEBIAN/*; do \ + sed -i "s/\$$PKG_NAME/${PKG_NAME}/g" $$file; \ + sed -i "s:\$$SYS_DIR:${SYS_DIR}:g" $$file; \ + sed -i "s/\$$VERSION/${VERSION}/g" $$file; \ + done + dpkg-deb --build ./$(PKG_DIR) + +rpm: init + mkdir -p ~/rpmbuild/SOURCES + cp -r $(PKG_DIR)/opt ~/rpmbuild/SOURCES + cp ./RPM/spec.spec . + sed -i "s:\$$SYS_DIR:${SYS_DIR}:g" spec.spec + sed -i "s:\$$PKG_NAME:${PKG_NAME}:g" spec.spec + sed -i "s:\$$VERSION:${VERSION}:g" spec.spec + sed -i "s:\$$RELEASE:${RELEASE}:g" spec.spec + rpmbuild -bb spec.spec + mv ~/rpmbuild/RPMS/x86_64/*.rpm . + rm -r ~/rpmbuild + + + +suse: + echo suse + + +clean: + rm -rf ./$(PKG_DIR) spec.spec diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..216e457 --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,4 @@ + +1. Run `make debian` to generate .deb package +2. Run `make rpm` to generate .rpm package +3. Run `make clean` once the packages are created. diff --git a/packaging/RPM/spec.spec b/packaging/RPM/spec.spec new file mode 100644 index 0000000..fef41b1 --- /dev/null +++ b/packaging/RPM/spec.spec @@ -0,0 +1,35 @@ +Name: $PKG_NAME +Version: $VERSION +Release: $RELEASE +Summary: Diagnostics scripts for NFS and CIFS +License: GPL +URL: https://example.com + +%description +Diagnostics scripts for NFS and CIFS + +%prep + +%install +# Install script and related files +# install -m 454 ~/opt/xstore/bin/wrapper.sh %{buildroot}/opt/xstore/bin/wrapper.sh +cp -r ~/rpmbuild/SOURCES/opt %{buildroot} +echo %{buildroot} + +%post +chmod 454 $SYS_DIR/bin/wrapper.sh + +%files +# List all the files that are part of the package +# /opt/xstore/bin/wrapper.sh +$SYS_DIR/bin/wrapper.sh +$SYS_DIR/lib/NfsDiagnostics/README +$SYS_DIR/lib/NfsDiagnostics/nfsclientlogs.sh +$SYS_DIR/lib/NfsDiagnostics/trace-nfsbpf +$SYS_DIR/lib/SMBDiagnostics/README +$SYS_DIR/lib/SMBDiagnostics/smbclientlogs.sh +$SYS_DIR/lib/SMBDiagnostics/trace-cifsbpf +%changelog + +%postun +rm -r $SYS_DIR diff --git a/wrapper.sh b/wrapper.sh new file mode 100755 index 0000000..be66374 --- /dev/null +++ b/wrapper.sh @@ -0,0 +1,19 @@ +#!/usr/bin/bash + +PACKAGE_TREE="$(dirname $(dirname $(readlink -f $0)))" +run() { + if [[ $1 == "nfs" ]] || [[ $1 == "cifs" ]]; + then + echo $1; + if [[ $1 == "nfs" ]] + then script_path="${PACKAGE_TREE}/lib/NfsDiagnostics/nfsclientlogs.sh" + else script_path="${PACKAGE_TREE}/lib/SMBDiagnostics/smbclientlogs.sh" + fi + $script_path "$@" + + else + echo "Syntax: $SCRIPT_NAME [Version] [CaptureNetwork] [OnAnomaly]" >&2 + fi +} + +run "$@" From 65146fa3e9e0378e3d1a066ccfcdf05b2c2679d2 Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon, 3 Jul 2023 14:29:38 +0530 Subject: [PATCH 2/9] Packaging NFS and CIFS into .deb and .rpm packages. * Created Makefile to generate .deb and .rpm packages. * Created single wrapper file (diag-main.sh) to invoke both smbclientlogs.sh and nfsclientlogs.sh. --- NfsDiagnostics/nfsclientlogs.sh | 2 +- SMBDiagnostics/smbclientlogs.sh | 2 +- wrapper.sh => diag-main.sh | 3 +-- packaging/DEBIAN/postinst | 4 ++-- packaging/Makefile | 19 ++++--------------- packaging/README.md | 8 ++++---- packaging/RPM/spec.spec | 8 ++++---- 7 files changed, 17 insertions(+), 29 deletions(-) rename wrapper.sh => diag-main.sh (76%) diff --git a/NfsDiagnostics/nfsclientlogs.sh b/NfsDiagnostics/nfsclientlogs.sh index 1b993a2..4dc6a4b 100755 --- a/NfsDiagnostics/nfsclientlogs.sh +++ b/NfsDiagnostics/nfsclientlogs.sh @@ -23,7 +23,7 @@ main() { then stop 0<&- > "${STDLOG_FILE}" 2>&1 else - echo "Usage: ./nfsclientlogs.sh <> " + echo "Usage: diag-main.sh nfs " exit 1 fi diff --git a/SMBDiagnostics/smbclientlogs.sh b/SMBDiagnostics/smbclientlogs.sh index ae62212..8d520f5 100755 --- a/SMBDiagnostics/smbclientlogs.sh +++ b/SMBDiagnostics/smbclientlogs.sh @@ -16,7 +16,7 @@ main() { then stop 0<&- > "${STDLOG_FILE}" 2>&1 else - echo "Usage: ./smbclientlogs.sh " + echo "Usage: diag-main.sh cifs " exit 1 fi diff --git a/wrapper.sh b/diag-main.sh similarity index 76% rename from wrapper.sh rename to diag-main.sh index be66374..2e9bd0a 100755 --- a/wrapper.sh +++ b/diag-main.sh @@ -4,7 +4,6 @@ PACKAGE_TREE="$(dirname $(dirname $(readlink -f $0)))" run() { if [[ $1 == "nfs" ]] || [[ $1 == "cifs" ]]; then - echo $1; if [[ $1 == "nfs" ]] then script_path="${PACKAGE_TREE}/lib/NfsDiagnostics/nfsclientlogs.sh" else script_path="${PACKAGE_TREE}/lib/SMBDiagnostics/smbclientlogs.sh" @@ -12,7 +11,7 @@ run() { $script_path "$@" else - echo "Syntax: $SCRIPT_NAME [Version] [CaptureNetwork] [OnAnomaly]" >&2 + echo "Usage: diag-main.sh [Version] [CaptureNetwork] [OnAnomaly]" >&2 fi } diff --git a/packaging/DEBIAN/postinst b/packaging/DEBIAN/postinst index f65ab53..3fd1675 100755 --- a/packaging/DEBIAN/postinst +++ b/packaging/DEBIAN/postinst @@ -1,3 +1,3 @@ -chown root:root $SYS_DIR/bin/wrapper.sh -chmod 454 $SYS_DIR/bin/wrapper.sh +chown root:root $SYS_DIR/bin/diag-main.sh +chmod 454 $SYS_DIR/bin/diag-main.sh diff --git a/packaging/Makefile b/packaging/Makefile index e1bcef5..68ea217 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -1,5 +1,4 @@ -export sles= -export PKG_NAME=nfs-cifs-diag +export PKG_NAME=azure-files-diag export RELEASE=1 export VERSION=1 export SYS_DIR=/opt/xstore @@ -10,22 +9,18 @@ export PKG_DIR=$(PKG_NAME) export DEB_PKG_DIR=$(PKG_DIR)/DEBIAN export OPT_DIR=$(PKG_DIR)$(SYS_DIR) -build: init - echo $(SRC_DIR) - echo hello +build: init debian rpm clean + echo "Building deb and rpm packages" init: mkdir -p $(OPT_DIR)/bin mkdir -p $(OPT_DIR)/lib cp -r ../NfsDiagnostics $(OPT_DIR)/lib cp -r ../SMBDiagnostics $(OPT_DIR)/lib - cp -r ../wrapper.sh $(OPT_DIR)/bin + cp -r ../diag-main.sh $(OPT_DIR)/bin debian: init cp -r ./DEBIAN ./$(PKG_DIR) - # sed -i "s/\$$PKG_NAME/${PKG_NAME}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst - # sed -i "s/\$$SYS_DIR/${SYS_DIR}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst - # sed -i "s/\$$VERSION/${VERSION}/g" ./$(PKG_DIR)/DEBIAN/control ./$(PKG_DIR)/DEBIAN/postrm ./$(PKG_DIR)/DEBIAN/postinst for file in ./$(PKG_DIR)/DEBIAN/*; do \ sed -i "s/\$$PKG_NAME/${PKG_NAME}/g" $$file; \ sed -i "s:\$$SYS_DIR:${SYS_DIR}:g" $$file; \ @@ -45,11 +40,5 @@ rpm: init mv ~/rpmbuild/RPMS/x86_64/*.rpm . rm -r ~/rpmbuild - - -suse: - echo suse - - clean: rm -rf ./$(PKG_DIR) spec.spec diff --git a/packaging/README.md b/packaging/README.md index 216e457..227019f 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1,4 +1,4 @@ - -1. Run `make debian` to generate .deb package -2. Run `make rpm` to generate .rpm package -3. Run `make clean` once the packages are created. +Run `make` to generate both .deb and .rpm packages and clean the build directories or individually run the following. +Run `make debian` to generate .deb package +Run `make rpm` to generate .rpm package +Run `make clean` once the packages are created. diff --git a/packaging/RPM/spec.spec b/packaging/RPM/spec.spec index fef41b1..9db09ac 100644 --- a/packaging/RPM/spec.spec +++ b/packaging/RPM/spec.spec @@ -12,17 +12,17 @@ Diagnostics scripts for NFS and CIFS %install # Install script and related files -# install -m 454 ~/opt/xstore/bin/wrapper.sh %{buildroot}/opt/xstore/bin/wrapper.sh +# install -m 454 ~/opt/xstore/bin/diag-main.sh %{buildroot}/opt/xstore/bin/diag-main.sh cp -r ~/rpmbuild/SOURCES/opt %{buildroot} echo %{buildroot} %post -chmod 454 $SYS_DIR/bin/wrapper.sh +chmod 454 $SYS_DIR/bin/diag-main.sh %files # List all the files that are part of the package -# /opt/xstore/bin/wrapper.sh -$SYS_DIR/bin/wrapper.sh +# /opt/xstore/bin/diag-main.sh +$SYS_DIR/bin/diag-main.sh $SYS_DIR/lib/NfsDiagnostics/README $SYS_DIR/lib/NfsDiagnostics/nfsclientlogs.sh $SYS_DIR/lib/NfsDiagnostics/trace-nfsbpf From b0ed4e0281edf37565508a1e190cfbe37b20434f Mon Sep 17 00:00:00 2001 From: aman-1004 <77986530+aman-1004@users.noreply.github.com> Date: Mon, 3 Jul 2023 15:29:57 +0530 Subject: [PATCH 3/9] Update README.md --- packaging/README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packaging/README.md b/packaging/README.md index 227019f..afe1488 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1,4 +1,8 @@ -Run `make` to generate both .deb and .rpm packages and clean the build directories or individually run the following. -Run `make debian` to generate .deb package -Run `make rpm` to generate .rpm package -Run `make clean` once the packages are created. +Run `make` to generate both .deb and .rpm packages and clean the build directories or individually run the following: + +- Run `make debian` to generate .deb package +- Run `make rpm` to generate .rpm package +- Run `make clean` once the packages are created. + +Edit `DEBIAN/control` and `RPM/spec.spec` files to change package description or maintainer information. \ +Edit `Makefile` to make changes to PKG_NAME, RELEASE or VERSION, etc. From dc17685c66aac5a4f9ccc07a73d9b02c2dc2cdb9 Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Wed, 5 Jul 2023 13:39:32 +0530 Subject: [PATCH 4/9] Updated README for diag-main.sh and changed the python invocation for trace-nfsbpf and trace-cifsbpf scripts. --- NfsDiagnostics/nfsclientlogs.sh | 2 +- NfsDiagnostics/trace-nfsbpf | 2 +- SMBDiagnostics/smbclientlogs.sh | 2 +- SMBDiagnostics/trace-cifsbpf | 2 +- packaging/README.md | 29 +++++++++++++++++++++++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/NfsDiagnostics/nfsclientlogs.sh b/NfsDiagnostics/nfsclientlogs.sh index 4dc6a4b..a24d226 100755 --- a/NfsDiagnostics/nfsclientlogs.sh +++ b/NfsDiagnostics/nfsclientlogs.sh @@ -91,7 +91,7 @@ capture_network() { } trace_nfsbpf() { - nohup "${PYTHON_PROG}" "${TRACE_NFSBPF_ABS_PATH}" "${DIRNAME}" 0<&- 2>&1 & + nohup /usr/bin/env "${PYTHON_PROG}" "${TRACE_NFSBPF_ABS_PATH}" "${DIRNAME}" 0<&- 2>&1 & } stop() { diff --git a/NfsDiagnostics/trace-nfsbpf b/NfsDiagnostics/trace-nfsbpf index 25692cd..8ec1101 100755 --- a/NfsDiagnostics/trace-nfsbpf +++ b/NfsDiagnostics/trace-nfsbpf @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python from bcc import BPF from bcc.utils import printb from time import sleep diff --git a/SMBDiagnostics/smbclientlogs.sh b/SMBDiagnostics/smbclientlogs.sh index 8d520f5..f2fba6f 100755 --- a/SMBDiagnostics/smbclientlogs.sh +++ b/SMBDiagnostics/smbclientlogs.sh @@ -117,7 +117,7 @@ capture_network() { } trace_cifsbpf() { - nohup "${PYTHON_PROG}" "${TRACE_CIFSBPF_ABS_PATH}" "${DIRNAME}" 0<&- 2>&1 & + nohup /usr/bin/env "${PYTHON_PROG}" "${TRACE_CIFSBPF_ABS_PATH}" "${DIRNAME}" 0<&- 2>&1 & } stop() { diff --git a/SMBDiagnostics/trace-cifsbpf b/SMBDiagnostics/trace-cifsbpf index cd88ff2..187acf4 100644 --- a/SMBDiagnostics/trace-cifsbpf +++ b/SMBDiagnostics/trace-cifsbpf @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python from bcc import BPF from bcc.utils import printb from time import sleep diff --git a/packaging/README.md b/packaging/README.md index afe1488..6c059bb 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1,3 +1,4 @@ +# Generate Packages: Run `make` to generate both .deb and .rpm packages and clean the build directories or individually run the following: - Run `make debian` to generate .deb package @@ -6,3 +7,31 @@ Run `make` to generate both .deb and .rpm packages and clean the build directori Edit `DEBIAN/control` and `RPM/spec.spec` files to change package description or maintainer information. \ Edit `Makefile` to make changes to PKG_NAME, RELEASE or VERSION, etc. + +# Installation: +Debian: + `sudo dpkg -i azure-files-diag.deb` + +RPM: + `sudo rpm -i azure-files-diag-*.x86_64.rpm` + +Add `/opt/xstore/bin/diag-main.sh` to `PATH` for root user. __[Optional]__ + +# How to use: + +These scripts require root priveleges. +1. Start trace: +`sudo diag-main.sh start [] [CaptureNetwork] [OnAnomaly]`. + - NFS defaults to __v4__ (if no version is specified). + - [OPTION] are optional arguments. + +2. Stop: +If __OnAnomaly__ option is enabled, the script will auto detect and collect the traces and generate the zip file. No action needed here. Otherwise: `sudo diag-main.sh stop` + + +# Uninstall: +Debian: + `sudo apt remove azure-files-diag` + +RPM: + `sudo rpm -e azure-files-diag` From 2073b919dd8a45cf18aae9bc2ecb72faca9a7de4 Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu, 20 Jul 2023 04:01:22 +0530 Subject: [PATCH 5/9] Squashed commit of the following: commit dc391f6c12456499791089100652e72fc1c1e4df Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu Jul 20 03:55:42 2023 +0530 added hooks for shellcheck commit 2f3f3e47db572440f83ad8ce257ea080fa79c318 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu Jul 20 03:45:15 2023 +0530 small fix for trace-cifsbpf and trace-nfsbpf scripts commit c4e3d6a2e48cf7488939b5473a7e9d04666e99ad Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu Jul 20 03:45:03 2023 +0530 small fix for trace-cifsbpf and trace-nfsbpf scripts commit b78153e93eb9376012081451c7e1e3571b485365 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Wed Jul 19 18:49:32 2023 +0530 updated readme file for dependency change commit ea86f74c388c75783fab33a123fd78fb9dc75180 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Wed Jul 19 16:02:52 2023 +0530 fixed dep commit commit 6e461165e973627efe001b299a1faf4d2d8bb8a3 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Wed Jul 19 15:24:12 2023 +0530 dependency commit commit ee5346a948876db3c1c32e39dbc0fc3525f650f6 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Wed Jul 19 09:14:07 2023 +0530 changed filename to cifs_dmesg from nfs_dmesg within trace-cifsbpf commit 66b4180e5285fdc1e498949189c143f162463655 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Tue Jul 18 22:31:41 2023 +0530 demo commit ce2835846eef010aa59ef343217376419b5ef690 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Tue Jul 18 22:16:27 2023 +0530 demo automatic build commit df4b6b6f47b872a19d381c285dd269f2b5e45fdc Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 15:38:34 2023 +0530 random commit af374b72d0d0f804a711db198c1f7c9d2fba40c5 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 15:37:56 2023 +0530 random commit a0633db430d0e4c846260b8dbd04b685e768ec61 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 15:34:47 2023 +0530 random commit 702a029090c0e6a17793ba2c70d8ca2b591672b4 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 14:25:29 2023 +0530 testing git hooks commit 654e61a963bca582d5aab5db0f558aafcaebc1de Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 14:07:37 2023 +0530 random commit 4ddee636f5fe532187377224e478e1533a7b77ba Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 13:39:14 2023 +0530 random commit 8faaaad05e6b8d62a4c013da454de6118009c170 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 13:35:09 2023 +0530 random commit 5e352f70a0b6c62002f32510760c435f5d599638 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 13:31:27 2023 +0530 random commit 739fabe22944cd04a29e01c9acbe4fc3893fb407 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 13:15:01 2023 +0530 random commit 3bda9fb1d77f8894f8b53494343ec99124911448 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 09:11:23 2023 +0530 random commit 25a0e0d1e5eb1d73af23d0ed5c4b4937dfc7dd94 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 09:01:41 2023 +0530 random commit 595a9d2aeef66e339016eba9ec483d775d638590 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 09:00:06 2023 +0530 random commit e624c3a71eb909b3cd6d46827cc2ea79c8fd6ae3 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 08:37:48 2023 +0530 random commit 79ac92c8981e31899a5001f0e490bdc6644c083c Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 08:35:36 2023 +0530 _tmp commit 443f5ad3445bdf2be833db84f890668891585552 Author: Aman <2020ceb1004@iitrpr.ac.in> Date: Mon Jul 10 08:27:48 2023 +0530 testing actions Built an automated setup to build DEP and RPM packages on sucessful push. * Added github hooks to validate scripts before commiting. * Added github action to automatically build the packages on succesful push. * Fixed some minor issues with cifs and nfs diagnostic scripts. --- .githooks/pre-commit | 14 +++++++ .github/workflows/packaging-action.yaml | 54 +++++++++++++++++++++++++ NfsDiagnostics/nfsclientlogs.sh | 12 +++++- NfsDiagnostics/trace-nfsbpf | 20 ++++----- SMBDiagnostics/smbclientlogs.sh | 12 +++++- SMBDiagnostics/trace-cifsbpf | 18 +++++---- demo.txt | 0 diag-main.sh | 3 +- enable-hooks.md | 1 + ignore.txt | 0 packaging/.gitignore | 2 + packaging/DEBIAN/control | 1 + packaging/Makefile | 7 +++- packaging/README.md | 6 +-- packaging/RPM/spec.spec | 6 +++ packaging/VERSION.txt | 1 + 16 files changed, 131 insertions(+), 26 deletions(-) create mode 100755 .githooks/pre-commit create mode 100644 .github/workflows/packaging-action.yaml create mode 100644 demo.txt create mode 100644 enable-hooks.md create mode 100644 ignore.txt create mode 100644 packaging/.gitignore create mode 100644 packaging/VERSION.txt diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 0000000..3fe92c4 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if ! shellcheck -S error NfsDiagnostics/nfsclientlogs.sh SMBDiagnostics/smbclientlogs.sh +then + echo "Shellcheck failed" + exit 1 +fi diff --git a/.github/workflows/packaging-action.yaml b/.github/workflows/packaging-action.yaml new file mode 100644 index 0000000..16d33a7 --- /dev/null +++ b/.github/workflows/packaging-action.yaml @@ -0,0 +1,54 @@ +name: Package NFS and CIFS diagnostic scripts +run-name: Package NFS and CIFS diagnostic scripts +on: [push] + +jobs: + package: + runs-on: ubuntu-latest + + steps: + # - name: Download version artifact + # continue-on-error: true + # uses: actions/download-artifact@v3 + # with: + # name: version + # path: packaging + + + - name: Set up environment + run: | + sudo apt install -y shellcheck + sudo apt install -y rpm + sudo apt install -y build-essential + sudo apt install -y debhelper + + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: ShellCheck-Validation + run: | + if ! shellcheck -S error NfsDiagnostics/nfsclientlogs.sh SMBDiagnostics/smbclientlogs.sh; then echo "ShellCheck Failed"; exit 1; fi + + - name: Build Packages + run: | + cd packaging + make + + - name: Upload Debian Package + uses: actions/upload-artifact@v3 + with: + name: debian-package + path: packaging/*.deb + + - name: Upload RPM Package + uses: actions/upload-artifact@v3 + with: + name: rpm-package + path: packaging/*.rpm + + # - name: Update Future Version + # uses: actions/upload-artifact@v3 + # with: + # name: version + # path: packaging/VERSION.txt + diff --git a/NfsDiagnostics/nfsclientlogs.sh b/NfsDiagnostics/nfsclientlogs.sh index a24d226..322bcc7 100755 --- a/NfsDiagnostics/nfsclientlogs.sh +++ b/NfsDiagnostics/nfsclientlogs.sh @@ -3,11 +3,19 @@ PIDFILE="/tmp/nfsclientlog.pid" DIRNAME="./output" NFS_PORT=2049 -TRACE_NFSBPF_ABS_PATH="$(cd "$(dirname "trace-nfsbpf")" && pwd)/$(basename "trace-nfsbpf")" +#TRACE_NFSBPF_ABS_PATH="$(cd "$(dirname "trace-nfsbpf")" && pwd)/$(basename "trace-nfsbpf")" +TRACE_NFSBPF_ABS_PATH="/opt/xstore/lib/NfsDiagnostics/trace-nfsbpf" PYTHON_PROG='python' STDLOG_FILE='/dev/null' +# to enable backward compatibility. +_trace_nfsfsbpf_alt_path="$(cd "$(dirname "trace-nfsbpf")" && pwd)/$(basename "trace-nfsbpf")" +if [[ -f "${_trace_nfsbpf_alt_path}" ]]; +then + TRACE_NFSBPF_ABS_PATH="${_trace_nfsbpf_alt_path}" +fi + main() { if [[ "$*" =~ "v3b" ]] then @@ -45,7 +53,7 @@ start() { init() { check_utils - rm -r "$DIRNAME" + rm -rf "$DIRNAME" mkdir -p "$DIRNAME" dmesg -Tc > /dev/null diff --git a/NfsDiagnostics/trace-nfsbpf b/NfsDiagnostics/trace-nfsbpf index 8ec1101..1d1d40e 100755 --- a/NfsDiagnostics/trace-nfsbpf +++ b/NfsDiagnostics/trace-nfsbpf @@ -4,6 +4,7 @@ from bcc.utils import printb from time import sleep import os from sys import argv +from datetime import datetime # define BPF program bpf_text= """ #include @@ -90,10 +91,10 @@ b.attach_tracepoint(tp="nfs:nfs_commit_error", fn_name="trace_page_error") b.attach_tracepoint(tp="nfs:nfs_pgio_error", fn_name="trace_pgio_error") b.attach_tracepoint(tp="nfs:nfs_writeback_page_exit", fn_name="trace_inode_event") b.attach_tracepoint(tp="nfs:nfs_writeback_inode_exit", fn_name="trace_inode_event") -print("Running Anomaly") class stop_and_collapse(Exception): pass +print(f"[{str(datetime.now())}] Running Anomaly Mode") while 1: try: sleep(1); @@ -109,17 +110,18 @@ while 1: break; output_dir = argv[1] -print("Exiting Anomaly") -fd=open("/tmp/nfsclientlog.pid", "r"); -# trace_pid=fd.readline(); -tcpdump_pid=fd.readline(); -print(tcpdump_pid) -command = "kill -INT %s" % (tcpdump_pid) -os.system(command); -# command = "kill -INT %s" % (trace_pid) +print(f"[{str(datetime.now())}] Exiting Anomaly Mode") +if(os.path.exists("/tmp/nfsclientlog.pid")): + fd=open("/tmp/nfsclientlog.pid", "r"); + tcpdump_pid=fd.readline(); + command = "kill -INT %s" % (tcpdump_pid) + os.system(command); + command = "trace-cmd stop" os.system(command); sleep(3) + +os.system(f"trace-cmd extract") os.system(f"trace-cmd report 2>&1 > {output_dir}/nfs_trace") os.system("trace-cmd reset") os.system(f"sudo dmesg -c > {output_dir}/nfs_dmesg") diff --git a/SMBDiagnostics/smbclientlogs.sh b/SMBDiagnostics/smbclientlogs.sh index f2fba6f..7f34d67 100755 --- a/SMBDiagnostics/smbclientlogs.sh +++ b/SMBDiagnostics/smbclientlogs.sh @@ -3,11 +3,19 @@ PIDFILE="/tmp/smbclientlog.pid" DIRNAME="./output" CIFS_PORT=445 -TRACE_CIFSBPF_ABS_PATH="$(cd "$(dirname "trace-cifsbpf")" && pwd)/$(basename "trace-cifsbpf")" +# TRACE_CIFSBPF_ABS_PATH="$(cd "$(dirname "trace-cifsbpf")" && pwd)/$(basename "trace-cifsbpf")" +TRACE_CIFSBPF_ABS_PATH="/opt/xstore/lib/SMBDiagnostics/trace-cifsbpf" PYTHON_PROG='python' STDLOG_FILE='/dev/null' +# to enable backward compatibility. +_trace_cifsbpf_alt_path="$(cd "$(dirname "trace-cifsbpf")" && pwd)/$(basename "trace-cifsbpf")" +if [[ -f "${_trace_cifsbpf_alt_path}" ]]; +then + TRACE_CIFSBPF_ABS_PATH="${_trace_cifsbpf_alt_path}" +fi + main() { if [[ "$*" =~ "start" ]] then @@ -43,7 +51,7 @@ start() { init() { check_utils - rm -r "$DIRNAME" + rm -rf "$DIRNAME" mkdir -p "$DIRNAME" dmesg -Tc > /dev/null diff --git a/SMBDiagnostics/trace-cifsbpf b/SMBDiagnostics/trace-cifsbpf index 187acf4..d54f4c0 100644 --- a/SMBDiagnostics/trace-cifsbpf +++ b/SMBDiagnostics/trace-cifsbpf @@ -133,19 +133,21 @@ while 1: output_dir = argv[1] print(f"[{str(datetime.now())}] Exiting Anomaly Mode") -fd=open("/tmp/smbclientlog.pid", "r"); -# trace_pid=fd.readline(); -tcpdump_pid=fd.readline(); -print(tcpdump_pid) -command = "kill -INT %s" % (tcpdump_pid) -os.system(command); -# command = "kill -INT %s" % (trace_pid) + +if(os.path.exists("/tmp/smbclientlog.pid")): + fd=open("/tmp/smbclientlog.pid", "r"); + tcpdump_pid=fd.readline(); + command = "kill -INT %s" % (tcpdump_pid) + os.system(command); + command = "trace-cmd stop" os.system(command); sleep(3) + +os.system(f"trace-cmd extract") os.system(f"trace-cmd report 2>&1 > {output_dir}/cifs_trace") os.system("trace-cmd reset") -os.system(f"sudo dmesg -c > {output_dir}/nfs_dmesg") +os.system(f"sudo dmesg -c > {output_dir}/cifs_dmesg") os.system(f"mv cifs_diag.txt {output_dir}") os.system(f"mv os_details.txt {output_dir}") command = f"zip -r $(basename {output_dir}).zip {output_dir}" diff --git a/demo.txt b/demo.txt new file mode 100644 index 0000000..e69de29 diff --git a/diag-main.sh b/diag-main.sh index 2e9bd0a..29fb9c9 100755 --- a/diag-main.sh +++ b/diag-main.sh @@ -1,6 +1,7 @@ #!/usr/bin/bash -PACKAGE_TREE="$(dirname $(dirname $(readlink -f $0)))" +# PACKAGE_TREE="$(dirname $(dirname $(readlink -f $0)))" +PACKAGE_TREE="/opt/xstore" run() { if [[ $1 == "nfs" ]] || [[ $1 == "cifs" ]]; then diff --git a/enable-hooks.md b/enable-hooks.md new file mode 100644 index 0000000..4a457dc --- /dev/null +++ b/enable-hooks.md @@ -0,0 +1 @@ +Run this command in repo's root directory to enable local validations: `git config core.hooksPath .githooks` diff --git a/ignore.txt b/ignore.txt new file mode 100644 index 0000000..e69de29 diff --git a/packaging/.gitignore b/packaging/.gitignore new file mode 100644 index 0000000..f7288a3 --- /dev/null +++ b/packaging/.gitignore @@ -0,0 +1,2 @@ +*.rpm +*.deb diff --git a/packaging/DEBIAN/control b/packaging/DEBIAN/control index 55490eb..7b98087 100644 --- a/packaging/DEBIAN/control +++ b/packaging/DEBIAN/control @@ -3,3 +3,4 @@ Version: $VERSION Maintainer: Microsoft Architecture: all Description: Diagnostics scripts for CIFS and NFS. +Depends: tcpdump, trace-cmd, nfs-common, bpfcc-tools diff --git a/packaging/Makefile b/packaging/Makefile index 68ea217..729a13a 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -1,6 +1,6 @@ export PKG_NAME=azure-files-diag export RELEASE=1 -export VERSION=1 +VERSION := $(shell cat ./VERSION.txt) export SYS_DIR=/opt/xstore export SRC_DIR=.. # export PKG_BUILD=$(PKG_NAME)$(sles)-$(RELEASE)-1.x86_64 @@ -13,6 +13,8 @@ build: init debian rpm clean echo "Building deb and rpm packages" init: + # if [ -f VERSION.txt ]; then echo "file present";VERSION=$(shell cat ./VERSION.txt); fi + echo "Building Version: ${VERSION}" mkdir -p $(OPT_DIR)/bin mkdir -p $(OPT_DIR)/lib cp -r ../NfsDiagnostics $(OPT_DIR)/lib @@ -40,5 +42,8 @@ rpm: init mv ~/rpmbuild/RPMS/x86_64/*.rpm . rm -r ~/rpmbuild +post: + expr ${VERSION} + 1 > VERSION.txt + clean: rm -rf ./$(PKG_DIR) spec.spec diff --git a/packaging/README.md b/packaging/README.md index 6c059bb..88e1212 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -10,10 +10,10 @@ Edit `Makefile` to make changes to PKG_NAME, RELEASE or VERSION, etc. # Installation: Debian: - `sudo dpkg -i azure-files-diag.deb` + `sudo apt install -f ./azure-files-diag.deb` RPM: - `sudo rpm -i azure-files-diag-*.x86_64.rpm` + `sudo dnf install ./azure-files-diag-*.x86_64.rpm` Add `/opt/xstore/bin/diag-main.sh` to `PATH` for root user. __[Optional]__ @@ -34,4 +34,4 @@ Debian: `sudo apt remove azure-files-diag` RPM: - `sudo rpm -e azure-files-diag` + `sudo dnf remove azure-files-diag` diff --git a/packaging/RPM/spec.spec b/packaging/RPM/spec.spec index 9db09ac..b5408bb 100644 --- a/packaging/RPM/spec.spec +++ b/packaging/RPM/spec.spec @@ -5,6 +5,12 @@ Summary: Diagnostics scripts for NFS and CIFS License: GPL URL: https://example.com +Requires: tcpdump +Requires: trace-cmd +Requires: rpcdebug +Requires: bcc + + %description Diagnostics scripts for NFS and CIFS diff --git a/packaging/VERSION.txt b/packaging/VERSION.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/packaging/VERSION.txt @@ -0,0 +1 @@ +1 From a9d6e3a3ea6c6034b5bc06185cc60225c9bacd34 Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu, 20 Jul 2023 04:09:29 +0530 Subject: [PATCH 6/9] removed a demo file created --- demo.txt | 0 ignore.txt | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 demo.txt delete mode 100644 ignore.txt diff --git a/demo.txt b/demo.txt deleted file mode 100644 index e69de29..0000000 diff --git a/ignore.txt b/ignore.txt deleted file mode 100644 index e69de29..0000000 From 734b908aaf4544f5234fd49ae6d4fe8830c5afe2 Mon Sep 17 00:00:00 2001 From: Aman <2020ceb1004@iitrpr.ac.in> Date: Thu, 20 Jul 2023 09:19:43 +0530 Subject: [PATCH 7/9] added the POC health check daemon and added readme for git hooks and actions --- README_hooks.md | 10 ++ enable-hooks.md | 1 - health-check-daemon-POC/README.md | 14 +++ health-check-daemon-POC/buggy-module/Makefile | 7 ++ health-check-daemon-POC/buggy-module/module.c | 57 ++++++++++++ .../buggy-module/moduleA.ko | Bin 0 -> 70784 bytes .../buggy-module/moduleB.ko | Bin 0 -> 70784 bytes health-check-daemon-POC/crash_dump.sh | 88 ++++++++++++++++++ health-check-daemon-POC/main.sh | 23 +++++ health-check-daemon-POC/t.awk | 21 +++++ 10 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 README_hooks.md delete mode 100644 enable-hooks.md create mode 100644 health-check-daemon-POC/README.md create mode 100644 health-check-daemon-POC/buggy-module/Makefile create mode 100644 health-check-daemon-POC/buggy-module/module.c create mode 100644 health-check-daemon-POC/buggy-module/moduleA.ko create mode 100644 health-check-daemon-POC/buggy-module/moduleB.ko create mode 100755 health-check-daemon-POC/crash_dump.sh create mode 100755 health-check-daemon-POC/main.sh create mode 100755 health-check-daemon-POC/t.awk diff --git a/README_hooks.md b/README_hooks.md new file mode 100644 index 0000000..a4903a2 --- /dev/null +++ b/README_hooks.md @@ -0,0 +1,10 @@ +# Git Hooks +- The hooks need to be enabled manually by the contributor. +- To enable hooks, change the default hook directory by `git config core.hooksPath .githooks` or manually copy hooks from `.githooks` to `.git/hooks` +- New validations can be added to `.githooks/pre-commit`. + + +# GitHub Actions +- Github actions are stored in .github/workflow +- To modify automatic packaging process (for cifs and nfs diagnostic scripts), make changes to .github/workflow/packaging-action.yaml +- New validations can be added here. diff --git a/enable-hooks.md b/enable-hooks.md deleted file mode 100644 index 4a457dc..0000000 --- a/enable-hooks.md +++ /dev/null @@ -1 +0,0 @@ -Run this command in repo's root directory to enable local validations: `git config core.hooksPath .githooks` diff --git a/health-check-daemon-POC/README.md b/health-check-daemon-POC/README.md new file mode 100644 index 0000000..cdc6ee7 --- /dev/null +++ b/health-check-daemon-POC/README.md @@ -0,0 +1,14 @@ +# Steps to simulate fault and test the daemon: +1. Install the linux-crashdump using `./crash_dump.sh install`. This step requires a reboot. +2. Start the daemon by running 'sudo ./main.sh'. +3. Simulate fault by inserting module from `./buggy-module/moduleA.ko`. +4. Wait for daemon to print "Crash Dump Enabled". +5. Once crash dump is enabled, insert the other copy of buggy module `./buggy-module/moduleB.ko` +6. This should trigger a kernel panic and the system should enter into a reboot. +7. Crashdumps will be generated inside `/var/crash` directory. +8. Disable crashdumps manually running `sudo ./crash_dump.sh disable`. + +# Note: +- crashdumps can be enabled without a restart. +- disabling crashdumps require a restart. +- moduleB is a copy of moduleA. We need two copies because when the buggy module is inserted, it cannot be removed from kernel by running `rmmod Module Name`. So instead of inserting, removing and reinserting the same module, we instead use a copy of the same module. diff --git a/health-check-daemon-POC/buggy-module/Makefile b/health-check-daemon-POC/buggy-module/Makefile new file mode 100644 index 0000000..4fa2ad0 --- /dev/null +++ b/health-check-daemon-POC/buggy-module/Makefile @@ -0,0 +1,7 @@ +obj-m += module.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/health-check-daemon-POC/buggy-module/module.c b/health-check-daemon-POC/buggy-module/module.c new file mode 100644 index 0000000..9fcee59 --- /dev/null +++ b/health-check-daemon-POC/buggy-module/module.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +MODULE_AUTHOR("Aman"); +MODULE_DESCRIPTION("This module when inserted causes null pointer dereference fault"); +MODULE_LICENSE("GPL"); + +typedef struct ABC { + int a; + int b; +} ABC; + +ABC* ptr; + +void print(ABC* abc) { + printk(KERN_INFO "abc(a: %d, b: %d)\n", abc->a, abc->b); +} + +void cause_gpf(void) { + printk(KERN_WARNING "Hello World \n\n"); + ptr = kmalloc(sizeof(ABC), GFP_KERNEL); + ptr->a = 118; + ptr->b = 212; + + printk(KERN_INFO "Before Free:"); + print(ptr); + kfree(ptr); +} + +void cause_nullderef(void) { + ptr = kmalloc(sizeof(ABC), GFP_KERNEL); + ptr -> a = 118; + ptr -> b = 212; + printk(KERN_INFO "Before Free"); + print(ptr); + kfree(ptr); + ptr = NULL; + print(ptr); +} + +static int __init custom_init(void) { + cause_nullderef(); + return 1; +} + +static void __exit custom_exit(void) { + printk(KERN_INFO "After Free:"); + print(ptr); + printk(KERN_INFO "Goodbye |:>)\n\n"); +} + +module_init(custom_init); +module_exit(custom_exit); + + diff --git a/health-check-daemon-POC/buggy-module/moduleA.ko b/health-check-daemon-POC/buggy-module/moduleA.ko new file mode 100644 index 0000000000000000000000000000000000000000..0097d99c27f8c8bc9fb2e0471f7dd9c16ddce9c2 GIT binary patch literal 70784 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 literal 0 HcmV?d00001 diff --git a/health-check-daemon-POC/buggy-module/moduleB.ko b/health-check-daemon-POC/buggy-module/moduleB.ko new file mode 100644 index 0000000000000000000000000000000000000000..6848ffb482e7becf5eed70ef1f9877298b52f90a GIT binary patch literal 70784 zcmeFacVJw_)i-?au2x=2mbB`!B-<<7a*@3%mWvE7l4aQvwhEGsZQ6PztqN8{yK2qAo@&Fb#4otNi(-si9PS@6}I-<&x! zbLPyMGjs3WJ)wThN|$Y0=3`q+tue}=mbEKs46Px!#+q%FS_zQOhJSAOx2k!ab^iAI zpMK%x+f$x;?v32ebNsKL)Ok^7BIF?-RB?^!9w)9C=MnG6lIzY|pK#Vf zBU);5=Buo|TKC^-T3kg^`Mszn&RC}^7lk;hq%?Ee3ql>8GeZaXOSwox;nOp{l^}#bXIaQ>gYdy?0F60{{A8V`k|5j zF8|`j!AN){>aX9@*Y95w8tv%?(Mv&0e_v-9vX-oBU1N2HBb_6C!_mH>!6jUHD;4e< z>Dv+>u|lKK-l35tm5ZXiK`0a*9oZfPas8pbK`S!S2`mvTS-E26+_}r=&tI`%e$~PS zmGkQs)K^t4ss-u8;lZxR5^E$J9UkiM8w@YmXbpx2!b`fgM1xWX2pI_V^mQ(oUsgH4 ztRhfZF|RTZ+A#_`YHw=w4-9n$M+f_dLS2}Y8YBMys0hh?=%M7Dn1php{o!DLX#3D; zRPw&fpZmw}z^P?z?uN1YHU$*VzfXVULn=QI9td`ZI(x&x5R6Y}Fggf7~EF9AP8eHIx-lH_Kps2{tty5SuY=d*#%U7c%*MI`Yj7N z%0D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 literal 0 HcmV?d00001 diff --git a/health-check-daemon-POC/crash_dump.sh b/health-check-daemon-POC/crash_dump.sh new file mode 100755 index 0000000..e978fca --- /dev/null +++ b/health-check-daemon-POC/crash_dump.sh @@ -0,0 +1,88 @@ +#!/usr/bin/bash + +temp_action() { + echo "encountered error patterns" +} + +install_crashdump() { + export DEBIAN_FRONTEND=noninteractive + sudo DEBIAN_FRONTEND=noninteractive apt install -y linux-crashdump + echo 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT crashkernel=512M-:512M"' | sudo tee '/etc/default/grub.d/kdump-tools.cfg' + _update_configuration +} + + +_update_configuration() { + echo "This action requires a restart. Do you want to restart now. Enter (y|N)" + read -r var; + res=${var:0:1} + if [ "$res" == "y" ] || [ "$res" == "Y" ] + then + update-grub + echo restarting + reboot + return 0 + fi + return 1 +} + +enable_crash_dump() { + LOAD_KEXEC=$(awk -F= '/^LOAD_KEXEC/ {print $2}' /etc/default/kexec) + USE_KDUMP=$(awk -F= '/^USE_KDUMP/ {print $2}' /etc/default/kdump-tools) + echo $LOAD_KEXEC $USE_KDUMP + + if [ "$LOAD_KEXEC" == true ] && [ "$USE_KDUMP" == 1 ] + then + echo "Crash Dump is already enabled" + return 0 + fi + + if ! grep -q '^LOAD_KEXEC' /etc/default/kexec + then + echo LOAD_KEXEC=true >> /etc/default/kexec + else + sed 's/LOAD_KEXEC=false/LOAD_KEXEC=true/' -i /etc/default/kexec + fi + + if ! grep -q '^USE_KDUMP' /etc/default/kdump-tools + then + echo USE_KDUMP=1 >> /etc/default/kdump-tools + else + sed 's/USE_KDUMP=0/USE_KDUMP=1/' -i /etc/default/kdump-tools + fi + + kdump-config load + echo "Crash Dump Enabled" +} + +disable_crash_dump() { + LOAD_KEXEC=$(awk -F= '/^LOAD_KEXEC/ {print $2}' /etc/default/kexec) + USE_KDUMP=$(awk -F= '/^USE_KDUMP/ {print $2}' /etc/default/kdump-tools) + echo $LOAD_KEXEC $USE_KDUMP + + if [ "$LOAD_KEXEC" != true ] && [ "$USE_KDUMP" != 1 ] + then + echo "Crash Dump is already disabled" + return 0 + fi + + sed 's/LOAD_KEXEC=true/LOAD_KEXEC=false/' -i /etc/default/kexec + sed 's/USE_KDUMP=1/USE_KDUMP=0/' -i /etc/default/kdump-tools + + echo "Crash Dump Disabled" + _update_configuration + +} + +if [ "$1" == "enable" ] +then + enable_crash_dump +elif [ "$1" == "disable" ] +then + disable_crash_dump +elif [ "$1" == "install" ] +then + install_crashdump +else + echo "Usage: ./crash_dump.sh " +fi diff --git a/health-check-daemon-POC/main.sh b/health-check-daemon-POC/main.sh new file mode 100755 index 0000000..daa2413 --- /dev/null +++ b/health-check-daemon-POC/main.sh @@ -0,0 +1,23 @@ +SLEEP_DURATION=15 + +input_logs() { + # cat ./crashdmesg070501.txt ./VMcrashdmesg-20.97.25.82.txt + # journalctl -ro short-unix + dmesg +} + +signal_handler() { + sudo bash ./crash_dump.sh disable +} + +main() { + while true; + do + input_logs | sudo ./t.awk + # input_logs | sudo ./t2.awk + sleep ${SLEEP_DURATION} + done +} + +main + diff --git a/health-check-daemon-POC/t.awk b/health-check-daemon-POC/t.awk new file mode 100755 index 0000000..b3404a4 --- /dev/null +++ b/health-check-daemon-POC/t.awk @@ -0,0 +1,21 @@ +#!/usr/bin/awk -f + +BEGIN { + i=0; +} + +$0 ~ "general protection fault" || $0 ~ "use-after-free" || $0 ~ "kernel NULL pointer dereference" { + i++; + system("sudo bash ./crash_dump.sh enable"); + end(); +} + +END { + end(); +} + +function end() { + # print i; + # print "End"; + exit 0; +} From f2d97aa35038a98e8cc8b4b7365adf8dc305f924 Mon Sep 17 00:00:00 2001 From: aman-1004 <77986530+aman-1004@users.noreply.github.com> Date: Fri, 21 Jul 2023 00:42:41 +0530 Subject: [PATCH 8/9] Update README_hooks.md --- README_hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_hooks.md b/README_hooks.md index a4903a2..8836b00 100644 --- a/README_hooks.md +++ b/README_hooks.md @@ -6,5 +6,5 @@ # GitHub Actions - Github actions are stored in .github/workflow -- To modify automatic packaging process (for cifs and nfs diagnostic scripts), make changes to .github/workflow/packaging-action.yaml +- To modify automatic packaging process (for cifs and nfs diagnostic scripts), make changes to `.github/workflow/packaging-action.yaml` - New validations can be added here. From 85514dad0b7b118c99c330a105dcaff153196512 Mon Sep 17 00:00:00 2001 From: aman-1004 <77986530+aman-1004@users.noreply.github.com> Date: Fri, 21 Jul 2023 00:46:04 +0530 Subject: [PATCH 9/9] updated readme for health check daemon --- health-check-daemon-POC/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-check-daemon-POC/README.md b/health-check-daemon-POC/README.md index cdc6ee7..9aebc98 100644 --- a/health-check-daemon-POC/README.md +++ b/health-check-daemon-POC/README.md @@ -11,4 +11,4 @@ # Note: - crashdumps can be enabled without a restart. - disabling crashdumps require a restart. -- moduleB is a copy of moduleA. We need two copies because when the buggy module is inserted, it cannot be removed from kernel by running `rmmod Module Name`. So instead of inserting, removing and reinserting the same module, we instead use a copy of the same module. +- moduleB is a copy of moduleA. We need two copies because when the buggy module is inserted, it cannot be removed from kernel by running `rmmod MODULE_NAME`. So instead of inserting, removing and reinserting the same module, we instead use a copy of the same module.