consolidate tasks.py cleanup for temporary files into a single place

see: #6199
This commit is contained in:
Ryan Petrello
2017-07-19 14:23:20 -04:00
parent 1848c25370
commit 198f2e31a4
2 changed files with 37 additions and 35 deletions

View File

@@ -6,6 +6,7 @@ import codecs
from collections import OrderedDict from collections import OrderedDict
import ConfigParser import ConfigParser
import cStringIO import cStringIO
import functools
import imp import imp
import json import json
import logging import logging
@@ -382,10 +383,29 @@ def delete_inventory(inventory_id):
return return
def with_path_cleanup(f):
@functools.wraps(f)
def _wrapped(self, *args, **kwargs):
try:
return f(self, *args, **kwargs)
finally:
for p in self.cleanup_paths:
try:
if os.path.isdir(p):
shutil.rmtree(p, ignore_errors=True)
elif os.path.exists(p):
os.remove(p)
except OSError:
logger.exception("Failed to remove tmp file: {}".format(p))
self.cleanup_paths = []
return _wrapped
class BaseTask(Task): class BaseTask(Task):
name = None name = None
model = None model = None
abstract = True abstract = True
cleanup_paths = []
def update_model(self, pk, _attempt=0, **updates): def update_model(self, pk, _attempt=0, **updates):
"""Reload the model instance from the database and update the """Reload the model instance from the database and update the
@@ -454,6 +474,7 @@ class BaseTask(Task):
''' '''
path = tempfile.mkdtemp(prefix='ansible_tower_%s_' % instance.pk, dir=settings.AWX_PROOT_BASE_PATH) path = tempfile.mkdtemp(prefix='ansible_tower_%s_' % instance.pk, dir=settings.AWX_PROOT_BASE_PATH)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
self.cleanup_paths.append(path)
return path return path
def build_private_data_files(self, instance, **kwargs): def build_private_data_files(self, instance, **kwargs):
@@ -666,6 +687,7 @@ class BaseTask(Task):
Hook for any steps to run after job/task is marked as complete. Hook for any steps to run after job/task is marked as complete.
''' '''
@with_path_cleanup
def run(self, pk, isolated_host=None, **kwargs): def run(self, pk, isolated_host=None, **kwargs):
''' '''
Run the job/task and capture its output. Run the job/task and capture its output.
@@ -730,6 +752,7 @@ class BaseTask(Task):
if not check_proot_installed(): if not check_proot_installed():
raise RuntimeError('bubblewrap is not installed') raise RuntimeError('bubblewrap is not installed')
kwargs['proot_temp_dir'] = build_proot_temp_dir() kwargs['proot_temp_dir'] = build_proot_temp_dir()
self.cleanup_paths.append(kwargs['proot_temp_dir'])
args = wrap_args_with_proot(args, cwd, **kwargs) args = wrap_args_with_proot(args, cwd, **kwargs)
safe_args = wrap_args_with_proot(safe_args, cwd, **kwargs) safe_args = wrap_args_with_proot(safe_args, cwd, **kwargs)
# If there is an SSH key path defined, wrap args with ssh-agent. # If there is an SSH key path defined, wrap args with ssh-agent.
@@ -779,16 +802,6 @@ class BaseTask(Task):
if settings.DEBUG: if settings.DEBUG:
logger.exception('exception occurred while running task') logger.exception('exception occurred while running task')
finally: finally:
if kwargs.get('private_data_dir', ''):
try:
shutil.rmtree(kwargs['private_data_dir'], True)
except OSError:
pass
if kwargs.get('proot_temp_dir', ''):
try:
shutil.rmtree(kwargs['proot_temp_dir'], True)
except OSError:
pass
try: try:
stdout_handle.flush() stdout_handle.flush()
stdout_handle.close() stdout_handle.close()
@@ -1215,6 +1228,7 @@ class RunProjectUpdate(BaseTask):
} }
''' '''
handle, self.revision_path = tempfile.mkstemp(dir=settings.AWX_PROOT_BASE_PATH) handle, self.revision_path = tempfile.mkstemp(dir=settings.AWX_PROOT_BASE_PATH)
self.cleanup_paths.append(self.revision_path)
private_data = {'credentials': {}} private_data = {'credentials': {}}
if project_update.credential: if project_update.credential:
credential = project_update.credential credential = project_update.credential
@@ -1498,13 +1512,6 @@ class RunProjectUpdate(BaseTask):
if status == 'successful' and instance.launch_type != 'sync': if status == 'successful' and instance.launch_type != 'sync':
self._update_dependent_inventories(instance, dependent_inventory_sources) self._update_dependent_inventories(instance, dependent_inventory_sources)
def final_run_hook(self, instance, status, **kwargs):
super(RunProjectUpdate, self).final_run_hook(instance, status, **kwargs)
try:
os.remove(self.revision_path)
except Exception, e:
logger.error("Failed removing revision tmp file: {}".format(e))
class RunInventoryUpdate(BaseTask): class RunInventoryUpdate(BaseTask):
@@ -1841,7 +1848,7 @@ class RunInventoryUpdate(BaseTask):
elif src == 'scm': elif src == 'scm':
args.append(inventory_update.get_actual_source_path()) args.append(inventory_update.get_actual_source_path())
elif src == 'custom': elif src == 'custom':
runpath = tempfile.mkdtemp(prefix='ansible_tower_launch_', dir=settings.AWX_PROOT_BASE_PATH) runpath = tempfile.mkdtemp(prefix='ansible_tower_inventory_', dir=settings.AWX_PROOT_BASE_PATH)
handle, path = tempfile.mkstemp(dir=runpath) handle, path = tempfile.mkstemp(dir=runpath)
f = os.fdopen(handle, 'w') f = os.fdopen(handle, 'w')
if inventory_update.source_script is None: if inventory_update.source_script is None:
@@ -1851,7 +1858,7 @@ class RunInventoryUpdate(BaseTask):
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
args.append(path) args.append(path)
args.append("--custom") args.append("--custom")
self.custom_dir_path.append(runpath) self.cleanup_paths.append(runpath)
args.append('-v%d' % inventory_update.verbosity) args.append('-v%d' % inventory_update.verbosity)
if settings.DEBUG: if settings.DEBUG:
args.append('--traceback') args.append('--traceback')
@@ -1873,8 +1880,6 @@ class RunInventoryUpdate(BaseTask):
return getattr(settings, 'INVENTORY_UPDATE_IDLE_TIMEOUT', None) return getattr(settings, 'INVENTORY_UPDATE_IDLE_TIMEOUT', None)
def pre_run_hook(self, inventory_update, **kwargs): def pre_run_hook(self, inventory_update, **kwargs):
self.custom_dir_path = []
source_project = None source_project = None
if inventory_update.inventory_source: if inventory_update.inventory_source:
source_project = inventory_update.inventory_source.source_project source_project = inventory_update.inventory_source.source_project
@@ -1906,14 +1911,6 @@ class RunInventoryUpdate(BaseTask):
('project_update', local_project_sync.name, local_project_sync.id))) ('project_update', local_project_sync.name, local_project_sync.id)))
raise raise
def final_run_hook(self, instance, status, **kwargs):
if self.custom_dir_path:
for p in self.custom_dir_path:
try:
shutil.rmtree(p, True)
except OSError:
pass
class RunAdHocCommand(BaseTask): class RunAdHocCommand(BaseTask):
''' '''
@@ -2106,12 +2103,6 @@ class RunAdHocCommand(BaseTask):
''' '''
return getattr(settings, 'AWX_PROOT_ENABLED', False) return getattr(settings, 'AWX_PROOT_ENABLED', False)
def final_run_hook(self, ad_hoc_command, status, **kwargs):
'''
Hook for actions to run after ad hoc command is marked as completed.
'''
super(RunAdHocCommand, self).final_run_hook(ad_hoc_command, status, **kwargs)
class RunSystemJob(BaseTask): class RunSystemJob(BaseTask):

View File

@@ -262,6 +262,17 @@ class TestGenericRun(TestJobExecution):
]: ]:
assert c in self.task.update_model.call_args_list assert c in self.task.update_model.call_args_list
def test_artifact_cleanup(self):
path = tempfile.NamedTemporaryFile(delete=False).name
try:
self.task.cleanup_paths.append(path)
assert os.path.exists(path)
self.task.run(self.pk)
assert not os.path.exists(path)
finally:
if os.path.exists(path):
os.remove(path)
def test_uses_bubblewrap(self): def test_uses_bubblewrap(self):
self.task.run(self.pk) self.task.run(self.pk)