Skip to content

Commit

Permalink
lts support check
Browse files Browse the repository at this point in the history
  • Loading branch information
maksimryndin committed Jul 21, 2024
1 parent e4501e1 commit 0212b8e
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 25 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
* 0.1.9
* reorder system logs fields for charts
* ssh versions checks
* ssh versions checks (for ubuntu)
* system support check (for ubuntu)

* 0.1.8
* fix ssh logs parsing
Expand Down
93 changes: 70 additions & 23 deletions src/services/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ enum SystemInfoRequest {
SshNeedUpdate(String, oneshot::Sender<Result<bool, String>>),
#[cfg(target_os = "linux")]
OSName(oneshot::Sender<Option<String>>),
#[cfg(target_os = "linux")]
IsSupported(oneshot::Sender<Result<bool, String>>),
}

pub(crate) struct SystemService {
Expand Down Expand Up @@ -100,24 +102,6 @@ impl SystemService {

while let Some(request) = request_rx.blocking_recv() {
match request {
SystemInfoRequest::Telemetry(scrape_time) => {
let result = collector::collect(
&mut sys,
&mounts,
&names,
scrape_time.naive_utc(),
&messenger,
)
.map(Data::Many)
.map_err(|e| Data::Message(format!("sysinfo scraping error {e}")));
if sender.blocking_send(TaskResult { id: 0, result }).is_err() {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("exiting system info scraping thread");
return;
}
panic!("assert: sysinfo messages queue shouldn't be closed before shutdown signal");
}
}
#[cfg(target_os = "linux")]
SystemInfoRequest::SshNeedUpdate(changelog, reply_to) => {
let response = ssh::check_is_ssh_needs_update(&changelog);
Expand All @@ -144,6 +128,37 @@ impl SystemService {
);
}
}
#[cfg(target_os = "linux")]
SystemInfoRequest::IsSupported(reply_to) => {
let response = ssh::is_system_still_supported();
if reply_to.send(response).is_err() {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("exiting system info scraping thread");
return;
}
panic!(
"assert: system support check recepient shouldn't be closed before shutdown signal"
);
}
}
SystemInfoRequest::Telemetry(scrape_time) => {
let result = collector::collect(
&mut sys,
&mounts,
&names,
scrape_time.naive_utc(),
&messenger,
)
.map(Data::Many)
.map_err(|e| Data::Message(format!("sysinfo scraping error {e}")));
if sender.blocking_send(TaskResult { id: 0, result }).is_err() {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("exiting system info scraping thread");
return;
}
panic!("assert: sysinfo messages queue shouldn't be closed before shutdown signal");
}
}
}
}
}
Expand Down Expand Up @@ -178,14 +193,14 @@ impl SystemService {
}

