Skip to content

Commit cd19ce8

Browse files
authored
Merge pull request #55 from arortiz-rh/main
Addition of New Feature - Binary Support
2 parents 11ffdc8 + dc579d9 commit cd19ce8

6 files changed

Lines changed: 137 additions & 13 deletions

File tree

src/lib/greenboot.rs

Lines changed: 104 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use anyhow::{Result, bail};
22
use glob::glob;
33
use std::collections::HashSet;
44
use std::error::Error;
5+
use std::fs;
6+
use std::os::unix::fs::PermissionsExt;
57
use std::path::Path;
68
use std::process::Command;
79

@@ -104,35 +106,53 @@ fn run_scripts(name: &str, path: &str, disabled_scripts: Option<&[String]>) -> S
104106
skipped: Vec::new(),
105107
};
106108

107-
// Handle glob pattern error early
108-
let entries = match glob(&format!("{}*.sh", path)) {
109-
Ok(e) => e,
109+
let entries = match glob(&format!("{}*", path)) {
110+
Ok(e) => {
111+
let valid: Vec<_> = e
112+
.filter_map(Result::ok)
113+
.filter(|entry| {
114+
if let Ok(metadata) = fs::metadata(entry) {
115+
let mode = metadata.permissions().mode();
116+
metadata.is_file()
117+
&& (entry.extension().and_then(|ext| ext.to_str()) == Some("sh")
118+
|| (mode & 0o001 != 0 || mode & 0o010 != 0 || mode & 0o100 != 0))
119+
} else {
120+
false
121+
}
122+
})
123+
.collect();
124+
Some(valid).into_iter()
125+
}
110126
Err(e) => {
111127
result.errors.push(Box::new(e));
112128
return result;
113129
}
114130
};
115131

116132
for entry in entries.flatten() {
117-
// Process script name
118-
let script_name = match entry.file_name().and_then(|n| n.to_str()) {
133+
// Process script/binary name
134+
let file_name = match entry.file_name().and_then(|n| n.to_str()) {
119135
Some(name) => name,
120136
None => continue,
121137
};
122138

123-
// Check if script should be skipped
139+
// Check if script/binary should be skipped
124140
if let Some(disabled) = disabled_scripts {
125-
if disabled.contains(&script_name.to_string()) {
126-
log::info!("Skipping disabled script: {}", script_name);
127-
result.skipped.push(script_name.to_string());
141+
if disabled.contains(&file_name.to_string()) {
142+
log::info!("Skipping disabled script: {}", file_name);
143+
result.skipped.push(file_name.to_string());
128144
continue;
129145
}
130146
}
131147

132148
log::info!("running {} check {}", name, entry.to_string_lossy());
133149

134-
// Execute script and handle output
135-
let output = Command::new("bash").arg("-C").arg(&entry).output();
150+
// Sort between scripts and binaries since they require different commands to execute properly.
151+
let output = if entry.extension().and_then(|ext| ext.to_str()) == Some("sh") {
152+
Command::new("bash").arg("-C").arg(&entry).output()
153+
} else {
154+
Command::new(&entry).output()
155+
};
136156

137157
match output {
138158
Ok(o) if o.status.success() => {
@@ -213,6 +233,11 @@ mod test {
213233
setup_folder_structure(false)
214234
.context("Test setup failed")
215235
.unwrap();
236+
// Causes errors if these are not removed since they cause an excess amount
237+
// of failures.
238+
let required_path = format!("{}/check/required.d", GREENBOOT_INSTALL_PATHS[1]);
239+
let _ = std::fs::remove_file(format!("{}/01_failing_binary", required_path));
240+
let _ = std::fs::remove_file(format!("{}/02_failing_binary", required_path));
216241

217242
let base_path = GREENBOOT_INSTALL_PATHS[1];
218243

@@ -279,6 +304,12 @@ mod test {
279304
.context("Test setup failed")
280305
.unwrap();
281306

307+
// Removing extra failing binaries because this can cause a
308+
// failure if not added to the skips or removed as done below.
309+
let required_path = format!("{}/check/required.d", GREENBOOT_INSTALL_PATHS[1]);
310+
let _ = std::fs::remove_file(format!("{}/01_failing_binary", required_path));
311+
let _ = std::fs::remove_file(format!("{}/02_failing_binary", required_path));
312+
282313
// Skip the disabled script in required.d ,since there are two
283314
// failing- scripts passing them both so that this test passes.
284315
let state = run_diagnostics(vec![
@@ -293,11 +324,41 @@ mod test {
293324
tear_down().context("Test teardown failed").unwrap();
294325
}
295326

327+
// Since binaries are a separate and later added feature compared to
328+
// scripts, there should be a separate test to ensure they both work.
329+
#[test]
330+
fn test_skip_disabled_binary() {
331+
setup_folder_structure(false)
332+
.context("Test setup failed")
333+
.unwrap();
334+
335+
// Removing extra failing scripts because this can cause a
336+
// failure if not added to the skips or removed as done below
337+
let required_path = format!("{}/check/required.d", GREENBOOT_INSTALL_PATHS[1]);
338+
let _ = std::fs::remove_file(format!("{}/01_failing_script.sh", required_path));
339+
let _ = std::fs::remove_file(format!("{}/02_failing_script.sh", required_path));
340+
341+
// Skip the disabled script in required.d ,since there are two
342+
// failing- scripts passing them both so that this test passes.
343+
let state = run_diagnostics(vec![
344+
"01_failing_binary".to_string(),
345+
"02_failing_binary".to_string(),
346+
]);
347+
assert!(
348+
state.is_ok(),
349+
"Should pass when skipping disabled required binary"
350+
);
351+
352+
tear_down().context("Test teardown failed").unwrap();
353+
}
354+
296355
fn setup_folder_structure(passing: bool) -> Result<()> {
297356
let required_path = format!("{}/check/required.d", GREENBOOT_INSTALL_PATHS[1]);
298357
let wanted_path = format!("{}/check/wanted.d", GREENBOOT_INSTALL_PATHS[1]);
299358
let passing_test_scripts = "testing_assets/passing_script.sh";
300359
let failing_test_scripts = "testing_assets/failing_script.sh";
360+
let passing_test_binary = "testing_assets/passing_binary";
361+
let failing_test_binary = "testing_assets/failing_binary";
301362

302363
fs::create_dir_all(&required_path).expect("cannot create folder");
303364
fs::create_dir_all(&wanted_path).expect("cannot create folder");
@@ -315,13 +376,33 @@ mod test {
315376
)
316377
.context("unable to copy passing script to wanted.d")?;
317378

379+
// Create passing binary in both required and wanted
380+
fs::copy(
381+
passing_test_binary,
382+
format!("{}/passing_binary", &required_path),
383+
)
384+
.context("unable to copy passing binary to required.d")?;
385+
386+
fs::copy(
387+
passing_test_binary,
388+
format!("{}/passing_binary", &wanted_path),
389+
)
390+
.context("unable to copy passing binary to wanted.d")?;
391+
318392
// Create failing script in wanted.d
319393
fs::copy(
320394
failing_test_scripts,
321395
format!("{}/failing_script.sh", &wanted_path),
322396
)
323397
.context("unable to copy failing script to wanted.d")?;
324398

399+
// Create failing binary in wanted.d
400+
fs::copy(
401+
failing_test_binary,
402+
format!("{}/failing_binary", &wanted_path),
403+
)
404+
.context("unable to copy failing binary to wanted.d")?;
405+
325406
if !passing {
326407
// Create multiple failing script in required.d for failure cases
327408
fs::copy(
@@ -334,6 +415,18 @@ mod test {
334415
format!("{}/02_failing_script.sh", &required_path),
335416
)
336417
.context("unable to copy another failing script to required.d")?;
418+
419+
// Create multiple failing binaries in required.d for failure cases
420+
fs::copy(
421+
failing_test_scripts,
422+
format!("{}/01_failing_binary", &required_path),
423+
)
424+
.context("unable to copy failing binary to required.d")?;
425+
fs::copy(
426+
failing_test_scripts,
427+
format!("{}/02_failing_binary", &required_path),
428+
)
429+
.context("unable to copy another failing binary to required.d")?;
337430
}
338431
Ok(())
339432
}

testing_assets/failing_binary

12.1 KB
Binary file not shown.

testing_assets/passing_binary

12.1 KB
Binary file not shown.

tests/greenboot-bootc-anaconda-iso.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ fi
150150
greenprint "Building greenboot packages"
151151
pushd .. && \
152152
make rpm
153-
cp rpmbuild/RPMS/x86_64/*.rpm tests/ && popd
153+
cp rpmbuild/RPMS/x86_64/*.rpm tests/
154+
cp testing_assets/passing_binary tests/
155+
cp testing_assets/failing_binary tests/ && popd
154156

155157
###########################################################
156158
##
@@ -169,6 +171,8 @@ RUN dnf install -y \
169171
systemctl enable greenboot-healthcheck.service greenboot-rollback.service greenboot-success.target
170172
RUN sed -i "s/GREENBOOT_MAX_BOOT_ATTEMPTS=3/GREENBOOT_MAX_BOOT_ATTEMPTS=5/g" /etc/greenboot/greenboot.conf
171173
RUN sed -i 's#DISABLED_HEALTHCHECKS=()#DISABLED_HEALTHCHECKS=("01_repository_dns_check.sh" "not_exit.sh")#g' /etc/greenboot/greenboot.conf
174+
COPY passing_binary /etc/greenboot/check/required.d/
175+
COPY failing_binary /etc/greenboot/check/wanted.d/
172176
# Clean up by removing the local RPMs if desired
173177
RUN rm -f /tmp/greenboot-*.rpm
174178
EOF

tests/greenboot-bootc-qcow2.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ fi
150150
greenprint "Building greenboot packages"
151151
pushd .. && \
152152
make rpm
153-
cp rpmbuild/RPMS/x86_64/*.rpm tests/ && popd
153+
cp rpmbuild/RPMS/x86_64/*.rpm tests/
154+
cp testing_assets/passing_binary tests/
155+
cp testing_assets/failing_binary tests/ && popd
154156

155157
###########################################################
156158
##
@@ -169,6 +171,8 @@ RUN dnf install -y \
169171
systemctl enable greenboot-healthcheck.service greenboot-rollback.service greenboot-success.target
170172
RUN sed -i "s/GREENBOOT_MAX_BOOT_ATTEMPTS=3/GREENBOOT_MAX_BOOT_ATTEMPTS=5/g" /etc/greenboot/greenboot.conf
171173
RUN sed -i 's#DISABLED_HEALTHCHECKS=()#DISABLED_HEALTHCHECKS=("01_repository_dns_check.sh" "not_exit.sh")#g' /etc/greenboot/greenboot.conf
174+
COPY passing_binary /etc/greenboot/check/required.d/
175+
COPY failing_binary /etc/greenboot/check/wanted.d/
172176
# Clean up by removing the local RPMs if desired
173177
RUN rm -f /tmp/greenboot-*.rpm
174178
EOF

tests/greenboot-bootc.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,29 @@
164164
set_fact:
165165
failed_counter: "{{ failed_counter | int + 1 }}"
166166

167+
# case: check binary file support
168+
- name: check binary file support
169+
block:
170+
- name: binary file check result should be found here
171+
shell: journalctl -b -0 -u greenboot -u greenboot-healthcheck
172+
become: yes
173+
register: result_binary
174+
175+
- assert:
176+
that:
177+
- "'required script /etc/greenboot/check/required.d/passing_binary success!' in result_binary.stdout"
178+
- "'wanted script /etc/greenboot/check/wanted.d/failing_binary failed!' in result_binary.stdout"
179+
fail_msg: "Binary file check log not found"
180+
success_msg: "Found binary file check log"
181+
182+
always:
183+
- set_fact:
184+
total_counter: "{{ total_counter | int + 1 }}"
185+
rescue:
186+
- name: failed count + 1
187+
set_fact:
188+
failed_counter: "{{ failed_counter | int + 1 }}"
189+
167190
# case: check boot times
168191
- name: check boot times
169192
block:

0 commit comments

Comments
 (0)