cloud-init/backport-Resource-leak-cleanup-1556.patch

178 lines
6.5 KiB
Diff

From fadb6489cfbc14c67ebcd9b34a032ad574a3d529 Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
Date: Wed, 13 Jul 2022 13:05:46 -0600
Subject: [PATCH 4/8] Resource leak cleanup (#1556)
Reference:https://github.com/canonical/cloud-init/commit/9cbd94dd57112083856ead0e0ff724e9d1c1f714
Conflict:test file.
Add tox target for tracing for resource leaks, fix some leaks
---
cloudinit/analyze/__main__.py | 13 +++++++++++++
cloudinit/analyze/tests/test_boot.py | 24 +++++++++++++-----------
cloudinit/analyze/tests/test_dump.py | 4 ++--
cloudinit/cmd/cloud_id.py | 3 ++-
tests/unittests/test_util.py | 3 ++-
tox.ini | 9 +++++++++
6 files changed, 41 insertions(+), 15 deletions(-)
diff --git a/cloudinit/analyze/__main__.py b/cloudinit/analyze/__main__.py
index 99e5c20..4ec609c 100644
--- a/cloudinit/analyze/__main__.py
+++ b/cloudinit/analyze/__main__.py
@@ -8,6 +8,7 @@ import sys
from cloudinit.util import json_dumps
from datetime import datetime
+from typing import IO
from . import dump
from . import show
@@ -136,6 +137,7 @@ def analyze_boot(name, args):
}
outfh.write(status_map[status_code].format(**kwargs))
+ clean_io(infh, outfh)
return status_code
@@ -161,6 +163,7 @@ def analyze_blame(name, args):
outfh.write('\n'.join(srecs) + '\n')
outfh.write('\n')
outfh.write('%d boot records analyzed\n' % (idx + 1))
+ clean_io(infh, outfh)
def analyze_show(name, args):
@@ -193,12 +196,14 @@ def analyze_show(name, args):
'character.\n\n')
outfh.write('\n'.join(record) + '\n')
outfh.write('%d boot records analyzed\n' % (idx + 1))
+ clean_io(infh, outfh)
def analyze_dump(name, args):
"""Dump cloud-init events in json format"""
(infh, outfh) = configure_io(args)
outfh.write(json_dumps(_get_events(infh)) + '\n')
+ clean_io(infh, outfh)
def _get_events(infile):
@@ -232,6 +237,14 @@ def configure_io(args):
return (infh, outfh)
+def clean_io(*file_handles: IO) -> None:
+ """close filehandles"""
+ for file_handle in file_handles:
+ if file_handle in (sys.stdin, sys.stdout):
+ continue
+ file_handle.close()
+
+
if __name__ == '__main__':
parser = get_parser()
args = parser.parse_args()
diff --git a/cloudinit/analyze/tests/test_boot.py b/cloudinit/analyze/tests/test_boot.py
index f69423c..6676676 100644
--- a/cloudinit/analyze/tests/test_boot.py
+++ b/cloudinit/analyze/tests/test_boot.py
@@ -117,17 +117,19 @@ class TestAnalyzeBoot(CiTestCase):
analyze_boot(name_default, args)
# now args have been tested, go into outfile and make sure error
# message is in the outfile
- outfh = open(args.outfile, 'r')
- data = outfh.read()
- err_string = 'Your Linux distro or container does not support this ' \
- 'functionality.\nYou must be running a Kernel ' \
- 'Telemetry supported distro.\nPlease check ' \
- 'https://cloudinit.readthedocs.io/en/latest/topics' \
- '/analyze.html for more information on supported ' \
- 'distros.\n'
-
- self.remove_dummy_file(path, log_path)
- self.assertEqual(err_string, data)
+ with open(args.outfile, "r") as outfh:
+ data = outfh.read()
+ err_string = (
+ "Your Linux distro or container does not support this "
+ "functionality.\nYou must be running a Kernel "
+ "Telemetry supported distro.\nPlease check "
+ "https://cloudinit.readthedocs.io/en/latest/topics"
+ "/analyze.html for more information on supported "
+ "distros.\n"
+ )
+
+ self.remove_dummy_file(path, log_path)
+ self.assertEqual(err_string, data)
@mock.patch("cloudinit.util.is_container", return_value=True)
@mock.patch('cloudinit.subp.subp', return_value=('U=1000000', None))
diff --git a/cloudinit/analyze/tests/test_dump.py b/cloudinit/analyze/tests/test_dump.py
index dac1efb..27db1b1 100644
--- a/cloudinit/analyze/tests/test_dump.py
+++ b/cloudinit/analyze/tests/test_dump.py
@@ -184,8 +184,8 @@ class TestDumpEvents(CiTestCase):
tmpfile = self.tmp_path('logfile')
write_file(tmpfile, SAMPLE_LOGS)
m_parse_from_date.return_value = 1472594005.972
-
- events, data = dump_events(cisource=open(tmpfile))
+ with open(tmpfile) as file:
+ events, data = dump_events(cisource=file)
year = datetime.now().year
dt1 = datetime.strptime(
'Nov 03 06:51:06.074410 %d' % year, '%b %d %H:%M:%S.%f %Y')
diff --git a/cloudinit/cmd/cloud_id.py b/cloudinit/cmd/cloud_id.py
index 9760892..985f9a2 100755
--- a/cloudinit/cmd/cloud_id.py
+++ b/cloudinit/cmd/cloud_id.py
@@ -53,7 +53,8 @@ def handle_args(name, args):
@return: 0 on success, 1 otherwise.
"""
try:
- instance_data = json.load(open(args.instance_data))
+ with open(args.instance_data) as file:
+ instance_data = json.load(file)
except IOError:
return error(
"File not found '%s'. Provide a path to instance data json file"
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 0b01337..1185487 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -560,7 +560,8 @@ class TestMultiLog(helpers.FilesystemMockingTestCase):
self._createConsole(self.root)
logged_string = 'something very important'
util.multi_log(logged_string)
- self.assertEqual(logged_string, open('/dev/console').read())
+ with open("/dev/console") as f:
+ self.assertEqual(logged_string, f.read())
def test_logs_dont_go_to_stdout_if_console_exists(self):
self._createConsole(self.root)
diff --git a/tox.ini b/tox.ini
index 874d3f2..5360067 100644
--- a/tox.ini
+++ b/tox.ini
@@ -60,6 +60,15 @@ commands =
{envpython} -m sphinx {posargs:doc/rtd doc/rtd_html}
doc8 doc/rtd
+#commands = {envpython} -X tracemalloc=40 -Werror::ResourceWarning:cloudinit -m pytest \
+[testenv:py3-leak]
+deps = {[testenv:py3]deps}
+commands = {envpython} -X tracemalloc=40 -Wall -m pytest \
+ --durations 10 \
+ {posargs:--cov=cloudinit --cov-branch \
+ tests/unittests}
+
+
[xenial-shared-deps]
# The version of pytest in xenial doesn't work with Python 3.8, so we define
# two xenial environments: [testenv:xenial] runs the tests with exactly the
--
2.40.0