#[cfg(target_os = "linux")]
async fn ssh_version_checker(
async fn system_checker(
is_shutdown: Arc<AtomicBool>,
send_notification: Sender,
mut sys_req_tx: mpsc::Sender<SystemInfoRequest>,
) {
let mut interval = tokio::time::interval(Duration::from_secs(4 * 60 * 60)); // 4 hours
let request_timeout = Duration::from_secs(5);
tracing::info!("starting ssh version checking");
tracing::info!("starting system updates checking");
loop {
tokio::select! {
_ = interval.tick() => {
Expand All @@ -201,7 +216,7 @@ impl SystemService {
let (tx, rx) = oneshot::channel();
if let Err(e) = Self::make_system_request(&mut sys_req_tx, request_timeout, SystemInfoRequest::SshNeedUpdate(source, tx)).await {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("finished ssh version checking");
tracing::info!("finished system updates checking");
return;
}
let msg = format!("error making ssh version check request `{}`", e);
Expand All @@ -223,14 +238,46 @@ impl SystemService {
}
Err(e) => {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("finished ssh version checking");
tracing::info!("finished system updates checking");
return;
}
let msg = format!("error fetching ssh version update `{e}`");
tracing::error!("{}", msg);
send_notification.fatal(msg).await;
}
};
let (tx, rx) = oneshot::channel();
if let Err(e) = Self::make_system_request(&mut sys_req_tx, request_timeout, SystemInfoRequest::IsSupported(tx)).await {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("finished system updates checking");
return;
}
let msg = format!("error making system support check request `{}`", e);
tracing::error!("{}", msg);
send_notification.fatal(msg).await;
}
match rx.await {
Ok(Ok(false)) => {
let msg = "the system seems to be [no longer supported](https://wiki.ubuntu.com/Releases)".to_string();
tracing::warn!("{}", msg);
send_notification.warn(msg).await;
},
Ok(Ok(true)) => continue,

Ok(Err(message)) => {
let msg = format!("error fetching system support check `{message}`");
tracing::error!("{}", msg);
}
Err(e) => {
if is_shutdown.load(Ordering::Relaxed) {
tracing::info!("finished system updates checking");
return;
}
let msg = format!("error fetching system updates `{e}`");
tracing::error!("{}", msg);
send_notification.fatal(msg).await;
}
};
}
}
}
Expand Down Expand Up @@ -504,7 +551,7 @@ impl Service for SystemService {
Self::fetch_os_name(&is_shutdown, &mut sys_req_tx, &send_notification).await;
if let Some(true) = os_name.map(|name| name.to_lowercase().contains("ubuntu")) {
tasks.push(tokio::spawn(async move {
Self::ssh_version_checker(is_shutdown, send_notification, sys_req_tx).await;
Self::system_checker(is_shutdown, send_notification, sys_req_tx).await;
}));
}
}
Expand Down
74 changes: 73 additions & 1 deletion src/services/system/ssh.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::google::datavalue::{Datarow, Datavalue};
use crate::notifications::{Notification, Sender};
use crate::services::{Data, TaskResult};
use chrono::{NaiveDateTime, Utc};
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use lazy_static::lazy_static;
use logwatcher::{LogWatcher, LogWatcherAction, LogWatcherEvent};
use regex::{Regex, RegexBuilder};
Expand Down Expand Up @@ -316,6 +316,63 @@ pub(super) fn check_is_ssh_needs_update(changelog: &str) -> Result<bool, String>
Ok(latest_patch != patch)
}

const MONTHS: [&str; 12] = [
"january",
"february",
"march",
"april",
"may",
"june",
"july",
"august",
"september",
"october",
"november",
"december",
];

fn parse_lts_end(command_output: &str) -> Option<DateTime<Utc>> {
lazy_static! {
static ref RE: Regex = RegexBuilder::new(r#"(january|february|march|april|may|june|july|august|september|october|november|december)\s(\d{4})"#)
.case_insensitive(true)
.build()
.expect("assert: ssh version command regex is properly constructed");
}
let (month, year) = RE.captures(command_output).map(|capture| {
let (_, [month, year]) = capture.extract();
(month, year)
})?;
let month = month.to_lowercase();
let month: u32 = MONTHS
.into_iter()
.position(|m| m == month)?
.try_into()
.ok()?;
let next_month = (month + 2) % 12;
let mut year: i32 = year.parse().ok()?;
if next_month == 1 {
year += 1;
}
// should not fail
// https://docs.rs/chrono/latest/chrono/offset/type.MappedLocalTime.html#method.unwrap
Some(Utc.with_ymd_and_hms(year, next_month, 1, 0, 0, 0).unwrap())
}

pub(super) fn is_system_still_supported() -> Result<bool, String> {
let output = match Command::new("hwe-support-status").arg("--verbose").output() {
Ok(output) if output.status.success() => {
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
Ok(output) => Err(String::from_utf8_lossy(&output.stderr).to_string()),
Err(e) => Err(format!(
"failed to execute ssh version command with error {e}"
)),
}?;
let supported_till = parse_lts_end(&output)
.ok_or_else(|| format!("failed to parse hwe-support-status output {output}"))?;
Ok(Utc::now() < supported_till)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -564,4 +621,19 @@ mod tests {
parse_ssh_version_and_patch(output)
);
}

#[test]
fn parse_lts_support() {
let output = "You are not running a system with a Hardware Enablement Stack. Your system is supported until April 2027.";
assert_eq!(
Utc.with_ymd_and_hms(2027, 5, 1, 0, 0, 0).unwrap(),
parse_lts_end(output).unwrap()
);

let output = "You are not running a system with a Hardware Enablement Stack. Your system is supported until December 2027.";
assert_eq!(
Utc.with_ymd_and_hms(2028, 1, 1, 0, 0, 0).unwrap(),
parse_lts_end(output).unwrap()
);
}
}

0 comments on commit 0212b8e

Please sign in to comment.