
The reason for this is that more and more things I was wanting to be able to see how long they took. This puts that time logic into a single place. It also supports (by default) reading from /proc/uptime as the timing mechanism. While that is almost certainly slower than time.time(), it does give millisecond granularity and is not affected by 'ntpdate' having run in between the two events.
144 lines
4.6 KiB
Python
144 lines
4.6 KiB
Python
# vi: ts=4 expandtab
|
|
#
|
|
# Copyright (C) 2011 Canonical Ltd.
|
|
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# Author: Scott Moser <scott.moser@canonical.com>
|
|
# Author: Juerg Haefliger <juerg.haefliger@hp.com>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 3, as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# 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 errno
|
|
import os
|
|
import stat
|
|
|
|
from cloudinit.settings import PER_ALWAYS
|
|
from cloudinit import util
|
|
|
|
frequency = PER_ALWAYS
|
|
|
|
|
|
def _resize_btrfs(mount_point, devpth): # pylint: disable=W0613
|
|
return ('btrfs', 'filesystem', 'resize', 'max', mount_point)
|
|
|
|
|
|
def _resize_ext(mount_point, devpth): # pylint: disable=W0613
|
|
return ('resize2fs', devpth)
|
|
|
|
|
|
def _resize_xfs(mount_point, devpth): # pylint: disable=W0613
|
|
return ('xfs_growfs', devpth)
|
|
|
|
# Do not use a dictionary as these commands should be able to be used
|
|
# for multiple filesystem types if possible, e.g. one command for
|
|
# ext2, ext3 and ext4.
|
|
RESIZE_FS_PREFIXES_CMDS = [
|
|
('btrfs', _resize_btrfs),
|
|
('ext', _resize_ext),
|
|
('xfs', _resize_xfs),
|
|
]
|
|
|
|
NOBLOCK = "noblock"
|
|
|
|
|
|
def handle(name, cfg, _cloud, log, args):
|
|
if len(args) != 0:
|
|
resize_root = args[0]
|
|
else:
|
|
resize_root = util.get_cfg_option_str(cfg, "resize_rootfs", True)
|
|
|
|
if not util.translate_bool(resize_root, addons=[NOBLOCK]):
|
|
log.debug("Skipping module named %s, resizing disabled", name)
|
|
return
|
|
|
|
# TODO(harlowja) 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)
|
|
|
|
# TODO(harlowja): allow what is to be resized to be configurable??
|
|
resize_what = "/"
|
|
result = util.get_mount_info(resize_what, log)
|
|
if not result:
|
|
log.warn("Could not determine filesystem type of %s", resize_what)
|
|
return
|
|
|
|
(devpth, fs_type, mount_point) = result
|
|
|
|
# Ensure the path is a block device.
|
|
info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what)
|
|
log.debug("resize_info: %s" % info)
|
|
|
|
try:
|
|
statret = os.stat(devpth)
|
|
except OSError as exc:
|
|
if util.is_container() and exc.errno == errno.ENOENT:
|
|
log.debug("Device '%s' did not exist in container. "
|
|
"cannot resize: %s" % (devpth, info))
|
|
elif exc.errno == errno.ENOENT:
|
|
log.warn("Device '%s' did not exist. cannot resize: %s" %
|
|
(devpth, info))
|
|
else:
|
|
raise exc
|
|
return
|
|
|
|
if not stat.S_ISBLK(statret.st_mode):
|
|
if util.is_container():
|
|
log.debug("device '%s' not a block device in container."
|
|
" cannot resize: %s" % (devpth, info))
|
|
else:
|
|
log.warn("device '%s' not a block device. cannot resize: %s" %
|
|
(devpth, info))
|
|
return
|
|
|
|
resizer = None
|
|
fstype_lc = fs_type.lower()
|
|
for (pfix, root_cmd) in RESIZE_FS_PREFIXES_CMDS:
|
|
if fstype_lc.startswith(pfix):
|
|
resizer = root_cmd
|
|
break
|
|
|
|
if not resizer:
|
|
log.warn("Not resizing unknown filesystem type %s for %s",
|
|
fs_type, resize_what)
|
|
return
|
|
|
|
resize_cmd = resizer(resize_what, devpth)
|
|
log.debug("Resizing %s (%s) using %s", resize_what, fs_type,
|
|
' '.join(resize_cmd))
|
|
|
|
if resize_root == NOBLOCK:
|
|
# Fork to a child that will run
|
|
# the resize command
|
|
util.fork_cb(
|
|
util.log_time(logfunc=log.debug, msg="backgrounded Resizing",
|
|
func=do_resize, args=(resize_cmd, log)))
|
|
else:
|
|
util.log_time(logfunc=log.debug, msg="Resizing",
|
|
func=do_resize, args=(resize_cmd, log))
|
|
|
|
action = 'Resized'
|
|
if resize_root == NOBLOCK:
|
|
action = 'Resizing (via forking)'
|
|
log.debug("%s root filesystem (type=%s, val=%s)", action, fs_type,
|
|
resize_root)
|
|
|
|
|
|
def do_resize(resize_cmd, log):
|
|
try:
|
|
util.subp(resize_cmd)
|
|
except util.ProcessExecutionError:
|
|
util.logexc(log, "Failed to resize filesystem (cmd=%s)", resize_cmd)
|
|
raise
|
|
# TODO(harlowja): Should we add a fsck check after this to make
|
|
# sure we didn't corrupt anything?
|