Skip to content

[KubeSonic] Add bmp container watchdog #22352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions dockers/docker-bmp-watchdog/Dockerfile.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}} AS builder

# Update apt's cache of available packages
RUN apt-get update && apt-get install -y \
build-essential

# Install Rust/Cargo via rustup
ARG RUST_ROOT=/usr/.cargo
RUN RUSTUP_HOME=$RUST_ROOT CARGO_HOME=$RUST_ROOT bash -c \
'curl --proto "=https" -sSf https://sh.rustup.rs | sh -s -- --default-toolchain 1.79.0 -y'
ENV RUSTUP_HOME=$RUST_ROOT
ENV PATH $PATH:$RUST_ROOT/bin

# Copy watchdog source into /watchdog
WORKDIR /watchdog
COPY watchdog/ ./

# Build from within /watchdog
RUN cargo build --release

FROM docker-config-engine-bookworm-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}}

ARG docker_container_name
ARG image_version
RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf

ENV DEBIAN_FRONTEND=noninteractive
ENV IMAGE_VERSION=$image_version

RUN apt-get update

# Copy supervisord.conf into final stage
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]

# Copy the compiled Rust binary from the builder stage
COPY --from=builder /watchdog/target/release/bmp_watchdog /usr/bin/bmp_watchdog
RUN chmod +x /usr/bin/bmp_watchdog

ENTRYPOINT ["/usr/local/bin/supervisord"]
37 changes: 37 additions & 0 deletions dockers/docker-bmp-watchdog/supervisord.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true

[eventlistener:dependent-startup]
command=python3 -m supervisord_dependent_startup
autostart=true
autorestart=unexpected
startretries=0
exitcodes=0,3
events=PROCESS_STATE
buffer_size=1024

[program:rsyslogd]
command=/usr/sbin/rsyslogd -n -iNONE
priority=1
autostart=false
autorestart=unexpected
stdout_logfile=NONE
stdout_syslog=true
stderr_logfile=NONE
stderr_syslog=true
dependent_startup=true

[program:bmp_watchdog]
command=/usr/bin/bmp_watchdog
priority=3
autostart=false
autorestart=false
startsecs=0
stdout_logfile=NONE
stdout_syslog=true
stderr_logfile=NONE
stderr_syslog=true
dependent_startup=true
dependent_startup_wait_for=rsyslogd:running
7 changes: 7 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "bmp_watchdog"
version = "0.1.0"
edition = "2021"
description = "watchdog for bmp container"
license = "MIT"
authors = ["Feng Pan"]

[dependencies]
daemonize = "0.5"
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[[bin]]
name = "bmp_watchdog"
path = "src/main.rs"
27 changes: 27 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.ONESHELL:
SHELL = /bin/bash
.SHELLFLAGS += -e

#
# Debug build targets
#
build:
cargo build --all

test:
cargo test --all

clean:
cargo clean

#
# Release build targets
#
build-release:
cargo build --release --all

test-release:
cargo test --release --all

clean-release:
cargo clean --release
5 changes: 5 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/debian/changelog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sonic (1.0.0) stable; urgency=medium

* Initial release

-- Feng Pan <[email protected]> Tue, 15 Apr 2025 03:13:12 +0000
1 change: 1 addition & 0 deletions dockers/docker-bmp-watchdog/watchdog/debian/compat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11
9 changes: 9 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/debian/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Source: sonic
Maintainer: Feng Pan <[email protected]>
Section: net
Priority: optional
Standards-Version: 1.0.0

Package: sonic-bmp-watchdog
Architecture: any
Description: bmp watchdog for KubeSONiC project
1 change: 1 addition & 0 deletions dockers/docker-bmp-watchdog/watchdog/debian/install
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/release/bmp_watchdog /usr/bin
17 changes: 17 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#export DH_VERBOSE = 1

%:
dh $@

override_dh_auto_build:
cargo build --release --all

override_dh_auto_clean:
cargo clean --release

override_dh_auto_test:
# do nothing
:
88 changes: 88 additions & 0 deletions dockers/docker-bmp-watchdog/watchdog/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::io::{BufRead, BufReader, Write};
use std::net::TcpListener;
use std::process::Command;

use serde::Serialize;

#[derive(Serialize)]
struct HealthStatus {
check_bmp_supervisorctl: String,
check_bmp_db: String,
check_bmp_port: String,
}

fn check_bmp_supervisorctl() -> String {
// TODO: Replace with real health check
"OK".to_string()
}

fn check_bmp_db() -> String {
// TODO: Replace with real health check
"OK".to_string()
}

fn check_bmp_port() -> String {
// TODO: Replace with real health check
"OK".to_string()
}

