Reference:fa53c7f4089c7502a8012e17a0d6269f0efc474ebb414c78669cbd94dd576d817e94be0450a1faff
178 lines
6.5 KiB
Diff
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
|
|
|