cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #04271
[Merge] ~d-info-e/cloud-init:resizefs-on-zfs-root into cloud-init:master
do3meli has proposed merging ~d-info-e/cloud-init:resizefs-on-zfs-root into cloud-init:master.
Commit message:
resizefs module now able to handle zfs/zpool.
Previously there was no support at all for zfs file system. With this change it is now possible to use the resizefs module to extend a root zfs partition that lies on a zpool.
LP: #1721243
Requested reviews:
cloud-init commiters (cloud-init-dev)
For more details, see:
https://code.launchpad.net/~d-info-e/cloud-init/+git/cloud-init/+merge/340220
this change adds the possibility to use resizefs module to extend a zfs file system on a corresponding zpool.
--
Your team cloud-init commiters is requested to review the proposed merge of ~d-info-e/cloud-init:resizefs-on-zfs-root into cloud-init:master.
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
index cec22bb..1244215 100644
--- a/cloudinit/config/cc_resizefs.py
+++ b/cloudinit/config/cc_resizefs.py
@@ -84,6 +84,10 @@ def _resize_ufs(mount_point, devpth):
return ('growfs', devpth)
+def _resize_zfs(mount_point, devpth):
+ return ('zpool', 'online', '-e', mount_point, devpth)
+
+
def _get_dumpfs_output(mount_point):
dumpfs_res, err = util.subp(['dumpfs', '-m', mount_point])
return dumpfs_res
@@ -148,6 +152,7 @@ RESIZE_FS_PREFIXES_CMDS = [
('ext', _resize_ext),
('xfs', _resize_xfs),
('ufs', _resize_ufs),
+ ('zfs', _resize_zfs),
]
RESIZE_FS_PRECHECK_CMDS = {
@@ -188,6 +193,13 @@ def maybe_get_writable_device_path(devpath, info, log):
log.debug("Not attempting to resize devpath '%s': %s", devpath, info)
return None
+ # FreeBSD zpool can also just use gpt/<label>
+ # with that in mind we can not do an os.stat on "gpt/whatever"
+ # therefore return the devpath already here.
+ if util.is_FreeBSD() and devpath.startswith('gpt/'):
+ log.debug('We have FreeBSD and gpt labels - just go ahead')
+ return devpath
+
try:
statret = os.stat(devpath)
except OSError as exc:
@@ -231,6 +243,13 @@ def handle(name, cfg, _cloud, log, args):
(devpth, fs_type, mount_point) = result
+ # this is a bit confusing but easy to understand:
+ # for "zpool online" cmd we need the zpool name and
+ # not the mount_point. util.get_mount_info_fs_on_zpool
+ # will get us this. so we just replace resize what here.
+ if fs_type == 'zfs':
+ resize_what = mount_point
+
info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what)
log.debug("resize_info: %s" % info)
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 02dc2ce..b4a1585 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -2174,7 +2174,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):
(result, err) = subp(['mount', '-p', path], rcs=[0, 1])
if len(err):
# find a path if the input is not a mounting point
@@ -2188,23 +2188,42 @@ def get_mount_info_freebsd(path, log=LOG):
return "/dev/" + label_part, ret[2], ret[1]
+def get_mount_info_fs_on_zpool(zpool, log=LOG):
+ (zpoolstatus, err) = subp(['zpool', 'status', zpool])
+ if len(err):
+ return None
+ r = r'.*(ONLINE).*'
+ for line in zpoolstatus.split("\n"):
+ if re.search(r, line) and zpool not in line and "state" not in line:
+ disk = line.split()[0]
+ log.debug('found zpool "%s" on disk %s', zpool, disk)
+ # onlinging a zpool on first disk results in resize to max
+ return disk, 'zfs', zpool
+
+
def parse_mount(path):
- (mountoutput, _err) = subp("mount")
+ (mountoutput, _err) = subp(['mount'])
mount_locs = mountoutput.splitlines()
+ regex = r'^(/dev/[\S]+|.*zroot.*\S*?) on (/.*) \((.+), .+, (.+)\)$'
for line in mount_locs:
- m = re.search(r'^(/dev/[\S]+) on (/.*) \((.+), .+, (.+)\)$', line)
+ m = re.search(regex, line)
if not m:
continue
+ devpth = m.group(1)
+ mount_point = m.group(2)
+ fs_type = m.group(3)
# 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))
- if (not devm and is_FreeBSD()):
+ devm = re.search('^(/dev/.+)p([0-9])$', devpth)
+ # if we have a zfs FS we need to get the device name
+ # from the corresponding zpool.
+ if fs_type == 'zfs':
+ zpool = devpth.split('/')[0]
+ return get_mount_info_fs_on_zpool(zpool)
+ elif not devm and is_FreeBSD():
return get_mount_info_freebsd(path)
- devpth = m.group(1)
- mount_point = m.group(2)
- fs_type = m.group(3)
- if mount_point == path:
+ elif mount_point == path:
return devpth, fs_type, mount_point
return None