From e32617f099c5693c11c3da38f0439867787567e6 Mon Sep 17 00:00:00 2001 From: shixuantong Date: Tue, 26 Mar 2024 19:48:22 +0800 Subject: [PATCH] fix growpart race and handle error when log file is empty (cherry picked from commit 90d9563f44326cd28dad89c33e72c350115d1109) --- backport-fix-growpart-race-4618.patch | 113 ++++++++++++++++++ ...le-error-when-log-file-is-empty-4859.patch | 75 ++++++++++++ cloud-init.spec | 11 +- 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 backport-fix-growpart-race-4618.patch create mode 100644 backport-handle-error-when-log-file-is-empty-4859.patch diff --git a/backport-fix-growpart-race-4618.patch b/backport-fix-growpart-race-4618.patch new file mode 100644 index 0000000..af75300 --- /dev/null +++ b/backport-fix-growpart-race-4618.patch @@ -0,0 +1,113 @@ +From 598e0560d64f949369962ebbce2c53207763f5d2 Mon Sep 17 00:00:00 2001 +From: Brett Holman +Date: Fri, 5 Jan 2024 13:10:01 -0700 +Subject: [PATCH] fix: fix growpart race (#4618) + +Fixes GH-4613 + +Reference:https://github.com/canonical/cloud-init/commit/598e0560d64f949369962ebbce2c53207763f5d2 +Conflict:(1)change tests/unittests/test_handler/test_handler_growpart.py not tests/unittests/config/test_cc_growpart.py. +(2)Community patch: +-from typing import Tuple ++from typing import Optional, Tuple +Adaptation patch: ++from typing import Optional +(3)add "import pytest" in test_handler_growpart.py +(4)The context of the code is slightly different. +--- + cloudinit/config/cc_growpart.py | 22 +++++++++++++++---- + .../test_handler/test_handler_growpart.py | 17 ++++++++++++++ + 2 files changed, 35 insertions(+), 4 deletions(-) + +diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py +index 1ddc9dc..1552072 100644 +--- a/cloudinit/config/cc_growpart.py ++++ b/cloudinit/config/cc_growpart.py +@@ -74,6 +74,7 @@ from cloudinit.settings import PER_ALWAYS + from cloudinit import subp + from cloudinit import temp_utils + from cloudinit import util ++from typing import Optional + + frequency = PER_ALWAYS + +@@ -212,12 +213,16 @@ class ResizeGpart(object): + return (before, get_size(partdev)) + + +-def get_size(filename): +- fd = os.open(filename, os.O_RDONLY) ++def get_size(filename) -> Optional[int]: ++ fd = None + try: ++ fd = os.open(filename, os.O_RDONLY) + return os.lseek(fd, 0, os.SEEK_END) ++ except FileNotFoundError: ++ return None + finally: +- os.close(fd) ++ if fd: ++ os.close(fd) + + + def device_part_info(devpath): +@@ -318,10 +323,19 @@ def resize_devices(resizer, devices): + continue + + try: +- (old, new) = resizer.resize(disk, ptnum, blockdev) ++ old, new = resizer.resize(disk, ptnum, blockdev) + if old == new: + info.append((devent, RESIZE.NOCHANGE, + "no change necessary (%s, %s)" % (disk, ptnum),)) ++ elif new is None or old is None: ++ info.append( ++ ( ++ devent, ++ RESIZE.CHANGED, ++ "changed (%s, %s) size, new size is unknown" ++ % (disk, ptnum), ++ ) ++ ) + else: + info.append((devent, RESIZE.CHANGED, + "changed (%s, %s) from %s to %s" % +diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py +index 7f039b7..2f40e86 100644 +--- a/tests/unittests/test_handler/test_handler_growpart.py ++++ b/tests/unittests/test_handler/test_handler_growpart.py +@@ -6,6 +6,7 @@ from cloudinit import subp + + from cloudinit.tests.helpers import TestCase + ++import pytest + import errno + import logging + import os +@@ -227,6 +228,22 @@ class TestResize(unittest.TestCase): + os.stat = real_stat + + ++class TestGetSize: ++ @pytest.mark.parametrize( ++ "file_exists, expected", ++ ( ++ (False, None), ++ (True, 1), ++ ), ++ ) ++ def test_get_size_behaves(self, file_exists, expected, tmp_path): ++ """Ensure that get_size() doesn't raise exception""" ++ tmp_file = tmp_path / "tmp.txt" ++ if file_exists: ++ tmp_file.write_bytes(b"0") ++ assert expected == cc_growpart.get_size(tmp_file) ++ ++ + def simple_device_part_info(devpath): + # simple stupid return (/dev/vda, 1) for /dev/vda + ret = re.search("([^0-9]*)([0-9]*)$", devpath) +-- +2.33.0 + + diff --git a/backport-handle-error-when-log-file-is-empty-4859.patch b/backport-handle-error-when-log-file-is-empty-4859.patch new file mode 100644 index 0000000..8d5ff43 --- /dev/null +++ b/backport-handle-error-when-log-file-is-empty-4859.patch @@ -0,0 +1,75 @@ +From ee79940717e354d26954fc4401dc5b0c38980509 Mon Sep 17 00:00:00 2001 +From: Hasan +Date: Tue, 13 Feb 2024 19:34:11 +0400 +Subject: [PATCH] feat: handle error when log file is empty (#4859) + +Fixes GH-4686 + +Reference:https://github.com/canonical/cloud-init/commit/ee79940717e354d26954fc4401dc5b0c38980509 +Conflict:(1)not change tools/.github-cla-signers +(2)Community patch: ++from cloudinit.analyze import analyze_show +Adaptation patch: ++from cloudinit.analyze.__main__ import analyze_show +--- + cloudinit/analyze/show.py | 4 ++++ + tests/unittests/analyze/test_show.py | 24 ++++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + create mode 100644 tests/unittests/analyze/test_show.py + +diff --git a/cloudinit/analyze/show.py b/cloudinit/analyze/show.py +index 01a4d3e..3cf91e1 100644 +--- a/cloudinit/analyze/show.py ++++ b/cloudinit/analyze/show.py +@@ -8,6 +8,7 @@ import base64 + import datetime + import json + import os ++import sys + import time + import sys + +@@ -381,6 +382,9 @@ def load_events_infile(infile): + :return: json version of logfile, raw file + ''' + data = infile.read() ++ if not data.strip(): ++ sys.stderr.write("Empty file %s\n" % infile.name) ++ sys.exit(1) + try: + return json.loads(data), data + except ValueError: +diff --git a/tests/unittests/analyze/test_show.py b/tests/unittests/analyze/test_show.py +new file mode 100644 +index 0000000..0984e90 +--- /dev/null ++++ b/tests/unittests/analyze/test_show.py +@@ -0,0 +1,24 @@ ++from collections import namedtuple ++ ++import pytest ++ ++from cloudinit.analyze.__main__ import analyze_show ++ ++ ++@pytest.fixture ++def mock_io(tmp_path): ++ """Mock args for configure_io function""" ++ infile = tmp_path / "infile" ++ outfile = tmp_path / "outfile" ++ return namedtuple("MockIO", ["infile", "outfile"])(infile, outfile) ++ ++ ++class TestAnalyzeShow: ++ """Test analyze_show (and/or helpers) in cloudinit/analyze/__init__.py""" ++ ++ def test_empty_logfile(self, mock_io, capsys): ++ """Test analyze_show with an empty logfile""" ++ mock_io.infile.write_text("") ++ with pytest.raises(SystemExit): ++ analyze_show("dontcare", mock_io) ++ assert capsys.readouterr().err == f"Empty file {mock_io.infile}\n" +-- +2.33.0 + + diff --git a/cloud-init.spec b/cloud-init.spec index 57e9437..c94e5e3 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -1,6 +1,6 @@ Name: cloud-init Version: 21.4 -Release: 24 +Release: 25 Summary: the defacto multi-distribution package that handles early initialization of a cloud instance. License: ASL 2.0 or GPLv3 URL: http://launchpad.net/cloud-init @@ -72,6 +72,8 @@ Patch6037: backport-cloud-config-honor-cloud_dir-setting-1523.patch Patch6038: backport-collect-logs-fix-memory-usage-SC-1590-4289.patch Patch6039: backport-Return-a-namedtuple-from-subp-1376.patch Patch6040: backport-fix-Don-t-loosen-the-permissions-of-the-log-file.patch +Patch6041: backport-fix-growpart-race-4618.patch +Patch6042: backport-handle-error-when-log-file-is-empty-4859.patch BuildRequires: pkgconfig(systemd) python3-devel python3-setuptools systemd BuildRequires: iproute python3-configobj python3-httpretty >= 0.8.14-2 @@ -182,6 +184,13 @@ fi %exclude /usr/share/doc/* %changelog +* Tue Mar 26 2024 shixuantong - 21.4-25 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:fix growpart race + handle error when log file is empty + * Thu Dec 14 2023 shixuantong - 21.4-24 - Type:bugfix - CVE:NA -- Gitee