diff --git a/README.md b/README.md
index c382b592aef..02b2f666580 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ get in contact with that distribution and send them our way!
| Supported OSes | Supported Public Clouds | Supported Private Clouds |
| --- | --- | --- |
-| Alpine Linux
ArchLinux
Debian
Fedora
FreeBSD
Gentoo Linux
NetBSD
OpenBSD
RHEL/CentOS/AlmaLinux/Rocky
SLES/openSUSE
Ubuntu
| Amazon Web Services
Microsoft Azure
Google Cloud Platform
Oracle Cloud Infrastructure
Softlayer
Rackspace Public Cloud
IBM Cloud
Digital Ocean
Bigstep
Hetzner
Joyent
CloudSigma
Alibaba Cloud
OVH
OpenNebula
Exoscale
Scaleway
CloudStack
AltCloud
SmartOS
HyperOne
Vultr
Rootbox
| Bare metal installs
OpenStack
LXD
KVM
Metal-as-a-Service (MAAS)
|
+| Alpine Linux
ArchLinux
Debian
DragonFlyBSD
Fedora
FreeBSD
Gentoo Linux
NetBSD
OpenBSD
RHEL/CentOS/AlmaLinux/Rocky
SLES/openSUSE
Ubuntu
| Amazon Web Services
Microsoft Azure
Google Cloud Platform
Oracle Cloud Infrastructure
Softlayer
Rackspace Public Cloud
IBM Cloud
Digital Ocean
Bigstep
Hetzner
Joyent
CloudSigma
Alibaba Cloud
OVH
OpenNebula
Exoscale
Scaleway
CloudStack
AltCloud
SmartOS
HyperOne
Vultr
Rootbox
| Bare metal installs
OpenStack
LXD
KVM
Metal-as-a-Service (MAAS)
|
## To start developing cloud-init
diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py
index 9f338ad15a9..9f5525a1e92 100644
--- a/cloudinit/config/cc_growpart.py
+++ b/cloudinit/config/cc_growpart.py
@@ -224,6 +224,10 @@ def device_part_info(devpath):
freebsd_part = "/dev/" + util.find_freebsd_part(devpath)
m = re.search('^(/dev/.+)p([0-9])$', freebsd_part)
return (m.group(1), m.group(2))
+ elif util.is_DragonFlyBSD():
+ dragonflybsd_part = "/dev/" + util.find_dragonflybsd_part(devpath)
+ m = re.search('^(/dev/.+)s([0-9])$', dragonflybsd_part)
+ return (m.group(1), m.group(2))
if not os.path.exists(syspath):
raise ValueError("%s had no syspath (%s)" % (devpath, syspath))
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
index 9afbb847cdc..990a6939248 100644
--- a/cloudinit/config/cc_resizefs.py
+++ b/cloudinit/config/cc_resizefs.py
@@ -85,6 +85,10 @@ def _resize_zfs(mount_point, devpth):
return ('zpool', 'online', '-e', mount_point, devpth)
+def _resize_hammer2(mount_point, devpth):
+ return ('hammer2', 'growfs', mount_point)
+
+
def _can_skip_resize_ufs(mount_point, devpth):
# possible errors cases on the code-path to growfs -N following:
# https://github.com/freebsd/freebsd/blob/HEAD/sbin/growfs/growfs.c
@@ -113,6 +117,7 @@ def _can_skip_resize_ufs(mount_point, devpth):
('xfs', _resize_xfs),
('ufs', _resize_ufs),
('zfs', _resize_zfs),
+ ('hammer2', _resize_hammer2),
]
RESIZE_FS_PRECHECK_CMDS = {
diff --git a/cloudinit/distros/dragonflybsd.py b/cloudinit/distros/dragonflybsd.py
new file mode 100644
index 00000000000..2d825518259
--- /dev/null
+++ b/cloudinit/distros/dragonflybsd.py
@@ -0,0 +1,12 @@
+# Copyright (C) 2020-2021 Gonéri Le Bouder
+#
+# This file is part of cloud-init. See LICENSE file for license information.
+
+import cloudinit.distros.freebsd
+
+
+class Distro(cloudinit.distros.freebsd.Distro):
+ home_dir = '/home'
+
+
+# vi: ts=4 expandtab
diff --git a/cloudinit/distros/freebsd.py b/cloudinit/distros/freebsd.py
index 9659843fbf6..d94a52b88b9 100644
--- a/cloudinit/distros/freebsd.py
+++ b/cloudinit/distros/freebsd.py
@@ -18,6 +18,12 @@
class Distro(cloudinit.distros.bsd.BSD):
+ """
+ Distro subclass for FreeBSD.
+
+ (N.B. DragonFlyBSD inherits from this class.)
+ """
+
usr_lib_exec = '/usr/local/lib'
login_conf_fn = '/etc/login.conf'
login_conf_fn_bak = '/etc/login.conf.orig'
@@ -28,6 +34,7 @@ class Distro(cloudinit.distros.bsd.BSD):
pkg_cmd_update_prefix = ["pkg", "update"]
pkg_cmd_upgrade_prefix = ["pkg", "upgrade"]
prefer_fqdn = True # See rc.conf(5) in FreeBSD
+ home_dir = '/usr/home'
def _get_add_member_to_group_cmd(self, member_name, group_name):
return ['pw', 'usermod', '-n', member_name, '-G', group_name]
@@ -66,9 +73,12 @@ def add_user(self, name, **kwargs):
pw_useradd_cmd.append('-d/nonexistent')
log_pw_useradd_cmd.append('-d/nonexistent')
else:
- pw_useradd_cmd.append('-d/usr/home/%s' % name)
+ pw_useradd_cmd.append('-d{home_dir}/{name}'.format(
+ home_dir=self.home_dir, name=name))
pw_useradd_cmd.append('-m')
- log_pw_useradd_cmd.append('-d/usr/home/%s' % name)
+ log_pw_useradd_cmd.append('-d{home_dir}/{name}'.format(
+ home_dir=self.home_dir, name=name))
+
log_pw_useradd_cmd.append('-m')
# Run the command
@@ -155,4 +165,5 @@ def update_package_sources(self):
"update-sources", self.package_command,
["update"], freq=PER_INSTANCE)
+
# vi: ts=4 expandtab
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py
index 6b3b84f7016..b827d41a7ec 100644
--- a/cloudinit/net/__init__.py
+++ b/cloudinit/net/__init__.py
@@ -351,7 +351,7 @@ def device_devid(devname):
def get_devicelist():
- if util.is_FreeBSD():
+ if util.is_FreeBSD() or util.is_DragonFlyBSD():
return list(get_interfaces_by_mac().values())
try:
@@ -376,7 +376,7 @@ def is_disabled_cfg(cfg):
def find_fallback_nic(blacklist_drivers=None):
"""Return the name of the 'fallback' network device."""
- if util.is_FreeBSD():
+ if util.is_FreeBSD() or util.is_DragonFlyBSD():
return find_fallback_nic_on_freebsd(blacklist_drivers)
elif util.is_NetBSD() or util.is_OpenBSD():
return find_fallback_nic_on_netbsd_or_openbsd(blacklist_drivers)
@@ -816,7 +816,7 @@ def get_ib_interface_hwaddr(ifname, ethernet_format):
def get_interfaces_by_mac(blacklist_drivers=None) -> dict:
- if util.is_FreeBSD():
+ if util.is_FreeBSD() or util.is_DragonFlyBSD():
return get_interfaces_by_mac_on_freebsd(
blacklist_drivers=blacklist_drivers)
elif util.is_NetBSD():
diff --git a/cloudinit/net/freebsd.py b/cloudinit/net/freebsd.py
index c843d792e72..f8faf240389 100644
--- a/cloudinit/net/freebsd.py
+++ b/cloudinit/net/freebsd.py
@@ -32,6 +32,13 @@ def start_services(self, run=False):
LOG.debug("freebsd generate postcmd disabled")
return
+ for dhcp_interface in self.dhcp_interfaces():
+ # Observed on DragonFlyBSD 6. If we use the "restart" parameter,
+ # the routes are not recreated.
+ subp.subp(['service', 'dhclient', 'stop', dhcp_interface],
+ rcs=[0, 1],
+ capture=True)
+
subp.subp(['service', 'netif', 'restart'], capture=True)
# On FreeBSD 10, the restart of routing and dhclient is likely to fail
# because
@@ -42,7 +49,7 @@ def start_services(self, run=False):
subp.subp(['service', 'routing', 'restart'], capture=True, rcs=[0, 1])
for dhcp_interface in self.dhcp_interfaces():
- subp.subp(['service', 'dhclient', 'restart', dhcp_interface],
+ subp.subp(['service', 'dhclient', 'start', dhcp_interface],
rcs=[0, 1],
capture=True)
@@ -57,4 +64,4 @@ def set_route(self, network, netmask, gateway):
def available(target=None):
- return util.is_FreeBSD()
+ return util.is_FreeBSD() or util.is_DragonFlyBSD()
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 2de1123e904..f95dc435179 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -392,7 +392,11 @@ def is_Linux():
@lru_cache()
def is_BSD():
- return 'BSD' in platform.system()
+ if 'BSD' in platform.system():
+ return True
+ if platform.system() == 'DragonFly':
+ return True
+ return False
@lru_cache()
@@ -400,6 +404,11 @@ def is_FreeBSD():
return system_info()['variant'] == "freebsd"
+@lru_cache()
+def is_DragonFlyBSD():
+ return system_info()['variant'] == "dragonfly"
+
+
@lru_cache()
def is_NetBSD():
return system_info()['variant'] == "netbsd"
@@ -534,7 +543,9 @@ def system_info():
var = 'suse'
else:
var = 'linux'
- elif system in ('windows', 'darwin', "freebsd", "netbsd", "openbsd"):
+ elif system in (
+ 'windows', 'darwin', "freebsd", "netbsd",
+ "openbsd", "dragonfly"):
var = system
info['variant'] = var
@@ -1195,6 +1206,23 @@ def find_devs_with_openbsd(criteria=None, oformat='device',
return ['/dev/' + i for i in devlist]
+def find_devs_with_dragonflybsd(criteria=None, oformat='device',
+ tag=None, no_cache=False, path=None):
+ out, _err = subp.subp(['sysctl', '-n', 'kern.disks'], rcs=[0])
+ devlist = [i for i in sorted(out.split(), reverse=True)
+ if not i.startswith("md") and not i.startswith("vn")]
+
+ if criteria == "TYPE=iso9660":
+ devlist = [i for i in devlist
+ if i.startswith('cd') or i.startswith('acd')]
+ elif criteria in ["LABEL=CONFIG-2", "TYPE=vfat"]:
+ devlist = [i for i in devlist
+ if not (i.startswith('cd') or i.startswith('acd'))]
+ elif criteria:
+ LOG.debug("Unexpected criteria: %s", criteria)
+ return ['/dev/' + i for i in devlist]
+
+
def find_devs_with(criteria=None, oformat='device',
tag=None, no_cache=False, path=None):
"""
@@ -1213,6 +1241,9 @@ def find_devs_with(criteria=None, oformat='device',
elif is_OpenBSD():
return find_devs_with_openbsd(criteria, oformat,
tag, no_cache, path)
+ elif is_DragonFlyBSD():
+ return find_devs_with_dragonflybsd(criteria, oformat,
+ tag, no_cache, path)
blk_id_cmd = ['blkid']
options = []
@@ -2211,6 +2242,14 @@ def find_freebsd_part(fs):
LOG.warning("Unexpected input in find_freebsd_part: %s", fs)
+def find_dragonflybsd_part(fs):
+ splitted = fs.split('/')
+ if len(splitted) == 3 and splitted[1] == 'dev':
+ return splitted[2]
+ else:
+ LOG.warning("Unexpected input in find_dragonflybsd_part: %s", fs)
+
+
def get_path_dev_freebsd(path, mnt_list):
path_found = None
for line in mnt_list.split("\n"):
@@ -2264,6 +2303,9 @@ def parse_mount(path):
# https://regex101.com/r/T2en7a/1
regex = (r'^(/dev/[\S]+|.*zroot\S*?) on (/[\S]*) '
r'(?=(?:type)[\s]+([\S]+)|\(([^,]*))')
+ if is_DragonFlyBSD():
+ regex = (r'^(/dev/[\S]+|\S*?) on (/[\S]*) '
+ r'(?=(?:type)[\s]+([\S]+)|\(([^,]*))')
for line in mount_locs:
m = re.search(regex, line)
if not m:
diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
index 2f6c3a7db5a..586384e41f1 100644
--- a/config/cloud.cfg.tmpl
+++ b/config/cloud.cfg.tmpl
@@ -1,8 +1,8 @@
## template:jinja
# The top level settings are used as module
# and system configuration.
-
-{% if variant.endswith("bsd") %}
+{% set is_bsd = variant in ["dragonfly", "freebsd", "netbsd", "openbsd"] %}
+{% if is_bsd %}
syslog_fix_perms: root:wheel
{% elif variant in ["suse"] %}
syslog_fix_perms: root:root
@@ -61,11 +61,11 @@ cloud_init_modules:
{% endif %}
- bootcmd
- write-files
-{% if variant not in ["netbsd"] %}
+{% if variant not in ["netbsd", "openbsd"] %}
- growpart
- resizefs
{% endif %}
-{% if variant not in ["freebsd", "netbsd"] %}
+{% if not is_bsd %}
- disk_setup
- mounts
{% endif %}
@@ -158,6 +158,8 @@ system_info:
"fedora", "freebsd", "netbsd", "openbsd", "rhel", "rocky",
"suse", "ubuntu"] %}
distro: {{ variant }}
+{% elif variant in ["dragonfly"] %}
+ distro: dragonflybsd
{% else %}
# Unknown/fallback distro.
distro: ubuntu
@@ -249,6 +251,15 @@ system_info:
groups: [wheel]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/tcsh
+{% elif variant in ["dragonfly"] %}
+ # Default user name + that default users groups (if added/used)
+ default_user:
+ name: dragonfly
+ lock_passwd: True
+ gecos: DragonFly
+ groups: [wheel]
+ sudo: ["ALL=(ALL) NOPASSWD:ALL"]
+ shell: /bin/sh
{% elif variant in ["netbsd"] %}
default_user:
name: netbsd
@@ -269,4 +280,7 @@ system_info:
{% if variant in ["freebsd", "netbsd", "openbsd"] %}
network:
renderers: ['{{ variant }}']
+{% elif variant in ["dragonfly"] %}
+ network:
+ renderers: ['freebsd']
{% endif %}
diff --git a/doc/rtd/topics/availability.rst b/doc/rtd/topics/availability.rst
index f3e13edce92..e4480754265 100644
--- a/doc/rtd/topics/availability.rst
+++ b/doc/rtd/topics/availability.rst
@@ -14,12 +14,13 @@ distributions and clouds, both public and private.
Distributions
=============
-Cloud-init has support across all major Linux distributions, FreeBSD, NetBSD
-and OpenBSD:
+Cloud-init has support across all major Linux distributions, FreeBSD, NetBSD,
+OpenBSD and DragonFlyBSD:
- Alpine Linux
- ArchLinux
- Debian
+- DragonFlyBSD
- Fedora
- FreeBSD
- Gentoo Linux
diff --git a/setup.py b/setup.py
index cbacf48e1a0..dcbe0843d58 100755
--- a/setup.py
+++ b/setup.py
@@ -156,7 +156,7 @@ def render_tmpl(template, mode=None):
ETC = "etc"
USR_LIB_EXEC = "usr/lib"
LIB = "lib"
-if os.uname()[0] == 'FreeBSD':
+if os.uname()[0] in ['FreeBSD', 'DragonFly']:
USR = "usr/local"
USR_LIB_EXEC = "usr/local/lib"
elif os.path.isfile('/etc/redhat-release'):
diff --git a/sysvinit/freebsd/cloudinit b/sysvinit/freebsd/cloudinit
index aa5bd11878c..d26f3d0fbd3 100755
--- a/sysvinit/freebsd/cloudinit
+++ b/sysvinit/freebsd/cloudinit
@@ -2,7 +2,7 @@
# PROVIDE: cloudinit
# REQUIRE: FILESYSTEMS NETWORKING cloudinitlocal ldconfig devd
-# BEFORE: cloudconfig cloudfinal
+# BEFORE: LOGIN cloudconfig cloudfinal
. /etc/rc.subr
diff --git a/tests/unittests/test_distros/test_dragonflybsd.py b/tests/unittests/test_distros/test_dragonflybsd.py
new file mode 100644
index 00000000000..df2c00f41a1
--- /dev/null
+++ b/tests/unittests/test_distros/test_dragonflybsd.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+
+import cloudinit.util
+from cloudinit.tests.helpers import mock
+
+
+def test_find_dragonflybsd_part():
+ assert cloudinit.util.find_dragonflybsd_part("/dev/vbd0s3") == "vbd0s3"
+
+
+@mock.patch("cloudinit.util.is_DragonFlyBSD")
+@mock.patch("cloudinit.subp.subp")
+def test_parse_mount(mock_subp, m_is_DragonFlyBSD):
+ mount_out = """
+vbd0s3 on / (hammer2, local)
+devfs on /dev (devfs, nosymfollow, local)
+/dev/vbd0s0a on /boot (ufs, local)
+procfs on /proc (procfs, local)
+tmpfs on /var/run/shm (tmpfs, local)
+"""
+
+ mock_subp.return_value = (mount_out, "")
+ m_is_DragonFlyBSD.return_value = True
+ assert cloudinit.util.parse_mount("/") == ("vbd0s3", "hammer2", "/")
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index e52920010a2..2290cab70b9 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -999,4 +999,22 @@ def test_find_devs_with_netbsd(self, m_subp, criteria, expected_devlist):
devlist = util.find_devs_with_netbsd(criteria=criteria)
assert devlist == expected_devlist
+ @pytest.mark.parametrize(
+ 'criteria,expected_devlist', (
+ (None, ['/dev/vbd0', '/dev/cd0', '/dev/acd0']),
+ ('TYPE=iso9660', ['/dev/cd0', '/dev/acd0']),
+ ('TYPE=vfat', ['/dev/vbd0']),
+ ('LABEL_FATBOOT=A_LABEL', # lp: #1841466
+ ['/dev/vbd0', '/dev/cd0', '/dev/acd0']),
+ )
+ )
+ @mock.patch("cloudinit.subp.subp")
+ def test_find_devs_with_dragonflybsd(self, m_subp, criteria,
+ expected_devlist):
+ m_subp.return_value = (
+ 'md2 md1 cd0 vbd0 acd0 vn3 vn2 vn1 vn0 md0', ''
+ )
+ devlist = util.find_devs_with_dragonflybsd(criteria=criteria)
+ assert devlist == expected_devlist
+
# vi: ts=4 expandtab