Skip to content
Open
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
10 changes: 3 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,13 @@ fn check_previous_rollback() -> Result<bool> {
.context("Failed to execute journalctl command to check rollback status")?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
log::warn!(
"journalctl command failed with status: {}. Error: {}",
output.status,
stderr.trim()
log::info!(
"No previous boot journal available (expected on first boot or systems with non-persistent journal). Skipping rollback check."
Comment on lines -180 to +181

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change assumes that journalctl fails because there is no previous journal, without verifying that the command's stderr starts with "No journal boot entry found for the specified boot". It should instead return Ok(false) for that specific case, and Err(...) for any other failure.

);
return Ok(false);
}

let journal_output =
String::from_utf8(output.stdout).context("Failed to parse journalctl output as UTF-8")?;
let journal_output = String::from_utf8_lossy(&output.stdout);

if journal_output.trim().is_empty() {
log::debug!("No rollback service logs found in previous boot");
Expand Down
1 change: 1 addition & 0 deletions tests/greenboot-bootc-anaconda-iso.sh
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ fi
tee -a Containerfile >> /dev/null << EOF
RUN (dnf install -y 'dnf5-command(copr)' || dnf install -y 'dnf-command(copr)') && \
dnf copr enable -y packit/fedora-iot-greenboot-rs-${PR_NUMBER} ${COPR_CHROOT} && \
dnf clean metadata && \
dnf install -y greenboot greenboot-default-health-checks && \
systemctl enable greenboot-healthcheck.service
RUN sed -i "s/GREENBOOT_MAX_BOOT_ATTEMPTS=3/GREENBOOT_MAX_BOOT_ATTEMPTS=5/g" /etc/greenboot/greenboot.conf
Expand Down
1 change: 1 addition & 0 deletions tests/greenboot-bootc-qcow2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ fi
tee -a Containerfile >> /dev/null << EOF
RUN (dnf install -y 'dnf5-command(copr)' || dnf install -y 'dnf-command(copr)') && \
dnf copr enable -y packit/fedora-iot-greenboot-rs-${PR_NUMBER} ${COPR_CHROOT} && \
dnf clean metadata && \
dnf install -y greenboot greenboot-default-health-checks && \
systemctl enable greenboot-healthcheck.service
RUN sed -i "s/GREENBOOT_MAX_BOOT_ATTEMPTS=3/GREENBOOT_MAX_BOOT_ATTEMPTS=5/g" /etc/greenboot/greenboot.conf
Expand Down
51 changes: 51 additions & 0 deletions tests/greenboot-bootc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

# case: check rollback detection still works on non-first boot
- name: check rollback detection works correctly on non-first boot
block:
- name: get greenboot-healthcheck log from current boot (post-rollback)
command: journalctl -b -0 -u greenboot-healthcheck.service --no-pager
become: yes
register: result_healthcheck_post_rollback

- assert:
that:
- "'FALLBACK BOOT DETECTED!' in result_healthcheck_post_rollback.stdout"
fail_msg: "Rollback detection failed on non-first boot"
success_msg: "Rollback correctly detected on non-first boot"

always:
- set_fact:
total_counter: "{{ total_counter | int + 1 }}"
rescue:
- name: failed count + 1
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

# case: check greenboot-set-rollback-trigger log at first boot
- name: check greenboot-set-rollback-trigger at first boot
block:
Expand All @@ -142,6 +164,35 @@
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

# case: check proper first boot handling
- name: check greenboot-healthcheck handles first boot correctly
block:
- name: get earliest boot ID
shell: journalctl --list-boots --no-pager | awk '$2 ~ /^[0-9a-f]{32}$/{print $2; exit}'
become: yes
register: first_boot_id
Comment thread
sarmahaj marked this conversation as resolved.
failed_when: first_boot_id.stdout | length == 0
Comment on lines +170 to +174

@mmartinv mmartinv Jul 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
- name: get earliest boot ID
shell: journalctl --list-boots --no-pager | awk '$2 ~ /^[0-9a-f]{32}$/{print $2; exit}'
become: yes
register: first_boot_id
failed_when: first_boot_id.stdout | length == 0

Not needed, see below


- name: get greenboot-healthcheck log from first boot
command: "journalctl -b {{ first_boot_id.stdout }} -u greenboot-healthcheck.service --no-pager"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
command: "journalctl -b {{ first_boot_id.stdout }} -u greenboot-healthcheck.service --no-pager"
command: "journalctl -b 1 -u greenboot-healthcheck.service --no-pager"

From man journalctl:

Thus, 1 means the first boot found in the journal in chronological order

become: yes
register: result_healthcheck_first_boot

- assert:
that:
- "'No previous boot journal available' in result_healthcheck_first_boot.stdout"
- "'FALLBACK BOOT DETECTED!' not in result_healthcheck_first_boot.stdout"
fail_msg: "Expected first boot message not found or false rollback detection on first boot"
success_msg: "First boot correctly detected with appropriate message and no false rollback detection"
Comment on lines +181 to +186

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would separate this into two different asserts


always:
- set_fact:
total_counter: "{{ total_counter | int + 1 }}"
rescue:
- name: failed count + 1
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

# case: check greenboot-set-rollback-trigger log at boot after upgrade
- name: check greenboot-set-rollback-trigger at boot after upgrade
block:
Expand Down
52 changes: 52 additions & 0 deletions tests/greenboot-ostree.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

# case: check proper first boot handling
- name: check greenboot-healthcheck handles first boot correctly
block:
- name: get earliest boot ID
shell: journalctl --list-boots --no-pager | awk '$2 ~ /^[0-9a-f]{32}$/{print $2; exit}'
become: yes
register: first_boot_id

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Consider adding failed_when: first_boot_id.stdout | length == 0.

failed_when: first_boot_id.stdout | length == 0
Comment on lines +77 to +81

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not needed, see above


- name: get greenboot-healthcheck log from first boot
command: "journalctl -b {{ first_boot_id.stdout }} -u greenboot-healthcheck.service --no-pager"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
command: "journalctl -b {{ first_boot_id.stdout }} -u greenboot-healthcheck.service --no-pager"
command: "journalctl -b 1 -u greenboot-healthcheck.service --no-pager"

become: yes
register: result_healthcheck_first_boot

- assert:
that:
- "'No previous boot journal available' in result_healthcheck_first_boot.stdout"
- "'FALLBACK BOOT DETECTED!' not in result_healthcheck_first_boot.stdout"
fail_msg: "Expected first boot message not found or false rollback detection on first boot"
success_msg: "First boot correctly detected with appropriate message and no false rollback detection"
Comment on lines +88 to +93

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as above


always:
- set_fact:
total_counter: "{{ total_counter | int + 1 }}"
rescue:
- name: failed count + 1
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"

- name: check /boot mount status
shell: findmnt -r -o OPTIONS -n /boot | awk -F "," '{print $1}'
register: result_boot_mount_before
Expand Down Expand Up @@ -212,6 +241,29 @@
failed_counter: "{{ failed_counter | int + 1 }}"
when: result_rollback is defined and result_rollback is succeeded

# case: check rollback detection still works on non-first boot
- name: check rollback detection works correctly on non-first boot
block:
- name: get greenboot-healthcheck log from current boot (post-rollback)
command: journalctl -b -0 -u greenboot-healthcheck.service --no-pager
become: yes
register: result_healthcheck_post_rollback

- assert:
that:
- "'FALLBACK BOOT DETECTED!' in result_healthcheck_post_rollback.stdout"
fail_msg: "Rollback detection failed on non-first boot"
success_msg: "Rollback correctly detected on non-first boot"

always:
- set_fact:
total_counter: "{{ total_counter | int + 1 }}"
rescue:
- name: failed count + 1
set_fact:
failed_counter: "{{ failed_counter | int + 1 }}"
when: result_rollback is defined and result_rollback is succeeded

# case: check boot-complete.target status
- name: boot-complete.target should be active
block:
Expand Down
Loading