diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py index f774baa..725b76f 100644 --- a/cloudinit/config/cc_resizefs.py +++ b/cloudinit/config/cc_resizefs.py @@ -73,6 +73,8 @@ def _resize_xfs(mount_point, devpth): def _resize_ufs(mount_point, devpth): return ('growfs', devpth) +def _resize_zfs(zpool, devpth): + return ('zpool', 'online', '-e', zpool, devpth) def _get_dumpfs_output(mount_point): dumpfs_res, err = util.subp(['dumpfs', '-m', mount_point]) @@ -138,6 +140,7 @@ RESIZE_FS_PREFIXES_CMDS = [ ('ext', _resize_ext), ('xfs', _resize_xfs), ('ufs', _resize_ufs), + ('zfs', _resize_zfs), ] RESIZE_FS_PRECHECK_CMDS = { @@ -242,7 +245,11 @@ def handle(name, cfg, _cloud, log, args): info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what) log.debug("resize_info: %s" % info) - if not is_device_path_writable_block(devpth, info, log): + fstype_lc = fs_type.lower() + if fstype_lc == 'zfs': + log.debug('We do not detect if the device path is writable for ZFS file systems') + + elif not is_device_path_writable_block(devpth, info, log): return resizer = None @@ -251,7 +258,6 @@ def handle(name, cfg, _cloud, log, args): fs_type, resize_what) return - fstype_lc = fs_type.lower() for (pfix, root_cmd) in RESIZE_FS_PREFIXES_CMDS: if fstype_lc.startswith(pfix): resizer = root_cmd @@ -262,7 +268,11 @@ def handle(name, cfg, _cloud, log, args): fs_type, resize_what) return - resize_cmd = resizer(resize_what, devpth) + if fstype_lc == 'zfs': + resize_cmd = resizer(mount_point, devpth) + else: + resize_cmd = resizer(resize_what, devpth) + log.debug("Resizing %s (%s) using %s", resize_what, fs_type, ' '.join(resize_cmd)) diff --git a/cloudinit/util.py b/cloudinit/util.py index e1290aa..4fdb4c3 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -2111,7 +2111,7 @@ def get_path_dev_freebsd(path, mnt_list): return path_found -def get_mount_info_freebsd(path, log=LOG): +def get_mount_info_freebsd(path, fstype, log=LOG): (result, err) = subp(['mount', '-p', path], rcs=[0, 1]) if len(err): # find a path if the input is not a mounting point @@ -2122,6 +2122,16 @@ def get_mount_info_freebsd(path, log=LOG): result = path_found ret = result.split() label_part = find_freebsd_part(ret[0]) + if fstype == 'zfs': + zpool = label_part.split('/')[0] + (zpoolconfig, err) = subp(['zpool', 'status', zpool]) + if len(err) > 0: + return None + for line in zpoolconfig.split("\n"): + if "ONLINE" in line and not zpool in line and not "state" in line: + disk = line.split()[0] + # it is enough to take 1th disk for onlining + return disk, fstype, zpool return "/dev/" + label_part, ret[2], ret[1] @@ -2129,18 +2139,18 @@ def parse_mount(path): (mountoutput, _err) = subp("mount") mount_locs = mountoutput.splitlines() for line in mount_locs: - m = re.search(r'^(/dev/[\S]+) on (/.*) \((.+), .+, (.+)\)$', line) + m = re.search(r'^(/dev/[\S]+|.*zroot.*\S*?) on (/.*) \((.+), .+, (.+)\)$', line) if not m: continue + fs_type = m.group(3) + devpth = m.group(1) # check whether the dev refers to a label on FreeBSD # for example, if dev is '/dev/label/rootfs', we should # continue finding the real device like '/dev/da0'. - devm = re.search('^(/dev/.+)p([0-9])$', m.group(1)) + devm = re.search('^(/dev/.+)p([0-9])$', devpth) if (not devm and is_FreeBSD()): - return get_mount_info_freebsd(path) - devpth = m.group(1) + return get_mount_info_freebsd(path, fs_type) mount_point = m.group(2) - fs_type = m.group(3) if mount_point == path: return devpth, fs_type, mount_point return None