summaryrefslogtreecommitdiff
path: root/cloudinit/temp_utils.py
diff options
context:
space:
mode:
authorScott Moser <smoser@brickies.net>2017-08-29 09:59:20 -0400
committerScott Moser <smoser@brickies.net>2017-09-07 15:22:54 -0400
commit409918f9ba83e45e9bc5cc0b6c589e2fc8ae9b60 (patch)
tree9ed541b0118d6cb5a2b276e9a0473d8cd9ad2c18 /cloudinit/temp_utils.py
parentdcbb901cc3e9e888bc8f87e87bdc0ca8436a2baa (diff)
downloadcloud-init-git-409918f9ba83e45e9bc5cc0b6c589e2fc8ae9b60.tar.gz
Use /run/cloud-init for tempfile operations.
During boot, the usage of /tmp is not safe. In systemd systems, systemd-tmpfiles-clean may run at any point and clear out a temp file while cloud-init is using it. The solution here is to use /run/cloud-init/tmp. LP: #1707222
Diffstat (limited to 'cloudinit/temp_utils.py')
-rw-r--r--cloudinit/temp_utils.py93
1 files changed, 93 insertions, 0 deletions
diff --git a/cloudinit/temp_utils.py b/cloudinit/temp_utils.py
new file mode 100644
index 00000000..0355f19d
--- /dev/null
+++ b/cloudinit/temp_utils.py
@@ -0,0 +1,93 @@
+# This file is part of cloud-init. See LICENSE file for license information.
+
+import contextlib
+import errno
+import os
+import shutil
+import tempfile
+
+_TMPDIR = None
+_ROOT_TMPDIR = "/run/cloud-init/tmp"
+
+
+def _tempfile_dir_arg(odir=None):
+ """Return the proper 'dir' argument for tempfile functions.
+
+ When root, cloud-init will use /run/cloud-init/tmp to avoid
+ any cleaning that a distro boot might do on /tmp (such as
+ systemd-tmpfiles-clean).
+
+ If the caller of this function (mkdtemp or mkstemp) was provided
+ with a 'dir' argument, then that is respected.
+
+ @param odir: original 'dir' arg to 'mkdtemp' or other."""
+
+ if odir is not None:
+ return odir
+
+ global _TMPDIR
+ if _TMPDIR:
+ return _TMPDIR
+
+ if os.getuid() == 0:
+ tdir = _ROOT_TMPDIR
+ else:
+ tdir = os.environ.get('TMPDIR', '/tmp')
+ if not os.path.isdir(tdir):
+ os.makedirs(tdir)
+ os.chmod(tdir, 0o1777)
+
+ _TMPDIR = tdir
+ return tdir
+
+
+def ExtendedTemporaryFile(**kwargs):
+ kwargs['dir'] = _tempfile_dir_arg(kwargs.pop('dir', None))
+ fh = tempfile.NamedTemporaryFile(**kwargs)
+ # Replace its unlink with a quiet version
+ # that does not raise errors when the
+ # file to unlink has been unlinked elsewhere..
+
+ def _unlink_if_exists(path):
+ try:
+ os.unlink(path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise e
+
+ fh.unlink = _unlink_if_exists
+
+ # Add a new method that will unlink
+ # right 'now' but still lets the exit
+ # method attempt to remove it (which will
+ # not throw due to our del file being quiet
+ # about files that are not there)
+ def unlink_now():
+ fh.unlink(fh.name)
+
+ setattr(fh, 'unlink_now', unlink_now)
+ return fh
+
+
+@contextlib.contextmanager
+def tempdir(**kwargs):
+ # This seems like it was only added in python 3.2
+ # Make it since its useful...
+ # See: http://bugs.python.org/file12970/tempdir.patch
+ tdir = mkdtemp(**kwargs)
+ try:
+ yield tdir
+ finally:
+ shutil.rmtree(tdir)
+
+
+def mkdtemp(**kwargs):
+ kwargs['dir'] = _tempfile_dir_arg(kwargs.pop('dir', None))
+ return tempfile.mkdtemp(**kwargs)
+
+
+def mkstemp(**kwargs):
+ kwargs['dir'] = _tempfile_dir_arg(kwargs.pop('dir', None))
+ return tempfile.mkstemp(**kwargs)
+
+# vi: ts=4 expandtab