828e370fe1
Approved by: whu (maintainer, implicitly) MFH: 2021Q3 Sponsored by: The FreeBSD Foundation
356 lines
16 KiB
Python
356 lines
16 KiB
Python
--- azurelinuxagent/daemon/resourcedisk/freebsd.py.orig 2021-06-24 22:08:50 UTC
|
|
+++ azurelinuxagent/daemon/resourcedisk/freebsd.py
|
|
@@ -1,6 +1,7 @@
|
|
# Microsoft Azure Linux Agent
|
|
#
|
|
# Copyright 2018 Microsoft Corporation
|
|
+# Copyright 2020-2021 The FreeBSD Foundation
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
@@ -24,6 +25,8 @@ import azurelinuxagent.common.conf as conf
|
|
from azurelinuxagent.common.exception import ResourceDiskError
|
|
from azurelinuxagent.daemon.resourcedisk.default import ResourceDiskHandler
|
|
|
|
+# Keeping 1GB sapce if configured swap size is larger than the disk size
|
|
+MINIMAL_RESOURCE_PARTITION_SIZE = 1024 ** 3
|
|
|
|
class FreeBSDResourceDiskHandler(ResourceDiskHandler):
|
|
"""
|
|
@@ -32,37 +35,45 @@ class FreeBSDResourceDiskHandler(ResourceDiskHandler):
|
|
The resource disk locates at following slot:
|
|
scbus2 on blkvsc1 bus 0:
|
|
<Msft Virtual Disk 1.0> at scbus2 target 1 lun 0 (da1,pass2)
|
|
-
|
|
- There are 2 variations based on partition table type:
|
|
- 1. MBR: The resource disk partition is /dev/da1s1
|
|
- 2. GPT: The resource disk partition is /dev/da1p2, /dev/da1p1 is for reserved usage.
|
|
"""
|
|
|
|
def __init__(self): # pylint: disable=W0235
|
|
super(FreeBSDResourceDiskHandler, self).__init__()
|
|
|
|
@staticmethod
|
|
- def parse_gpart_list(data):
|
|
+ def parse_gpart_show(data):
|
|
dic = {}
|
|
for line in data.split('\n'):
|
|
- if line.find("Geom name: ") != -1:
|
|
- geom_name = line[11:]
|
|
- elif line.find("scheme: ") != -1:
|
|
- dic[geom_name] = line[8:]
|
|
+ if line:
|
|
+ l = line.split()
|
|
+ dic[l[3]] = l[4]
|
|
return dic
|
|
|
|
+ @staticmethod
|
|
+ def parse_mount_list(data):
|
|
+ dic = {}
|
|
+ for line in data.split('\n'):
|
|
+ if line:
|
|
+ l = line.split()
|
|
+ dic[l[2]] = l[0]
|
|
+ return dic
|
|
+
|
|
+ @staticmethod
|
|
+ def get_next_partition(x):
|
|
+ return x[:-1] + str(int(x[-1]) + 1)
|
|
+
|
|
def mount_resource_disk(self, mount_point):
|
|
fs = self.fs
|
|
if fs != 'ufs':
|
|
- raise ResourceDiskError(
|
|
- "Unsupported filesystem type:{0}, only ufs is supported.".format(fs))
|
|
+ raise ResourceDiskError("Unsupported filesystem type: "
|
|
+ "{0}, only ufs is supported.".format(fs))
|
|
|
|
# 1. Detect device
|
|
- err, output = shellutil.run_get_output('gpart list')
|
|
+ err, output = shellutil.run_get_output("gpart show | grep '=>'")
|
|
if err:
|
|
raise ResourceDiskError(
|
|
"Unable to detect resource disk device:{0}".format(output))
|
|
- disks = self.parse_gpart_list(output)
|
|
+ disks = self.parse_gpart_show(output)
|
|
|
|
device = self.osutil.device_for_ide_port(1)
|
|
if device is None or device not in disks:
|
|
@@ -74,8 +85,12 @@ class FreeBSDResourceDiskHandler(ResourceDiskHandler):
|
|
err, output = shellutil.run_get_output(
|
|
'camcontrol periphlist 3:1:0')
|
|
if err:
|
|
- raise ResourceDiskError(
|
|
- "Unable to detect resource disk device:{0}".format(output))
|
|
+ # try again on "0:0:1"
|
|
+ err, output = shellutil.run_get_output(
|
|
+ 'camcontrol periphlist 0:0:1')
|
|
+ if err:
|
|
+ raise ResourceDiskError(
|
|
+ "Unable to detect resource disk device:{0}".format(output))
|
|
|
|
# 'da1: generation: 4 index: 1 status: MORE\npass2: generation: 4 index: 2 status: LAST\n'
|
|
for line in output.split('\n'):
|
|
@@ -90,94 +105,195 @@ class FreeBSDResourceDiskHandler(ResourceDiskHandler):
|
|
raise ResourceDiskError("Unable to detect resource disk device.")
|
|
logger.info('Resource disk device {0} found.', device)
|
|
|
|
- # 2. Detect partition
|
|
- partition_table_type = disks[device]
|
|
+ # 2. Detect/create partition
|
|
|
|
- if partition_table_type == 'MBR':
|
|
- provider_name = device + 's1'
|
|
- elif partition_table_type == 'GPT':
|
|
- provider_name = device + 'p2'
|
|
- else:
|
|
- raise ResourceDiskError(
|
|
- "Unsupported partition table type:{0}".format(output))
|
|
+ # count the target size of each partition
|
|
+ err, output = shellutil.run_get_output("diskinfo {0}".format(device))
|
|
+ if err:
|
|
+ raise ResourceDiskError("Cannot get resource disk size.")
|
|
+ disk_info = output.split()
|
|
+ block_size = int(disk_info[1])
|
|
|
|
+ err, output = shellutil.run_get_output("gpart show {0} | grep '=>'".format(device))
|
|
+ if err:
|
|
+ raise ResourceDiskError("Cannot get resource disk partition information.")
|
|
+ disk_info = output.split()
|
|
+ partition_size = int(disk_info[2]) * block_size
|
|
+
|
|
+ swap_size = 0
|
|
+ if conf.get_resourcedisk_enable_swap():
|
|
+ swap_size_mb = conf.get_resourcedisk_swap_size_mb()
|
|
+ swap_size = swap_size_mb * 1024 * 1024
|
|
+ resource_size = partition_size - swap_size
|
|
+ if resource_size < MINIMAL_RESOURCE_PARTITION_SIZE:
|
|
+ resource_size = MINIMAL_RESOURCE_PARTITION_SIZE
|
|
+ swap_size = partition_size - resource_size
|
|
+
|
|
+ # get size of the current swap partition
|
|
+ current_swap_size = 0
|
|
err, output = shellutil.run_get_output(
|
|
- 'gpart show -p {0}'.format(device))
|
|
- if err or output.find(provider_name) == -1:
|
|
- raise ResourceDiskError("Resource disk partition not found.")
|
|
+ "gpart show {0} 2>/dev/null | grep freebsd-swap".format(device),
|
|
+ chk_err=False)
|
|
+ if output:
|
|
+ current_swap_size = int(output.split()[1]) * block_size
|
|
|
|
- partition = '/dev/' + provider_name
|
|
- logger.info('Resource disk partition {0} found.', partition)
|
|
+ partition_table_type = disks.get(device)
|
|
|
|
- # 3. Mount partition
|
|
- mount_list = shellutil.run_get_output("mount")[1]
|
|
- existing = self.osutil.get_mount_point(mount_list, partition)
|
|
+ resource_provider_name = device + 'p1'
|
|
+ swap_provider_name = device + 'p2'
|
|
|
|
+ # re-partition if needed
|
|
+ if partition_table_type != 'GPT' or current_swap_size != swap_size:
|
|
+ # unmount and swapoff if needed
|
|
+ mount_list = shellutil.run_get_output("mount")[1]
|
|
+ existing = self.osutil.get_mount_point(mount_list,
|
|
+ resource_provider_name)
|
|
+ if existing:
|
|
+ err, output = shellutil.run_get_output(
|
|
+ "umount {0}".format(mount_point), chk_err=False)
|
|
+
|
|
+ swap_info = shellutil.run_get_output("swapctl -l")[1].split('\n')
|
|
+ swap_device = None
|
|
+ if len(swap_info) > 2:
|
|
+ swap_device = swap_info[1].split()[0]
|
|
+ if swap_device:
|
|
+ err, output = shellutil.run_get_output(
|
|
+ "swapoff {0}".format(swap_device), chk_err=False)
|
|
+ if swap_device.endswith('.eli'):
|
|
+ err, output = shellutil.run_get_output(
|
|
+ "geli detach {0}".format(swap_device), chk_err=False)
|
|
+
|
|
+ if partition_table_type is not None:
|
|
+ gaprt_destroy_cmd = "gpart destroy -F {0}".format(device)
|
|
+ err, output = shellutil.run_get_output(gaprt_destroy_cmd,
|
|
+ chk_err=False)
|
|
+ if err:
|
|
+ raise ResourceDiskError("Failed to destroy the "
|
|
+ "partitioning scheme on {0}, "
|
|
+ "error: {1}".format(device, output))
|
|
+ gaprt_create_cmd = "gpart create -s GPT {0}".format(device)
|
|
+ err, output = shellutil.run_get_output(gaprt_create_cmd,
|
|
+ chk_err=False)
|
|
+ if err:
|
|
+ raise ResourceDiskError("Failed to create new GPT on {0}, "
|
|
+ "error: {1}".format(device, output))
|
|
+
|
|
+ mount_list = shellutil.run_get_output("mount")[1]
|
|
+ existing = self.osutil.get_mount_point(mount_list,
|
|
+ resource_provider_name)
|
|
if existing:
|
|
- logger.info("Resource disk {0} is already mounted", partition)
|
|
+ logger.info("Resource disk {0} is already mounted".format(
|
|
+ resource_provider_name))
|
|
return existing
|
|
|
|
+ # create resource partition
|
|
+ if not os.path.exists("/dev/{0}".format(resource_provider_name)):
|
|
+ if swap_size > 0:
|
|
+ err, output = shellutil.run_get_output(
|
|
+ 'gpart add -t freebsd-ufs -s {0}b {1}'.format(resource_size,
|
|
+ device))
|
|
+ else:
|
|
+ err, output = shellutil.run_get_output(
|
|
+ 'gpart add -t freebsd-ufs {0}'.format(device))
|
|
+ if err:
|
|
+ raise ResourceDiskError(
|
|
+ "Failed to add new freebsd-ufs partition to {0}, "
|
|
+ "error: {1}" .format(device, output))
|
|
+
|
|
+ # create swap partition, just use all the space left
|
|
+ if swap_size > 0:
|
|
+ err, output = shellutil.run_get_output(
|
|
+ 'gpart add -t freebsd-swap {0}'.format(device))
|
|
+ if err:
|
|
+ raise ResourceDiskError(
|
|
+ "Failed to add new freebsd-swap partition to {0}, "
|
|
+ "error: {1}" .format(device, output))
|
|
+
|
|
+ # 3. Mount partition
|
|
fileutil.mkdir(mount_point, mode=0o755)
|
|
- mount_cmd = 'mount -t {0} {1} {2}'.format(fs, partition, mount_point)
|
|
- err = shellutil.run(mount_cmd, chk_err=False)
|
|
- if err:
|
|
- logger.info(
|
|
- 'Creating {0} filesystem on partition {1}'.format(
|
|
- fs, partition))
|
|
+
|
|
+ need_newfs = True
|
|
+ if current_swap_size == swap_size:
|
|
+ # swap size is not adjusted,
|
|
+ # i.e., the resource partition is not changed
|
|
+ # check if a fs already exists
|
|
+ fstyp_cmd = 'fstyp /dev/{0}'.format(resource_provider_name)
|
|
+ err, output = shellutil.run_get_output(fstyp_cmd, chk_err=False)
|
|
+ if not err and output == fs:
|
|
+ need_newfs = False
|
|
+ logger.info(
|
|
+ "Resource disk partition {0} is found at {1} "
|
|
+ "with fstype {2}".format(
|
|
+ resource_provider_name, mount_point, fs))
|
|
+ elif swap_size < current_swap_size:
|
|
+ # resource partition size is increased, try to growfs first
|
|
err, output = shellutil.run_get_output(
|
|
- 'newfs -U {0}'.format(partition))
|
|
+ 'growfs -y {0}'.format(resource_provider_name), chk_err=False)
|
|
+ if not err:
|
|
+ need_newfs = False
|
|
+ logger.info(
|
|
+ "Resource disk partition {0} is found and enlarged at {1} "
|
|
+ "with fstype {2}".format(
|
|
+ resource_provider_name, mount_point, fs))
|
|
+ # else
|
|
+ # resource partition is shrunk and newfs is needed
|
|
+
|
|
+ if need_newfs:
|
|
+ logger.info('Creating {0} filesystem on partition {1}'.format(
|
|
+ fs, resource_provider_name))
|
|
+ err, output = shellutil.run_get_output(
|
|
+ 'newfs -U {0}'.format(resource_provider_name))
|
|
if err:
|
|
raise ResourceDiskError(
|
|
- "Failed to create new filesystem on partition {0}, error:{1}" .format(
|
|
- partition, output))
|
|
- err, output = shellutil.run_get_output(mount_cmd, chk_err=False)
|
|
- if err:
|
|
- raise ResourceDiskError(
|
|
- "Failed to mount partition {0}, error {1}".format(
|
|
- partition, output))
|
|
+ "Failed to create new filesystem on partition {0}, "
|
|
+ "error: {1}" .format(resource_provider_name, output))
|
|
|
|
+ mount_cmd = 'mount -t {0} /dev/{1} {2}'.format(
|
|
+ fs, resource_provider_name, mount_point)
|
|
+ err, output = shellutil.run_get_output(mount_cmd, chk_err=False)
|
|
+ if err:
|
|
+ raise ResourceDiskError(
|
|
+ "Failed to mount partition {0}, error {1}".format(
|
|
+ resource_provider_name, output))
|
|
+
|
|
logger.info(
|
|
- "Resource disk partition {0} is mounted at {1} with fstype {2}",
|
|
- partition,
|
|
- mount_point,
|
|
- fs)
|
|
+ "Resource disk partition {0} is mounted at {1} "
|
|
+ "with fstype {2}".format(
|
|
+ resource_provider_name, mount_point, fs))
|
|
return mount_point
|
|
|
|
def create_swap_space(self, mount_point, size_mb):
|
|
- size_kb = size_mb * 1024
|
|
- size = size_kb * 1024
|
|
- swapfile = os.path.join(mount_point, 'swapfile')
|
|
- swaplist = shellutil.run_get_output("swapctl -l")[1]
|
|
+ # done in mount_resource_disk()
|
|
+ pass
|
|
|
|
- if self.check_existing_swap_file(swapfile, swaplist, size):
|
|
+ def enable_swap(self, mount_point):
|
|
+ if conf.get_resourcedisk_swap_size_mb() <=0:
|
|
return
|
|
|
|
- if os.path.isfile(swapfile) and os.path.getsize(swapfile) != size:
|
|
- logger.info("Remove old swap file")
|
|
- shellutil.run("swapoff {0}".format(swapfile), chk_err=False)
|
|
- os.remove(swapfile)
|
|
+ # get swap partition (geom provider)
|
|
+ err, output = shellutil.run_get_output('mount')
|
|
+ if err:
|
|
+ raise ResourceDiskError("Unable to get mount information.")
|
|
+ devices = self.parse_mount_list(output)
|
|
+ resource_provider_name = devices[mount_point]
|
|
+ swap_provider_name = self.get_next_partition(resource_provider_name)
|
|
|
|
- if not os.path.isfile(swapfile):
|
|
- logger.info("Create swap file")
|
|
- self.mkfile(swapfile, size_kb * 1024)
|
|
+ if conf.get_resourcedisk_enable_swap_encryption():
|
|
+ shellutil.run("kldload -n aesni")
|
|
+ shellutil.run("kldload -n cryptodev")
|
|
+ shellutil.run("kldload -n geom_eli")
|
|
+ shellutil.run("geli onetime -e AES-XTS -l 256"
|
|
+ " -d {0}".format(swap_provider_name))
|
|
+ swap_provider_name += ".eli"
|
|
+ shellutil.run("chmod 0600 {0}".format(swap_provider_name))
|
|
|
|
- mddevice = shellutil.run_get_output(
|
|
- "mdconfig -a -t vnode -f {0}".format(swapfile))[1].rstrip()
|
|
- shellutil.run("chmod 0600 /dev/{0}".format(mddevice))
|
|
+ err, output = shellutil.run_get_output(
|
|
+ "swapctl -l | grep {0}".format(swap_provider_name))
|
|
+ if not output:
|
|
+ if shellutil.run("swapon {0}".format(swap_provider_name)):
|
|
+ raise ResourceDiskError(swap_provider_name)
|
|
|
|
- if conf.get_resourcedisk_enable_swap_encryption():
|
|
- shellutil.run("kldload aesni")
|
|
- shellutil.run("kldload cryptodev")
|
|
- shellutil.run("kldload geom_eli")
|
|
- shellutil.run(
|
|
- "geli onetime -e AES-XTS -l 256 -d /dev/{0}".format(mddevice))
|
|
- shellutil.run("chmod 0600 /dev/{0}.eli".format(mddevice))
|
|
- if shellutil.run("swapon /dev/{0}.eli".format(mddevice)):
|
|
- raise ResourceDiskError("/dev/{0}.eli".format(mddevice))
|
|
- logger.info(
|
|
- "Enabled {0}KB of swap at /dev/{1}.eli ({2})".format(size_kb, mddevice, swapfile))
|
|
- else:
|
|
- if shellutil.run("swapon /dev/{0}".format(mddevice)):
|
|
- raise ResourceDiskError("/dev/{0}".format(mddevice))
|
|
- logger.info(
|
|
- "Enabled {0}KB of swap at /dev/{1} ({2})".format(size_kb, mddevice, swapfile))
|
|
+ size_mb = shellutil.run_get_output(
|
|
+ "swapctl -lm | grep {0}".format(swap_provider_name))[1].split()[1]
|
|
+ logger.info(
|
|
+ "Enabled {0}MB of swap at {1}".format(size_mb, swap_provider_name))
|