diff options
Diffstat (limited to 'net/cloud-init-azure/files/patch-frbsd-azure.txt')
| -rw-r--r-- | net/cloud-init-azure/files/patch-frbsd-azure.txt | 1213 |
1 files changed, 0 insertions, 1213 deletions
diff --git a/net/cloud-init-azure/files/patch-frbsd-azure.txt b/net/cloud-init-azure/files/patch-frbsd-azure.txt deleted file mode 100644 index fe6e72cba422..000000000000 --- a/net/cloud-init-azure/files/patch-frbsd-azure.txt +++ /dev/null @@ -1,1213 +0,0 @@ ---- cloudinit/config/cc_resizefs.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/config/cc_resizefs.py -@@ -33,7 +33,10 @@ disabled altogether by setting ``resize_rootfs`` to `` - """ - - import errno -+import getopt - import os -+import re -+import shlex - import stat - - from cloudinit.settings import PER_ALWAYS -@@ -58,6 +61,62 @@ def _resize_ufs(mount_point, devpth): - return ('growfs', devpth) - - -+def _get_dumpfs_output(mount_point): -+ dumpfs_res, err = util.subp(['dumpfs', '-m', mount_point]) -+ return dumpfs_res -+ -+ -+def _get_gpart_output(part): -+ gpart_res, err = util.subp(['gpart', 'show', part]) -+ return gpart_res -+ -+ -+def _can_skip_resize_ufs(mount_point, devpth): -+ # extract the current fs sector size -+ """ -+ # dumpfs -m / -+ # newfs command for / (/dev/label/rootfs) -+ newfs -O 2 -U -a 4 -b 32768 -d 32768 -e 4096 -f 4096 -g 16384 -+ -h 64 -i 8192 -j -k 6408 -m 8 -o time -s 58719232 /dev/label/rootf -+ """ -+ cur_fs_sz = None -+ frag_sz = None -+ dumpfs_res = _get_dumpfs_output(mount_point) -+ for line in dumpfs_res.splitlines(): -+ if not line.startswith('#'): -+ newfs_cmd = shlex.split(line) -+ opt_value = 'O:Ua:s:b:d:e:f:g:h:i:jk:m:o:' -+ optlist, args = getopt.getopt(newfs_cmd[1:], opt_value) -+ for o, a in optlist: -+ if o == "-s": -+ cur_fs_sz = int(a) -+ if o == "-f": -+ frag_sz = int(a) -+ # check the current partition size -+ """ -+ # gpart show /dev/da0 -+=> 40 62914480 da0 GPT (30G) -+ 40 1024 1 freebsd-boot (512K) -+ 1064 58719232 2 freebsd-ufs (28G) -+ 58720296 3145728 3 freebsd-swap (1.5G) -+ 61866024 1048496 - free - (512M) -+ """ -+ expect_sz = None -+ m = re.search('^(/dev/.+)p([0-9])$', devpth) -+ gpart_res = _get_gpart_output(m.group(1)) -+ for line in gpart_res.splitlines(): -+ if re.search(r"freebsd-ufs", line): -+ fields = line.split() -+ expect_sz = int(fields[1]) -+ # Normalize the gpart sector size, -+ # because the size is not exactly the same as fs size. -+ normal_expect_sz = (expect_sz - expect_sz % (frag_sz / 512)) -+ if normal_expect_sz == cur_fs_sz: -+ return True -+ else: -+ return False -+ -+ - # 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. -@@ -68,6 +127,10 @@ RESIZE_FS_PREFIXES_CMDS = [ - ('ufs', _resize_ufs), - ] - -+RESIZE_FS_PRECHECK_CMDS = { -+ 'ufs': _can_skip_resize_ufs -+} -+ - NOBLOCK = "noblock" - - -@@ -90,6 +153,14 @@ def rootdev_from_cmdline(cmdline): - return "/dev/" + found - - -+def can_skip_resize(fs_type, resize_what, devpth): -+ fstype_lc = fs_type.lower() -+ for i, func in RESIZE_FS_PRECHECK_CMDS.items(): -+ if fstype_lc.startswith(i): -+ return func(resize_what, devpth) -+ return False -+ -+ - def handle(name, cfg, _cloud, log, args): - if len(args) != 0: - resize_root = args[0] -@@ -158,6 +229,11 @@ def handle(name, cfg, _cloud, log, args): - return - - resizer = None -+ if can_skip_resize(fs_type, resize_what, devpth): -+ log.debug("Skip resize filesystem type %s for %s", -+ fs_type, resize_what) -+ return -+ - fstype_lc = fs_type.lower() - for (pfix, root_cmd) in RESIZE_FS_PREFIXES_CMDS: - if fstype_lc.startswith(pfix): ---- cloudinit/distros/__init__.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/distros/__init__.py -@@ -142,6 +142,9 @@ class Distro(object): - ns, header=header, render_hwaddress=True) - return self.apply_network(contents, bring_up=bring_up) - -+ def generate_fallback_config(self): -+ return net.generate_fallback_config() -+ - def apply_network_config(self, netconfig, bring_up=False): - # apply network config netconfig - # This method is preferred to apply_network which only takes ---- cloudinit/distros/freebsd.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/distros/freebsd.py -@@ -30,6 +30,7 @@ class Distro(distros.Distro): - login_conf_fn_bak = '/etc/login.conf.orig' - resolv_conf_fn = '/etc/resolv.conf' - ci_sudoers_fn = '/usr/local/etc/sudoers.d/90-cloud-init-users' -+ default_primary_nic = 'hn0' - - def __init__(self, name, cfg, paths): - distros.Distro.__init__(self, name, cfg, paths) -@@ -38,6 +39,8 @@ class Distro(distros.Distro): - # should only happen say once per instance...) - self._runner = helpers.Runners(paths) - self.osfamily = 'freebsd' -+ self.ipv4_pat = re.compile(r"\s+inet\s+\d+[.]\d+[.]\d+[.]\d+") -+ cfg['ssh_svcname'] = 'sshd' - - # Updates a key in /etc/rc.conf. - def updatercconf(self, key, value): -@@ -183,7 +186,6 @@ class Distro(distros.Distro): - "gecos": '-c', - "primary_group": '-g', - "groups": '-G', -- "passwd": '-h', - "shell": '-s', - "inactive": '-E', - } -@@ -193,19 +195,11 @@ class Distro(distros.Distro): - "no_log_init": '--no-log-init', - } - -- redact_opts = ['passwd'] -- - for key, val in kwargs.items(): - if (key in adduser_opts and val and - isinstance(val, six.string_types)): - adduser_cmd.extend([adduser_opts[key], val]) - -- # Redact certain fields from the logs -- if key in redact_opts: -- log_adduser_cmd.extend([adduser_opts[key], 'REDACTED']) -- else: -- log_adduser_cmd.extend([adduser_opts[key], val]) -- - elif key in adduser_flags and val: - adduser_cmd.append(adduser_flags[key]) - log_adduser_cmd.append(adduser_flags[key]) -@@ -226,19 +220,21 @@ class Distro(distros.Distro): - except Exception as e: - util.logexc(LOG, "Failed to create user %s", name) - raise e -+ # Set the password if it is provided -+ # For security consideration, only hashed passwd is assumed -+ passwd_val = kwargs.get('passwd', None) -+ if passwd_val is not None: -+ self.set_passwd(name, passwd_val, hashed=True) - - def set_passwd(self, user, passwd, hashed=False): -- cmd = ['pw', 'usermod', user] -- - if hashed: -- cmd.append('-H') -+ hash_opt = "-H" - else: -- cmd.append('-h') -+ hash_opt = "-h" - -- cmd.append('0') -- - try: -- util.subp(cmd, passwd, logstring="chpasswd for %s" % user) -+ util.subp(['pw', 'usermod', user, hash_opt, '0'], -+ data=passwd, logstring="chpasswd for %s" % user) - except Exception as e: - util.logexc(LOG, "Failed to set password for %s", user) - raise e -@@ -270,6 +266,255 @@ class Distro(distros.Distro): - if 'ssh_authorized_keys' in kwargs: - keys = set(kwargs['ssh_authorized_keys']) or [] - ssh_util.setup_user_keys(keys, name, options=None) -+ -+ @staticmethod -+ def get_ifconfig_list(): -+ cmd = ['ifconfig', '-l'] -+ (nics, err) = util.subp(cmd, rcs=[0, 1]) -+ if len(err): -+ LOG.warn("Error running %s: %s", cmd, err) -+ return None -+ return nics -+ -+ @staticmethod -+ def get_ifconfig_ifname_out(ifname): -+ cmd = ['ifconfig', ifname] -+ (if_result, err) = util.subp(cmd, rcs=[0, 1]) -+ if len(err): -+ LOG.warn("Error running %s: %s", cmd, err) -+ return None -+ return if_result -+ -+ @staticmethod -+ def get_ifconfig_ether(): -+ cmd = ['ifconfig', '-l', 'ether'] -+ (nics, err) = util.subp(cmd, rcs=[0, 1]) -+ if len(err): -+ LOG.warn("Error running %s: %s", cmd, err) -+ return None -+ return nics -+ -+ @staticmethod -+ def get_interface_mac(ifname): -+ if_result = Distro.get_ifconfig_ifname_out(ifname) -+ for item in if_result.splitlines(): -+ if item.find('ether ') != -1: -+ mac = str(item.split()[1]) -+ if mac: -+ return mac -+ -+ @staticmethod -+ def get_devicelist(): -+ nics = Distro.get_ifconfig_list() -+ return nics.split() -+ -+ @staticmethod -+ def get_ipv6(): -+ ipv6 = [] -+ nics = Distro.get_devicelist() -+ for nic in nics: -+ if_result = Distro.get_ifconfig_ifname_out(nic) -+ for item in if_result.splitlines(): -+ if item.find("inet6 ") != -1 and item.find("scopeid") == -1: -+ ipv6.append(nic) -+ return ipv6 -+ -+ def get_ipv4(self): -+ ipv4 = [] -+ nics = Distro.get_devicelist() -+ for nic in nics: -+ if_result = Distro.get_ifconfig_ifname_out(nic) -+ for item in if_result.splitlines(): -+ print(item) -+ if self.ipv4_pat.match(item): -+ ipv4.append(nic) -+ return ipv4 -+ -+ def is_up(self, ifname): -+ if_result = Distro.get_ifconfig_ifname_out(ifname) -+ pat = "^" + ifname -+ for item in if_result.splitlines(): -+ if re.match(pat, item): -+ flags = item.split('<')[1].split('>')[0] -+ if flags.find("UP") != -1: -+ return True -+ -+ def _get_current_rename_info(self, check_downable=True): -+ """Collect information necessary for rename_interfaces.""" -+ names = Distro.get_devicelist() -+ bymac = {} -+ for n in names: -+ bymac[Distro.get_interface_mac(n)] = { -+ 'name': n, 'up': self.is_up(n), 'downable': None} -+ -+ if check_downable: -+ nics_with_addresses = set() -+ ipv6 = self.get_ipv6() -+ ipv4 = self.get_ipv4() -+ for bytes_out in (ipv6, ipv4): -+ for i in ipv6: -+ nics_with_addresses.update(i) -+ for i in ipv4: -+ nics_with_addresses.update(i) -+ -+ for d in bymac.values(): -+ d['downable'] = (d['up'] is False or -+ d['name'] not in nics_with_addresses) -+ -+ return bymac -+ -+ def _rename_interfaces(self, renames): -+ if not len(renames): -+ LOG.debug("no interfaces to rename") -+ return -+ -+ current_info = self._get_current_rename_info() -+ -+ cur_bymac = {} -+ for mac, data in current_info.items(): -+ cur = data.copy() -+ cur['mac'] = mac -+ cur_bymac[mac] = cur -+ -+ def update_byname(bymac): -+ return dict((data['name'], data) -+ for data in bymac.values()) -+ -+ def rename(cur, new): -+ util.subp(["ifconfig", cur, "name", new], capture=True) -+ -+ def down(name): -+ util.subp(["ifconfig", name, "down"], capture=True) -+ -+ def up(name): -+ util.subp(["ifconfig", name, "up"], capture=True) -+ -+ ops = [] -+ errors = [] -+ ups = [] -+ cur_byname = update_byname(cur_bymac) -+ tmpname_fmt = "cirename%d" -+ tmpi = -1 -+ -+ for mac, new_name in renames: -+ cur = cur_bymac.get(mac, {}) -+ cur_name = cur.get('name') -+ cur_ops = [] -+ if cur_name == new_name: -+ # nothing to do -+ continue -+ -+ if not cur_name: -+ errors.append("[nic not present] Cannot rename mac=%s to %s" -+ ", not available." % (mac, new_name)) -+ continue -+ -+ if cur['up']: -+ msg = "[busy] Error renaming mac=%s from %s to %s" -+ if not cur['downable']: -+ errors.append(msg % (mac, cur_name, new_name)) -+ continue -+ cur['up'] = False -+ cur_ops.append(("down", mac, new_name, (cur_name,))) -+ ups.append(("up", mac, new_name, (new_name,))) -+ -+ if new_name in cur_byname: -+ target = cur_byname[new_name] -+ if target['up']: -+ msg = "[busy-target] Error renaming mac=%s from %s to %s." -+ if not target['downable']: -+ errors.append(msg % (mac, cur_name, new_name)) -+ continue -+ else: -+ cur_ops.append(("down", mac, new_name, (new_name,))) -+ -+ tmp_name = None -+ while tmp_name is None or tmp_name in cur_byname: -+ tmpi += 1 -+ tmp_name = tmpname_fmt % tmpi -+ -+ cur_ops.append(("rename", mac, new_name, (new_name, tmp_name))) -+ target['name'] = tmp_name -+ cur_byname = update_byname(cur_bymac) -+ if target['up']: -+ ups.append(("up", mac, new_name, (tmp_name,))) -+ -+ cur_ops.append(("rename", mac, new_name, (cur['name'], new_name))) -+ cur['name'] = new_name -+ cur_byname = update_byname(cur_bymac) -+ ops += cur_ops -+ -+ opmap = {'rename': rename, 'down': down, 'up': up} -+ if len(ops) + len(ups) == 0: -+ if len(errors): -+ LOG.debug("unable to do any work for renaming of %s", renames) -+ else: -+ LOG.debug("no work necessary for renaming of %s", renames) -+ else: -+ LOG.debug("achieving renaming of %s with ops %s", -+ renames, ops + ups) -+ -+ for op, mac, new_name, params in ops + ups: -+ try: -+ opmap.get(op)(*params) -+ except Exception as e: -+ errors.append( -+ "[unknown] Error performing %s%s for %s, %s: %s" % -+ (op, params, mac, new_name, e)) -+ if len(errors): -+ raise Exception('\n'.join(errors)) -+ -+ def apply_network_config_names(self, netcfg): -+ renames = [] -+ for ent in netcfg.get('config', {}): -+ if ent.get('type') != 'physical': -+ continue -+ mac = ent.get('mac_address') -+ name = ent.get('name') -+ if not mac: -+ continue -+ renames.append([mac, name]) -+ return self._rename_interfaces(renames) -+ -+ @classmethod -+ def generate_fallback_config(self): -+ nics = Distro.get_ifconfig_ether() -+ if nics is None: -+ LOG.debug("Fail to get network interfaces") -+ return None -+ potential_interfaces = nics.split() -+ connected = [] -+ for nic in potential_interfaces: -+ pat = "^" + nic -+ if_result = Distro.get_ifconfig_ifname_out(nic) -+ for item in if_result.split("\n"): -+ if re.match(pat, item): -+ flags = item.split('<')[1].split('>')[0] -+ if flags.find("RUNNING") != -1: -+ connected.append(nic) -+ if connected: -+ potential_interfaces = connected -+ names = list(sorted(potential_interfaces)) -+ default_pri_nic = Distro.default_primary_nic -+ if default_pri_nic in names: -+ names.remove(default_pri_nic) -+ names.insert(0, default_pri_nic) -+ target_name = None -+ target_mac = None -+ for name in names: -+ mac = Distro.get_interface_mac(name) -+ if mac: -+ target_name = name -+ target_mac = mac -+ break -+ if target_mac and target_name: -+ nconf = {'config': [], 'version': 1} -+ nconf['config'].append( -+ {'type': 'physical', 'name': target_name, -+ 'mac_address': target_mac, 'subnets': [{'type': 'dhcp'}]}) -+ return nconf -+ else: -+ return None - - def _write_network(self, settings): - entries = net_util.translate_network(settings) ---- cloudinit/settings.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/settings.py -@@ -37,7 +37,7 @@ CFG_BUILTIN = { - ], - 'def_log_file': '/var/log/cloud-init.log', - 'log_cfgs': [], -- 'syslog_fix_perms': ['syslog:adm', 'root:adm'], -+ 'syslog_fix_perms': ['syslog:adm', 'root:adm', 'root:wheel'], - 'system_info': { - 'paths': { - 'cloud_dir': '/var/lib/cloud', ---- cloudinit/sources/DataSourceAzure.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/sources/DataSourceAzure.py -@@ -10,6 +10,7 @@ import crypt - from functools import partial - import os - import os.path -+import re - import time - from xml.dom import minidom - import xml.etree.ElementTree as ET -@@ -32,19 +33,160 @@ BOUNCE_COMMAND = [ - # azure systems will always have a resource disk, and 66-azure-ephemeral.rules - # ensures that it gets linked to this path. - RESOURCE_DISK_PATH = '/dev/disk/cloud/azure_resource' -+DEFAULT_PRIMARY_NIC = 'eth0' -+LEASE_FILE = '/var/lib/dhcp/dhclient.eth0.leases' -+DEFAULT_FS = 'ext4' - -+ -+def find_storvscid_from_sysctl_pnpinfo(sysctl_out, deviceid): -+ # extract the 'X' from dev.storvsc.X. if deviceid matches -+ """ -+ dev.storvsc.1.%pnpinfo: -+ classid=32412632-86cb-44a2-9b5c-50d1417354f5 -+ deviceid=00000000-0001-8899-0000-000000000000 -+ """ -+ for line in sysctl_out.splitlines(): -+ if re.search(r"pnpinfo", line): -+ fields = line.split() -+ if len(fields) >= 3: -+ columns = fields[2].split('=') -+ if (len(columns) >= 2 and -+ columns[0] == "deviceid" and -+ columns[1].startswith(deviceid)): -+ comps = fields[0].split('.') -+ return comps[2] -+ return None -+ -+ -+def find_busdev_from_disk(camcontrol_out, disk_drv): -+ # find the scbusX from 'camcontrol devlist -b' output -+ # if disk_drv matches the specified disk driver, i.e. blkvsc1 -+ """ -+ scbus0 on ata0 bus 0 -+ scbus1 on ata1 bus 0 -+ scbus2 on blkvsc0 bus 0 -+ scbus3 on blkvsc1 bus 0 -+ scbus4 on storvsc2 bus 0 -+ scbus5 on storvsc3 bus 0 -+ scbus-1 on xpt0 bus 0 -+ """ -+ for line in camcontrol_out.splitlines(): -+ if re.search(disk_drv, line): -+ items = line.split() -+ return items[0] -+ return None -+ -+ -+def find_dev_from_busdev(camcontrol_out, busdev): -+ # find the daX from 'camcontrol devlist' output -+ # if busdev matches the specified value, i.e. 'scbus2' -+ """ -+ <Msft Virtual CD/ROM 1.0> at scbus1 target 0 lun 0 (cd0,pass0) -+ <Msft Virtual Disk 1.0> at scbus2 target 0 lun 0 (da0,pass1) -+ <Msft Virtual Disk 1.0> at scbus3 target 1 lun 0 (da1,pass2) -+ """ -+ for line in camcontrol_out.splitlines(): -+ if re.search(busdev, line): -+ items = line.split('(') -+ if len(items) == 2: -+ dev_pass = items[1].split(',') -+ return dev_pass[0] -+ return None -+ -+ -+def get_dev_storvsc_sysctl(): -+ try: -+ sysctl_out, err = util.subp(['sysctl', 'dev.storvsc']) -+ except util.ProcessExecutionError: -+ LOG.debug("Fail to execute sysctl dev.storvsc") -+ return None -+ return sysctl_out -+ -+ -+def get_camcontrol_dev_bus(): -+ try: -+ camcontrol_b_out, err = util.subp(['camcontrol', 'devlist', '-b']) -+ except util.ProcessExecutionError: -+ LOG.debug("Fail to execute camcontrol devlist -b") -+ return None -+ return camcontrol_b_out -+ -+ -+def get_camcontrol_dev(): -+ try: -+ camcontrol_out, err = util.subp(['camcontrol', 'devlist']) -+ except util.ProcessExecutionError: -+ LOG.debug("Fail to execute camcontrol devlist") -+ return None -+ return camcontrol_out -+ -+ -+def get_resource_disk_on_freebsd(port_id): -+ g0 = "00000000" -+ if port_id > 1: -+ g0 = "00000001" -+ port_id = port_id - 2 -+ g1 = "000" + str(port_id) -+ g0g1 = "{0}-{1}".format(g0, g1) -+ """ -+ search 'X' from -+ 'dev.storvsc.X.%pnpinfo: -+ classid=32412632-86cb-44a2-9b5c-50d1417354f5 -+ deviceid=00000000-0001-8899-0000-000000000000' -+ """ -+ sysctl_out = get_dev_storvsc_sysctl() -+ -+ storvscid = find_storvscid_from_sysctl_pnpinfo(sysctl_out, g0g1) -+ if not storvscid: -+ LOG.debug("Fail to find storvsc id from sysctl") -+ return None -+ -+ camcontrol_b_out = get_camcontrol_dev_bus() -+ camcontrol_out = get_camcontrol_dev() -+ # try to find /dev/XX from 'blkvsc' device -+ blkvsc = "blkvsc{0}".format(storvscid) -+ scbusx = find_busdev_from_disk(camcontrol_b_out, blkvsc) -+ if scbusx: -+ devname = find_dev_from_busdev(camcontrol_out, scbusx) -+ if devname is None: -+ LOG.debug("Fail to find /dev/daX") -+ return None -+ return devname -+ # try to find /dev/XX from 'storvsc' device -+ storvsc = "storvsc{0}".format(storvscid) -+ scbusx = find_busdev_from_disk(camcontrol_b_out, storvsc) -+ if scbusx: -+ devname = find_dev_from_busdev(camcontrol_out, scbusx) -+ if devname is None: -+ LOG.debug("Fail to find /dev/daX") -+ return None -+ return devname -+ return None -+ -+# update the FreeBSD specific information -+if util.is_FreeBSD(): -+ DEFAULT_PRIMARY_NIC = 'hn0' -+ LEASE_FILE = '/var/db/dhclient.leases.hn0' -+ DEFAULT_FS = 'freebsd-ufs' -+ res_disk = get_resource_disk_on_freebsd(1) -+ if res_disk is not None: -+ LOG.debug("resource disk is not None") -+ RESOURCE_DISK_PATH = "/dev/" + res_disk -+ else: -+ LOG.debug("resource disk is None") -+ - BUILTIN_DS_CONFIG = { - 'agent_command': AGENT_START_BUILTIN, - 'data_dir': "/var/lib/waagent", - 'set_hostname': True, - 'hostname_bounce': { -- 'interface': 'eth0', -+ 'interface': DEFAULT_PRIMARY_NIC, - 'policy': True, - 'command': BOUNCE_COMMAND, - 'hostname_command': 'hostname', - }, - 'disk_aliases': {'ephemeral0': RESOURCE_DISK_PATH}, -- 'dhclient_lease_file': '/var/lib/dhcp/dhclient.eth0.leases', -+ 'dhclient_lease_file': LEASE_FILE, - } - - BUILTIN_CLOUD_CONFIG = { -@@ -53,7 +195,7 @@ BUILTIN_CLOUD_CONFIG = { - 'layout': [100], - 'overwrite': True}, - }, -- 'fs_setup': [{'filesystem': 'ext4', -+ 'fs_setup': [{'filesystem': DEFAULT_FS, - 'device': 'ephemeral0.1', - 'replace_fs': 'ntfs'}], - } -@@ -178,7 +320,11 @@ class DataSourceAzureNet(sources.DataSource): - for cdev in candidates: - try: - if cdev.startswith("/dev/"): -- ret = util.mount_cb(cdev, load_azure_ds_dir) -+ if util.is_FreeBSD(): -+ ret = util.mount_cb(cdev, load_azure_ds_dir, -+ mtype="udf", sync=False) -+ else: -+ ret = util.mount_cb(cdev, load_azure_ds_dir) - else: - ret = load_azure_ds_dir(cdev) - -@@ -206,11 +352,13 @@ class DataSourceAzureNet(sources.DataSource): - LOG.debug("using files cached in %s", ddir) - - # azure / hyper-v provides random data here -- seed = util.load_file("/sys/firmware/acpi/tables/OEM0", -- quiet=True, decode=False) -- if seed: -- self.metadata['random_seed'] = seed - -+ if not util.is_FreeBSD(): -+ seed = util.load_file("/sys/firmware/acpi/tables/OEM0", -+ quiet=True, decode=False) -+ if seed: -+ self.metadata['random_seed'] = seed -+ # TODO. find the seed on FreeBSD platform - # now update ds_cfg to reflect contents pass in config - user_ds_cfg = util.get_cfg_by_path(self.cfg, DS_CFG_PATH, {}) - self.ds_cfg = util.mergemanydict([user_ds_cfg, self.ds_cfg]) -@@ -619,8 +767,19 @@ def encrypt_pass(password, salt_id="$6$"): - def list_possible_azure_ds_devs(): - # return a sorted list of devices that might have a azure datasource - devlist = [] -- for fstype in ("iso9660", "udf"): -- devlist.extend(util.find_devs_with("TYPE=%s" % fstype)) -+ if util.is_FreeBSD(): -+ cdrom_dev = "/dev/cd0" -+ try: -+ util.subp(["mount", "-o", "ro", "-t", "udf", cdrom_dev, -+ "/mnt/cdrom/secure"]) -+ except util.ProcessExecutionError: -+ LOG.debug("Fail to mount cd") -+ return devlist -+ util.subp(["umount", "/mnt/cdrom/secure"]) -+ devlist.append(cdrom_dev) -+ else: -+ for fstype in ("iso9660", "udf"): -+ devlist.extend(util.find_devs_with("TYPE=%s" % fstype)) - - devlist.sort(reverse=True) - return devlist ---- cloudinit/sources/helpers/azure.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/sources/helpers/azure.py -@@ -29,6 +29,14 @@ def cd(newdir): - os.chdir(prevdir) - - -+def get_azure_endpoint(): -+ if util.is_FreeBSD(): -+ azure_endpoint = "option-245" -+ else: -+ azure_endpoint = "unknown-245" -+ return azure_endpoint -+ -+ - class AzureEndpointHttpClient(object): - - headers = { -@@ -236,7 +244,8 @@ class WALinuxAgentShim(object): - content = util.load_file(fallback_lease_file) - LOG.debug("content is %s", content) - for line in content.splitlines(): -- if 'unknown-245' in line: -+ azure_endpoint = get_azure_endpoint() -+ if azure_endpoint in line: - # Example line from Ubuntu - # option unknown-245 a8:3f:81:10; - leases.append(line.strip(' ').split(' ', 2)[-1].strip(';\n"')) ---- cloudinit/stages.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/stages.py -@@ -616,7 +616,7 @@ class Init(object): - return (None, loc) - if ncfg: - return (ncfg, loc) -- return (net.generate_fallback_config(), "fallback") -+ return (self.distro.generate_fallback_config(), "fallback") - - def apply_network_config(self, bring_up): - netcfg, src = self._find_networking_config() ---- cloudinit/util.py.orig 2016-12-23 16:37:45 UTC -+++ cloudinit/util.py -@@ -565,6 +565,10 @@ def is_ipv4(instr): - return len(toks) == 4 - - -+def is_FreeBSD(): -+ return system_info()['platform'].startswith('FreeBSD') -+ -+ - def get_cfg_option_bool(yobj, key, default=False): - if key not in yobj: - return default -@@ -2091,11 +2095,56 @@ def parse_mtab(path): - return None - - -+def find_freebsd_part(label_part): -+ if label_part.startswith("/dev/label/"): -+ target_label = label_part[5:] -+ (label_part, err) = subp(['glabel', 'status', '-s']) -+ for labels in label_part.split("\n"): -+ items = labels.split() -+ if len(items) > 0 and items[0].startswith(target_label): -+ label_part = items[2] -+ break -+ label_part = str(label_part) -+ return label_part -+ -+ -+def get_path_dev_freebsd(path, mnt_list): -+ path_found = None -+ for line in mnt_list.split("\n"): -+ items = line.split() -+ if (len(items) > 2 and os.path.exists(items[1] + path)): -+ path_found = line -+ break -+ return path_found -+ -+ -+def get_mount_info_freebsd(path, 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 -+ (mnt_list, err) = subp(['mount', '-p']) -+ path_found = get_path_dev_freebsd(path, mnt_list) -+ if (path_found is None): -+ return None -+ result = path_found -+ ret = result.split() -+ label_part = find_freebsd_part(ret[0]) -+ return "/dev/" + label_part, ret[2], ret[1] -+ -+ - 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) -+ if not m: -+ continue -+ # 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()): -+ return get_mount_info_freebsd(path) - devpth = m.group(1) - mount_point = m.group(2) - fs_type = m.group(3) -@@ -2357,7 +2406,8 @@ def read_dmi_data(key): - uname_arch = os.uname()[4] - if not (uname_arch == "x86_64" or - (uname_arch.startswith("i") and uname_arch[2:] == "86") or -- uname_arch == 'aarch64'): -+ uname_arch == 'aarch64' or -+ uname_arch == 'amd64'): - LOG.debug("dmidata is not supported on %s", uname_arch) - return None - ---- config/cloud.cfg-freebsd.orig 2016-12-23 16:37:45 UTC -+++ config/cloud.cfg-freebsd -@@ -5,7 +5,7 @@ syslog_fix_perms: root:wheel - - # This should not be required, but leave it in place until the real cause of - # not beeing able to find -any- datasources is resolved. --datasource_list: ['ConfigDrive', 'OpenStack', 'Ec2'] -+datasource_list: ['ConfigDrive', 'Azure', 'OpenStack', 'Ec2'] - - # A set of users which may be applied and/or used by various modules - # when a 'default' entry is found it will reference the 'default_user' ---- requirements.txt.orig 2016-12-23 16:37:45 UTC -+++ requirements.txt -@@ -28,7 +28,7 @@ configobj>=5.0.2 - pyyaml - - # The new main entrypoint uses argparse instead of optparse --argparse -+# argparse - - # Requests handles ssl correctly! - requests ---- setup.py.orig 2016-12-23 16:37:45 UTC -+++ setup.py -@@ -87,9 +87,9 @@ ETC = "/etc" - USR_LIB_EXEC = "/usr/lib" - LIB = "/lib" - if os.uname()[0] == 'FreeBSD': -+ ETC = "/usr/local/etc" - USR = "/usr/local" - USR_LIB_EXEC = "/usr/local/lib" -- ETC = "/usr/local/etc" - elif os.path.isfile('/etc/redhat-release'): - USR_LIB_EXEC = "/usr/libexec" - -@@ -166,8 +166,6 @@ else: - (ETC + '/cloud', glob('config/*.cfg')), - (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')), - (ETC + '/cloud/templates', glob('templates/*')), -- (ETC + '/NetworkManager/dispatcher.d/', ['tools/hook-network-manager']), -- (ETC + '/dhcp/dhclient-exit-hooks.d/', ['tools/hook-dhclient']), - (USR_LIB_EXEC + '/cloud-init', ['tools/uncloud-init', - 'tools/write-ssh-key-fingerprints']), - (USR + '/share/doc/cloud-init', [f for f in glob('doc/*') if is_f(f)]), -@@ -175,8 +173,13 @@ else: - [f for f in glob('doc/examples/*') if is_f(f)]), - (USR + '/share/doc/cloud-init/examples/seed', - [f for f in glob('doc/examples/seed/*') if is_f(f)]), -- (LIB + '/udev/rules.d', [f for f in glob('udev/*.rules')]), - ] -+ if os.uname()[0] != 'FreeBSD': -+ data_files.append([ -+ (ETC + '/NetworkManager/dispatcher.d/', ['tools/hook-network-manager']), -+ (ETC + '/dhcp/dhclient-exit-hooks.d/', ['tools/hook-dhclient']), -+ (LIB + '/udev/rules.d', [f for f in glob('udev/*.rules')]), -+ ]) - # Use a subclass for install that handles - # adding on the right init system configuration files - cmdclass = { -@@ -187,6 +190,9 @@ else: - requirements = read_requires() - if sys.version_info < (3,): - requirements.append('cheetah') -+if ((sys.version_info.major == 2 and sys.version_info.minor < 7) or -+ (sys.version_info.major == 3 and sys.version_info.minor < 2)): -+ requirements.append('argparse') - - setuptools.setup( - name='cloud-init', ---- sysvinit/freebsd/cloudconfig.orig 2016-12-23 16:37:45 UTC -+++ sysvinit/freebsd/cloudconfig -@@ -7,23 +7,13 @@ - . /etc/rc.subr - - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" --export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg - - name="cloudconfig" - command="/usr/local/bin/cloud-init" - start_cmd="cloudconfig_start" - stop_cmd=":" - rcvar="cloudinit_enable" --start_precmd="cloudinit_override" - start_cmd="cloudconfig_start" -- --cloudinit_override() --{ -- # If there exist sysconfig/defaults variable override files use it... -- if [ -f /etc/defaults/cloud-init ]; then -- . /etc/defaults/cloud-init -- fi --} - - cloudconfig_start() - { ---- sysvinit/freebsd/cloudfinal.orig 2016-12-23 16:37:45 UTC -+++ sysvinit/freebsd/cloudfinal -@@ -7,23 +7,13 @@ - . /etc/rc.subr - - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" --export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg - - name="cloudfinal" - command="/usr/local/bin/cloud-init" - start_cmd="cloudfinal_start" - stop_cmd=":" - rcvar="cloudinit_enable" --start_precmd="cloudinit_override" - start_cmd="cloudfinal_start" -- --cloudinit_override() --{ -- # If there exist sysconfig/defaults variable override files use it... -- if [ -f /etc/defaults/cloud-init ]; then -- . /etc/defaults/cloud-init -- fi --} - - cloudfinal_start() - { ---- sysvinit/freebsd/cloudinit.orig 2016-12-23 16:37:45 UTC -+++ sysvinit/freebsd/cloudinit -@@ -7,23 +7,13 @@ - . /etc/rc.subr - - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" --export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg - - name="cloudinit" - command="/usr/local/bin/cloud-init" - start_cmd="cloudinit_start" - stop_cmd=":" - rcvar="cloudinit_enable" --start_precmd="cloudinit_override" - start_cmd="cloudinit_start" -- --cloudinit_override() --{ -- # If there exist sysconfig/defaults variable override files use it... -- if [ -f /etc/defaults/cloud-init ]; then -- . /etc/defaults/cloud-init -- fi --} - - cloudinit_start() - { ---- sysvinit/freebsd/cloudinitlocal.orig 2016-12-23 16:37:45 UTC -+++ sysvinit/freebsd/cloudinitlocal -@@ -1,29 +1,19 @@ - #!/bin/sh - - # PROVIDE: cloudinitlocal --# REQUIRE: mountcritlocal -+# REQUIRE: ldconfig mountcritlocal - # BEFORE: NETWORKING FILESYSTEMS cloudinit cloudconfig cloudfinal - - . /etc/rc.subr - - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" --export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg - - name="cloudinitlocal" - command="/usr/local/bin/cloud-init" - start_cmd="cloudlocal_start" - stop_cmd=":" - rcvar="cloudinit_enable" --start_precmd="cloudinit_override" - start_cmd="cloudlocal_start" -- --cloudinit_override() --{ -- # If there exist sysconfig/defaults variable override files use it... -- if [ -f /etc/defaults/cloud-init ]; then -- . /etc/defaults/cloud-init -- fi --} - - cloudlocal_start() - { ---- tests/unittests/test_datasource/test_azure.py.orig 2016-12-23 16:37:45 UTC -+++ tests/unittests/test_datasource/test_azure.py -@@ -3,6 +3,8 @@ - from cloudinit import helpers - from cloudinit.util import b64e, decode_binary, load_file - from cloudinit.sources import DataSourceAzure -+from cloudinit.util import find_freebsd_part -+from cloudinit.util import get_path_dev_freebsd - - from ..helpers import TestCase, populate_dir, mock, ExitStack, PY26, SkipTest - -@@ -95,6 +97,41 @@ class TestAzureDataSource(TestCase): - for module, name, new in patches: - self.patches.enter_context(mock.patch.object(module, name, new)) - -+ def _get_mockds(self): -+ mod = DataSourceAzure -+ sysctl_out = "dev.storvsc.3.%pnpinfo: "\ -+ "classid=ba6163d9-04a1-4d29-b605-72e2ffb1dc7f "\ -+ "deviceid=f8b3781b-1e82-4818-a1c3-63d806ec15bb\n" -+ sysctl_out += "dev.storvsc.2.%pnpinfo: "\ -+ "classid=ba6163d9-04a1-4d29-b605-72e2ffb1dc7f "\ -+ "deviceid=f8b3781a-1e82-4818-a1c3-63d806ec15bb\n" -+ sysctl_out += "dev.storvsc.1.%pnpinfo: "\ -+ "classid=32412632-86cb-44a2-9b5c-50d1417354f5 "\ -+ "deviceid=00000000-0001-8899-0000-000000000000\n" -+ camctl_devbus = """ -+scbus0 on ata0 bus 0 -+scbus1 on ata1 bus 0 -+scbus2 on blkvsc0 bus 0 -+scbus3 on blkvsc1 bus 0 -+scbus4 on storvsc2 bus 0 -+scbus5 on storvsc3 bus 0 -+scbus-1 on xpt0 bus 0 -+ """ -+ camctl_dev = """ -+<Msft Virtual CD/ROM 1.0> at scbus1 target 0 lun 0 (cd0,pass0) -+<Msft Virtual Disk 1.0> at scbus2 target 0 lun 0 (da0,pass1) -+<Msft Virtual Disk 1.0> at scbus3 target 1 lun 0 (da1,pass2) -+ """ -+ self.apply_patches([ -+ (mod, 'get_dev_storvsc_sysctl', mock.MagicMock( -+ return_value=sysctl_out)), -+ (mod, 'get_camcontrol_dev_bus', mock.MagicMock( -+ return_value=camctl_devbus)), -+ (mod, 'get_camcontrol_dev', mock.MagicMock( -+ return_value=camctl_dev)) -+ ]) -+ return mod -+ - def _get_ds(self, data, agent_command=None): - - def dsdevs(): -@@ -176,6 +213,34 @@ class TestAzureDataSource(TestCase): - except AssertionError: - return - raise AssertionError("XML is the same") -+ -+ def test_get_resource_disk(self): -+ ds = self._get_mockds() -+ dev = ds.get_resource_disk_on_freebsd(1) -+ self.assertEqual("da1", dev) -+ -+ @mock.patch('cloudinit.util.subp') -+ def test_find_freebsd_part_on_Azure(self, mock_subp): -+ glabel_out = ''' -+gptid/fa52d426-c337-11e6-8911-00155d4c5e47 N/A da0p1 -+ label/rootfs N/A da0p2 -+ label/swap N/A da0p3 -+''' -+ mock_subp.return_value = (glabel_out, "") -+ res = find_freebsd_part("/dev/label/rootfs") -+ self.assertEqual("da0p2", res) -+ -+ def test_get_path_dev_freebsd_on_Azure(self): -+ mnt_list = ''' -+/dev/label/rootfs / ufs rw 1 1 -+devfs /dev devfs rw,multilabel 0 0 -+fdescfs /dev/fd fdescfs rw 0 0 -+/dev/da1s1 /mnt/resource ufs rw 2 2 -+''' -+ with mock.patch.object(os.path, 'exists', -+ return_value=True): -+ res = get_path_dev_freebsd('/etc', mnt_list) -+ self.assertNotEqual(res, None) - - def test_basic_seed_dir(self): - odata = {'HostName': "myhost", 'UserName': "myuser"} ---- tests/unittests/test_datasource/test_azure_helper.py.orig 2016-12-23 16:37:45 UTC -+++ tests/unittests/test_datasource/test_azure_helper.py -@@ -72,10 +72,11 @@ class TestFindEndpoint(TestCase): - - @staticmethod - def _build_lease_content(encoded_address): -+ endpoint = azure_helper.get_azure_endpoint() - return '\n'.join([ - 'lease {', - ' interface "eth0";', -- ' option unknown-245 {0};'.format(encoded_address), -+ ' option {0} {1};'.format(endpoint, encoded_address), - '}']) - - def test_from_dhcp_client(self): ---- tests/unittests/test_datasource/test_cloudstack.py.orig 2016-12-23 16:37:45 UTC -+++ tests/unittests/test_datasource/test_cloudstack.py -@@ -15,6 +15,11 @@ class TestCloudStackPasswordFetching(TestCase): - mod_name = 'cloudinit.sources.DataSourceCloudStack' - self.patches.enter_context(mock.patch('{0}.ec2'.format(mod_name))) - self.patches.enter_context(mock.patch('{0}.uhelp'.format(mod_name))) -+ default_gw = "192.201.20.0" -+ mod_name = 'cloudinit.sources.DataSourceCloudStack.get_default_gateway' -+ get_default_gw = mock.MagicMock(return_value=default_gw) -+ self.patches.enter_context( -+ mock.patch(mod_name, get_default_gw)) - - def _set_password_server_response(self, response_string): - subp = mock.MagicMock(return_value=(response_string, '')) ---- tests/unittests/test_distros/test_netconfig.py.orig 2016-12-23 16:37:45 UTC -+++ tests/unittests/test_distros/test_netconfig.py -@@ -83,6 +83,20 @@ class WriteBuffer(object): - - class TestNetCfgDistro(TestCase): - -+ frbsd_ifout = """\ -+hn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 -+ options=51b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,TSO4,LRO> -+ ether 00:15:5d:4c:73:00 -+ inet6 fe80::215:5dff:fe4c:7300%hn0 prefixlen 64 scopeid 0x2 -+ inet 10.156.76.127 netmask 0xfffffc00 broadcast 10.156.79.255 -+ nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL> -+ media: Ethernet autoselect (10Gbase-T <full-duplex>) -+ status: active -+""" -+ -+ def setUp(self): -+ super(TestNetCfgDistro, self).setUp() -+ - def _get_distro(self, dname): - cls = distros.fetch(dname) - cfg = settings.CFG_BUILTIN -@@ -126,6 +140,29 @@ class TestNetCfgDistro(TestCase): - self.assertIn(k, b1) - for (k, v) in b1.items(): - self.assertEqual(v, b2[k]) -+ -+ @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_list') -+ @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ifname_out') -+ def test_get_ip_nic_freebsd(self, ifname_out, iflist): -+ frbsd_distro = self._get_distro('freebsd') -+ iflist.return_value = "lo0 hn0" -+ ifname_out.return_value = self.frbsd_ifout -+ res = frbsd_distro.get_ipv4() -+ self.assertEqual(res, ['lo0', 'hn0']) -+ res = frbsd_distro.get_ipv6() -+ self.assertEqual(res, []) -+ -+ @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ether') -+ @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ifname_out') -+ @mock.patch('cloudinit.distros.freebsd.Distro.get_interface_mac') -+ def test_generate_fallback_config_freebsd(self, mac, ifname_out, if_ether): -+ frbsd_distro = self._get_distro('freebsd') -+ -+ if_ether.return_value = 'hn0' -+ ifname_out.return_value = self.frbsd_ifout -+ mac.return_value = '00:15:5d:4c:73:00' -+ res = frbsd_distro.generate_fallback_config() -+ self.assertIsNotNone(res) - - def test_simple_write_rh(self): - rh_distro = self._get_distro('rhel') ---- tests/unittests/test_util.py.orig 2016-12-23 16:37:45 UTC -+++ tests/unittests/test_util.py -@@ -567,7 +567,8 @@ class TestSubp(helpers.TestCase): - def test_subp_capture_stderr(self): - data = b'hello world' - (out, err) = util.subp(self.stdin2err, capture=True, -- decode=False, data=data) -+ decode=False, data=data, -+ update_env={'LC_ALL': 'C'}) - self.assertEqual(err, data) - self.assertEqual(out, b'') - ---- tools/build-on-freebsd.orig 2016-12-23 16:37:45 UTC -+++ tools/build-on-freebsd -@@ -3,16 +3,14 @@ - # installing cloud-init. This script takes care of building and installing. It - # will optionally make a first run at the end. - --fail() { echo "FAILED:" "$@" 1>&2; exit 1; } -+fail() { echo "FAILED:" "$@" 1>&2; exit 1;} - - # Check dependencies: - depschecked=/tmp/c-i.dependencieschecked - pkgs=" - dmidecode - e2fsprogs -- gpart - py27-Jinja2 -- py27-argparse - py27-boto - py27-cheetah - py27-configobj -@@ -38,7 +36,7 @@ python setup.py build - python setup.py install -O1 --skip-build --prefix /usr/local/ --init-system sysvinit_freebsd - - # Install the correct config file: --cp config/cloud.cfg-freebsd /usr/local/etc/cloud/cloud.cfg -+cp config/cloud.cfg-freebsd /etc/cloud/cloud.cfg - - # Enable cloud-init in /etc/rc.conf: - sed -i.bak -e "/cloudinit_enable=.*/d" /etc/rc.conf |
