summaryrefslogtreecommitdiff
path: root/cloudinit/transforms/cc_resizefs.py
diff options
context:
space:
mode:
authorJoshua Harlow <harlowja@yahoo-inc.com>2012-06-15 18:01:03 -0700
committerJoshua Harlow <harlowja@yahoo-inc.com>2012-06-15 18:01:03 -0700
commit508168acb95aee070d493b45656f781a42bdd262 (patch)
treee816b241c500d99f1289fb6afffb33abb560df99 /cloudinit/transforms/cc_resizefs.py
parent36c1da35c2c0cb1b2ee18b7374bc81df8349e3e2 (diff)
downloadvyos-cloud-init-508168acb95aee070d493b45656f781a42bdd262.tar.gz
vyos-cloud-init-508168acb95aee070d493b45656f781a42bdd262.zip
Complete initial cleanup for refactoring/rework.
Some of the cleanups were the following 1. Using standard (logged) utility functions for sub process work, writing, reading files, and other file system/operating system options 2. Having distrobutions impelement there own subclasses to handle system specifics (if applicable) 3. Having a cloud wrapper that provides just the functionality we want to expose (cloud.py) 4. Using a path class instead of globals for all cloud init paths (it is configured via config) 5. Removal of as much shared global state as possible (there should be none, minus a set of constants) 6. Other various cleanups that remove transforms/handlers/modules from reading/writing/chmoding there own files. a. They should be using util functions to take advantage of the logging that is now enabled in those util functions (very useful for debugging) 7. Urls being read and checked from a single module that serves this and only this purpose (+1 for code organization) 8. Updates to log whenever a transform decides not to run 9. Ensure whenever a exception is thrown (and possibly captured) that the util.logexc function is called a. For debugging, tracing this is important to not just drop them on the floor. 10. Code shuffling into utils.py where it makes sense (and where it could serve a benefit for other code now or in the future)
Diffstat (limited to 'cloudinit/transforms/cc_resizefs.py')
-rw-r--r--cloudinit/transforms/cc_resizefs.py142
1 files changed, 84 insertions, 58 deletions
diff --git a/cloudinit/transforms/cc_resizefs.py b/cloudinit/transforms/cc_resizefs.py
index 2dc66def..daaf4da9 100644
--- a/cloudinit/transforms/cc_resizefs.py
+++ b/cloudinit/transforms/cc_resizefs.py
@@ -18,91 +18,117 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import cloudinit.util as util
-import subprocess
+import errno
import os
import stat
import sys
-import time
import tempfile
-from cloudinit.CloudConfig import per_always
-
-frequency = per_always
+import time
+from cloudinit import util
+from cloudinit.settings import PER_ALWAYS
-def handle(_name, cfg, _cloud, log, args):
- if len(args) != 0:
- resize_root = False
- if str(args[0]).lower() in ['true', '1', 'on', 'yes']:
- resize_root = True
- else:
- resize_root = util.get_cfg_option_str(cfg, "resize_rootfs", True)
+frequency = PER_ALWAYS
- if str(resize_root).lower() in ['false', '0']:
- return
+resize_fs_prefixes_cmds = [
+ ('ext', 'resize2fs'),
+ ('xfs', 'xfs_growfs'),
+]
- # we use mktemp rather than mkstemp because early in boot nothing
- # else should be able to race us for this, and we need to mknod.
- devpth = tempfile.mktemp(prefix="cloudinit.resizefs.", dir="/run")
+def nodeify_path(devpth, where, log):
try:
- st_dev = os.stat("/").st_dev
+ st_dev = os.stat(where).st_dev
dev = os.makedev(os.major(st_dev), os.minor(st_dev))
os.mknod(devpth, 0400 | stat.S_IFBLK, dev)
+ return st_dev
except:
if util.is_container():
- log.debug("inside container, ignoring mknod failure in resizefs")
+ log.debug("Inside container, ignoring mknod failure in resizefs")
return
- log.warn("Failed to make device node to resize /")
+ log.warn("Failed to make device node to resize %s at %s", where, devpth)
raise
- cmd = ['blkid', '-c', '/dev/null', '-sTYPE', '-ovalue', devpth]
+
+def get_fs_type(st_dev, path, log):
try:
- (fstype, _err) = util.subp(cmd)
- except subprocess.CalledProcessError as e:
- log.warn("Failed to get filesystem type of maj=%s, min=%s via: %s" %
- (os.major(st_dev), os.minor(st_dev), cmd))
- log.warn("output=%s\nerror=%s\n", e.output[0], e.output[1])
- os.unlink(devpth)
+ fs_type = util.find_devs_with(tag='TYPE', oformat='value',
+ no_cache=True, path=path)
+ return fs_type
+ except util.ProcessExecutionError:
+ util.logexc(log, ("Failed to get filesystem type"
+ " of maj=%s, min=%s for path %s"),
+ os.major(st_dev), os.minor(st_dev), path)
raise
- if str(fstype).startswith("ext"):
- resize_cmd = ['resize2fs', devpth]
- elif fstype == "xfs":
- resize_cmd = ['xfs_growfs', devpth]
+
+def handle(name, cfg, _cloud, log, args):
+ if len(args) != 0:
+ resize_root = args[0]
else:
- os.unlink(devpth)
- log.debug("not resizing unknown filesystem %s" % fstype)
+ resize_root = util.get_cfg_option_str(cfg, "resize_rootfs", True)
+
+ if not util.translate_bool(resize_root):
+ log.debug("Skipping module named %s, resizing disabled", name)
return
- if resize_root == "noblock":
- fid = os.fork()
- if fid == 0:
- try:
- do_resize(resize_cmd, devpth, log)
- os._exit(0) # pylint: disable=W0212
- except Exception as exc:
- sys.stderr.write("Failed: %s" % exc)
- os._exit(1) # pylint: disable=W0212
- else:
- do_resize(resize_cmd, devpth, log)
+ # TODO is the directory ok to be used??
+ resize_root_d = util.get_cfg_option_str(cfg, "resize_rootfs_tmp", "/run")
+ util.ensure_dir(resize_root_d)
+ with util.SilentTemporaryFile(prefix="cloudinit.resizefs.",
+ dir=resize_root_d, delete=True) as tfh:
+ devpth = tfh.name
+
+ # Delete the file so that mknod will work
+ # but don't change the file handle to know that its
+ # removed so that when a later call that recreates
+ # occurs this temporary file will still benefit from
+ # auto deletion
+ tfh.unlink_now()
+
+ # TODO: allow what is to be resized to
+ # be configurable??
+ st_dev = nodeify_path(devpth, "/", log)
+ fs_type = get_fs_type(st_dev, devpath, log)
+
+ resizer = None
+ fstype_lc = fstype.lower()
+ for (pfix, root_cmd) in resize_fs_prefixes_cmds:
+ if fstype_lc.startswith(pfix):
+ resizer = root_cmd
+ break
- log.debug("resizing root filesystem (type=%s, maj=%i, min=%i, val=%s)" %
- (str(fstype).rstrip("\n"), os.major(st_dev), os.minor(st_dev),
- resize_root))
+ if not resizer:
+ log.warn("Not resizing unknown filesystem type %s", fs_type)
+ return
+
+ log.debug("Resizing using %s", resizer)
+ resize_cmd = [resizer, devpth]
- return
+ if resize_root == "noblock":
+ # Fork to a child that will run
+ # the resize command
+ util.fork_cb(do_resize, resize_cmd, log)
+ # Don't delete the file now in the parent
+ tfh.delete = False
+ else:
+ do_resize(resize_cmd, log)
+ action = 'Resized'
+ if resize_root == "noblock":
+ action = 'Resizing (via forking)'
+ log.debug("%s root filesystem (type=%s, maj=%i, min=%i, val=%s)",
+ action, fs_type, os.major(st_dev), os.minor(st_dev), resize_root)
-def do_resize(resize_cmd, devpth, log):
+
+def do_resize(resize_cmd, log):
+ start = time.time()
try:
- start = time.time()
util.subp(resize_cmd)
- except subprocess.CalledProcessError as e:
- log.warn("Failed to resize filesystem (%s)" % resize_cmd)
- log.warn("output=%s\nerror=%s\n", e.output[0], e.output[1])
- os.unlink(devpth)
+ except util.ProcessExecutionError as e:
+ util.logexc(log, "Failed to resize filesystem (using %s)", resize_cmd)
raise
-
- os.unlink(devpth)
- log.debug("resize took %s seconds" % (time.time() - start))
+ tot_time = int(time.time() - start)
+ log.debug("Resizing took %s seconds", tot_time)
+ # TODO: Should we add a fsck check after this to make
+ # sure we didn't corrupt anything?