fn main() {
// Start a HTTP server listening on port 50058
let listener = TcpListener::bind("127.0.0.1:50058")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

50058 is an ephemeral port ( /proc/sys/net/ipv4/ip_local_port_range).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just refer existing code

let listener = TcpListener::bind("127.0.0.1:50058")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maipbui
Could you please check this as well?
If we bind a TCP server to the port in the dynamic range that isn’t reserved in /proc/sys/net/ipv4/ip_local_reserved_ports, bind() may sometimes fail because another program might be using that port.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FengPan-Frank

I missed this PR: #17907, so using 50058 is also correct now.

.expect("Failed to bind to 127.0.0.1:50058");

println!("Watchdog HTTP server running on http://127.0.0.1:50058");

for stream_result in listener.incoming() {
match stream_result {
Ok(mut stream) => {
let mut reader = BufReader::new(&stream);
let mut request_line = String::new();

if let Ok(_) = reader.read_line(&mut request_line) {
println!("Received request: {}", request_line.trim_end());

if !request_line.starts_with("GET /") {
let response = "HTTP/1.1 405 Method Not Allowed\r\n\r\n";
stream.write_all(response.as_bytes()).ok();
continue;
}

let supervisorctl_result = check_bmp_supervisorctl();
let db_result = check_bmp_db();
let port_result = check_bmp_port();

let status = HealthStatus {
check_bmp_supervisorctl: supervisorctl_result.clone(),
check_bmp_db: db_result.clone(),
check_bmp_port: port_result.clone(),
};

let json_body = serde_json::to_string(&status).unwrap();
let all_passed = [supervisorctl_result, db_result, port_result]
.iter()
.all(|s| s.starts_with("OK"));

let status_line = if all_passed {
"HTTP/1.1 200 OK"
} else {
"HTTP/1.1 500 Internal Server Error"
};

let response = format!(
"{status_line}\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
json_body.len(),
json_body
);

if let Err(e) = stream.write_all(response.as_bytes()) {
eprintln!("Failed to write response: {}", e);
}
}
}
Err(e) => {
eprintln!("Error accepting connection: {}", e);
}
}
}
}
10 changes: 10 additions & 0 deletions rules/docker-bmp-watchdog.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
DPATH := $($(DOCKER_BMP_WATCHDOG)_PATH)
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/docker-bmp-watchdog.mk rules/docker-bmp-watchdog.dep
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
DEP_FILES += $(shell git ls-files $(DPATH))

$(DOCKER_BMP_WATCHDOG)_CACHE_MODE := GIT_CONTENT_SHA
$(DOCKER_BMP_WATCHDOG)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
$(DOCKER_BMP_WATCHDOG)_DEP_FILES := $(DEP_FILES)

$(eval $(call add_dbg_docker,$(DOCKER_BMP_WATCHDOG),$(DOCKER_BMP_WATCHDOG_DBG)))
28 changes: 28 additions & 0 deletions rules/docker-bmp-watchdog.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# docker image for bmp watchdog

DOCKER_BMP_WATCHDOG_STEM = docker-bmp-watchdog
DOCKER_BMP_WATCHDOG = $(DOCKER_BMP_WATCHDOG_STEM).gz
DOCKER_BMP_WATCHDOG_DBG = $(DOCKER_BMP_WATCHDOG_STEM)-$(DBG_IMAGE_MARK).gz

$(DOCKER_BMP_WATCHDOG)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BOOKWORM)

$(DOCKER_BMP_WATCHDOG)_PATH = $(DOCKERS_PATH)/$(DOCKER_BMP_WATCHDOG_STEM)

$(DOCKER_BMP_WATCHDOG)_VERSION = 1.0.0
$(DOCKER_BMP_WATCHDOG)_PACKAGE_NAME = bmp_watchdog

SONIC_DOCKER_IMAGES += $(DOCKER_BMP_WATCHDOG)
SONIC_BOOKWORM_DOCKERS += $(DOCKER_BMP_WATCHDOG)
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_BMP_WATCHDOG)

SONIC_DOCKER_DBG_IMAGES += $(DOCKER_BMP_WATCHDOG_DBG)
SONIC_BOOKWORM_DBG_DOCKERS += $(DOCKER_BMP_WATCHDOG_DBG)
SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_BMP_WATCHDOG_DBG)

$(DOCKER_BMP_WATCHDOG)_CONTAINER_NAME = bmp_watchdog
$(DOCKER_BMP_WATCHDOG)_RUN_OPT += -t --privileged --pid=host
$(DOCKER_BMP_WATCHDOG)_RUN_OPT += -v /lib/systemd/system:/lib/systemd/system:rw
$(DOCKER_BMP_WATCHDOG)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
$(DOCKER_BMP_WATCHDOG)_RUN_OPT += -v /etc/localtime:/etc/localtime:ro

$(DOCKER_BMP_WATCHDOG)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)
Loading