def transport_iso9660(require_iso=True): # Go through mounts to see if it was already mounted mounts = util.mounts() for (dev, info) in mounts.items(): fstype = info['fstype'] if fstype != "iso9660" and require_iso: continue if not maybe_cdrom_device(dev): continue mp = info['mountpoint'] (_fname, contents) = get_ovf_env(mp) if contents is not False: return contents if require_iso: mtype = "iso9660" else: mtype = None # generate a list of devices with mtype filesystem, filter by regex devs = [dev for dev in util.find_devs_with("TYPE=%s" % mtype if mtype else None) if maybe_cdrom_device(dev)] for dev in devs: try: (_fname, contents) = util.mount_cb(dev, get_ovf_env, mtype=mtype) except util.MountFailedError: LOG.debug("%s not mountable as iso9660", dev) continue if contents is not False: return contents return None
def transport_iso9660(require_iso=True): # default_regex matches values in # /lib/udev/rules.d/60-cdrom_id.rules # KERNEL!="sr[0-9]*|hd[a-z]|xvd*", GOTO="cdrom_end" envname = "CLOUD_INIT_CDROM_DEV_REGEX" default_regex = "^(sr[0-9]+|hd[a-z]|xvd.*)" devname_regex = os.environ.get(envname, default_regex) cdmatch = re.compile(devname_regex) # Go through mounts to see if it was already mounted mounts = util.mounts() for (dev, info) in mounts.iteritems(): fstype = info['fstype'] if fstype != "iso9660" and require_iso: continue if cdmatch.match(dev[5:]) is None: # take off '/dev/' continue mp = info['mountpoint'] (fname, contents) = get_ovf_env(mp) if contents is not False: return (contents, dev, fname) if require_iso: mtype = "iso9660" else: mtype = None devs = os.listdir("/dev/") devs.sort() for dev in devs: fullp = os.path.join("/dev/", dev) if (fullp in mounts or not cdmatch.match(dev) or os.path.isdir(fullp)): continue try: # See if we can read anything at all...?? util.peek_file(fullp, 512) except IOError: continue try: (fname, contents) = util.mount_cb(fullp, get_ovf_env, mtype=mtype) except util.MountFailedError: LOG.debug("%s not mountable as iso9660" % fullp) continue if contents is not False: return (contents, fullp, fname) return (False, None, None)
def transport_iso9660(require_iso=True): # default_regex matches values in # /lib/udev/rules.d/60-cdrom_id.rules # KERNEL!="sr[0-9]*|hd[a-z]|xvd*", GOTO="cdrom_end" envname = "CLOUD_INIT_CDROM_DEV_REGEX" default_regex = "^(sr[0-9]+|hd[a-z]|xvd.*)" devname_regex = os.environ.get(envname, default_regex) cdmatch = re.compile(devname_regex) # Go through mounts to see if it was already mounted mounts = util.mounts() for (dev, info) in mounts.items(): fstype = info['fstype'] if fstype != "iso9660" and require_iso: continue if cdmatch.match(dev[5:]) is None: # take off '/dev/' continue mp = info['mountpoint'] (fname, contents) = get_ovf_env(mp) if contents is not False: return (contents, dev, fname) if require_iso: mtype = "iso9660" else: mtype = None devs = os.listdir("/dev/") devs.sort() for dev in devs: fullp = os.path.join("/dev/", dev) if (fullp in mounts or not cdmatch.match(dev) or os.path.isdir(fullp)): continue try: # See if we can read anything at all...?? util.peek_file(fullp, 512) except IOError: continue try: (fname, contents) = util.mount_cb(fullp, get_ovf_env, mtype=mtype) except util.MountFailedError: LOG.debug("%s not mountable as iso9660" % fullp) continue if contents is not False: return (contents, fullp, fname) return (False, None, None)
def support_new_ephemeral(cfg): """ Windows Azure makes ephemeral devices ephemeral to boot; a ephemeral device may be presented as a fresh device, or not. Since the knowledge of when a disk is supposed to be plowed under is specific to Windows Azure, the logic resides here in the datasource. When a new ephemeral device is detected, cloud-init overrides the default frequency for both disk-setup and mounts for the current boot only. """ device = find_fabric_formatted_ephemeral_part() if not device: LOG.debug("no default fabric formated ephemeral0.1 found") return None LOG.debug("fabric formated ephemeral0.1 device at %s", device) file_count = 0 try: file_count = util.mount_cb(device, count_files) except Exception: return None LOG.debug("fabric prepared ephmeral0.1 has %s files on it", file_count) if file_count >= 1: LOG.debug("fabric prepared ephemeral0.1 will be preserved") return None else: # if device was already mounted, then we need to unmount it # race conditions could allow for a check-then-unmount # to have a false positive. so just unmount and then check. try: util.subp(['umount', device]) except util.ProcessExecutionError as e: if device in util.mounts(): LOG.warn("Failed to unmount %s, will not reformat.", device) LOG.debug("Failed umount: %s", e) return None LOG.debug("cloud-init will format ephemeral0.1 this boot.") LOG.debug("setting disk_setup and mounts modules 'always' for this boot") cc_modules = cfg.get('cloud_config_modules') if not cc_modules: return None mod_list = [] for mod in cc_modules: if mod in ("disk_setup", "mounts"): mod_list.append([mod, PER_ALWAYS]) LOG.debug("set module '%s' to 'always' for this boot", mod) else: mod_list.append(mod) return mod_list
def support_new_ephemeral(cfg): """ Windows Azure makes ephemeral devices ephemeral to boot; a ephemeral device may be presented as a fresh device, or not. Since the knowledge of when a disk is supposed to be plowed under is specific to Windows Azure, the logic resides here in the datasource. When a new ephemeral device is detected, cloud-init overrides the default frequency for both disk-setup and mounts for the current boot only. """ device = find_ephemeral_part() if not device: LOG.debug("no default fabric formated ephemeral0.1 found") return None LOG.debug("fabric formated ephemeral0.1 device at %s", device) file_count = 0 try: file_count = util.mount_cb(device, count_files) except: return None LOG.debug("fabric prepared ephmeral0.1 has %s files on it", file_count) if file_count >= 1: LOG.debug("fabric prepared ephemeral0.1 will be preserved") return None else: # if device was already mounted, then we need to unmount it # race conditions could allow for a check-then-unmount # to have a false positive. so just unmount and then check. try: util.subp(['umount', device]) except util.ProcessExecutionError as e: if device in util.mounts(): LOG.warn("Failed to unmount %s, will not reformat.", device) LOG.debug("Failed umount: %s", e) return None LOG.debug("cloud-init will format ephemeral0.1 this boot.") LOG.debug("setting disk_setup and mounts modules 'always' for this boot") cc_modules = cfg.get('cloud_config_modules') if not cc_modules: return None mod_list = [] for mod in cc_modules: if mod in ("disk_setup", "mounts"): mod_list.append([mod, PER_ALWAYS]) LOG.debug("set module '%s' to 'always' for this boot", mod) else: mod_list.append(mod) return mod_list
def handle(_name, cfg, cloud, log, _args): # fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno def_mnt_opts = "defaults,nobootwait" uses_systemd = cloud.distro.uses_systemd() if uses_systemd: def_mnt_opts = "defaults,nofail,x-systemd.requires=cloud-init.service" defvals = [None, None, "auto", def_mnt_opts, "0", "2"] defvals = cfg.get("mount_default_fields", defvals) # these are our default set of mounts defmnts = [["ephemeral0", "/mnt", "auto", defvals[3], "0", "2"], ["swap", "none", "swap", "sw", "0", "0"]] cfgmnt = [] if "mounts" in cfg: cfgmnt = cfg["mounts"] LOG.debug("mounts configuration is %s", cfgmnt) fstab_lines = [] fstab_devs = {} fstab_removed = [] for line in util.load_file(FSTAB_PATH).splitlines(): if MNT_COMMENT in line: fstab_removed.append(line) continue try: toks = WS.split(line) except Exception: pass fstab_devs[toks[0]] = line fstab_lines.append(line) for i in range(len(cfgmnt)): # skip something that wasn't a list if not isinstance(cfgmnt[i], list): log.warning("Mount option %s not a list, got a %s instead", (i + 1), type_utils.obj_name(cfgmnt[i])) continue start = str(cfgmnt[i][0]) sanitized = sanitize_devname(start, cloud.device_name_to_device, log) if sanitized != start: log.debug("changed %s => %s" % (start, sanitized)) if sanitized is None: log.debug("Ignoring nonexistent named mount %s", start) continue elif sanitized in fstab_devs: log.info("Device %s already defined in fstab: %s", sanitized, fstab_devs[sanitized]) continue cfgmnt[i][0] = sanitized # in case the user did not quote a field (likely fs-freq, fs_passno) # but do not convert None to 'None' (LP: #898365) for j in range(len(cfgmnt[i])): if cfgmnt[i][j] is None: continue else: cfgmnt[i][j] = str(cfgmnt[i][j]) for i in range(len(cfgmnt)): # fill in values with defaults from defvals above for j in range(len(defvals)): if len(cfgmnt[i]) <= j: cfgmnt[i].append(defvals[j]) elif cfgmnt[i][j] is None: cfgmnt[i][j] = defvals[j] # if the second entry in the list is 'None' this # clears all previous entries of that same 'fs_spec' # (fs_spec is the first field in /etc/fstab, ie, that device) if cfgmnt[i][1] is None: for j in range(i): if cfgmnt[j][0] == cfgmnt[i][0]: cfgmnt[j][1] = None # for each of the "default" mounts, add them only if no other # entry has the same device name for defmnt in defmnts: start = defmnt[0] sanitized = sanitize_devname(start, cloud.device_name_to_device, log) if sanitized != start: log.debug("changed default device %s => %s" % (start, sanitized)) if sanitized is None: log.debug("Ignoring nonexistent default named mount %s", start) continue elif sanitized in fstab_devs: log.debug("Device %s already defined in fstab: %s", sanitized, fstab_devs[sanitized]) continue defmnt[0] = sanitized cfgmnt_has = False for cfgm in cfgmnt: if cfgm[0] == defmnt[0]: cfgmnt_has = True break if cfgmnt_has: log.debug(("Not including %s, already" " previously included"), start) continue cfgmnt.append(defmnt) # now, each entry in the cfgmnt list has all fstab values # if the second field is None (not the string, the value) we skip it actlist = [] for x in cfgmnt: if x[1] is None: log.debug("Skipping nonexistent device named %s", x[0]) else: actlist.append(x) swapret = handle_swapcfg(cfg.get('swap', {})) if swapret: actlist.append([swapret, "none", "swap", "sw", "0", "0"]) if len(actlist) == 0: log.debug("No modifications to fstab needed") return cc_lines = [] needswap = False need_mount_all = False dirs = [] for line in actlist: # write 'comment' in the fs_mntops, entry, claiming this line[3] = "%s,%s" % (line[3], MNT_COMMENT) if line[2] == "swap": needswap = True if line[1].startswith("/"): dirs.append(line[1]) cc_lines.append('\t'.join(line)) mount_points = [ v['mountpoint'] for k, v in util.mounts().items() if 'mountpoint' in v ] for d in dirs: try: util.ensure_dir(d) except Exception: util.logexc(log, "Failed to make '%s' config-mount", d) # dirs is list of directories on which a volume should be mounted. # If any of them does not already show up in the list of current # mount points, we will definitely need to do mount -a. if not need_mount_all and d not in mount_points: need_mount_all = True sadds = [WS.sub(" ", n) for n in cc_lines] sdrops = [WS.sub(" ", n) for n in fstab_removed] sops = (["- " + drop for drop in sdrops if drop not in sadds] + ["+ " + add for add in sadds if add not in sdrops]) fstab_lines.extend(cc_lines) contents = "%s\n" % ('\n'.join(fstab_lines)) util.write_file(FSTAB_PATH, contents) activate_cmds = [] if needswap: activate_cmds.append(["swapon", "-a"]) if len(sops) == 0: log.debug("No changes to /etc/fstab made.") else: log.debug("Changes to fstab: %s", sops) need_mount_all = True if need_mount_all: activate_cmds.append(["mount", "-a"]) if uses_systemd: activate_cmds.append(["systemctl", "daemon-reload"]) fmt = "Activating swap and mounts with: %s" for cmd in activate_cmds: fmt = "Activate mounts: %s:" + ' '.join(cmd) try: util.subp(cmd) log.debug(fmt, "PASS") except util.ProcessExecutionError: log.warning(fmt, "FAIL") util.logexc(log, fmt, "FAIL")
def handle(_name, cfg, cloud, log, _args): # fs_spec, fs_file, fs_vfstype, fs_mntops, fs-freq, fs_passno def_mnt_opts = "defaults,nobootwait" uses_systemd = cloud.distro.uses_systemd() if uses_systemd: def_mnt_opts = "defaults,nofail,x-systemd.requires=cloud-init.service" defvals = [None, None, "auto", def_mnt_opts, "0", "2"] defvals = cfg.get("mount_default_fields", defvals) # these are our default set of mounts defmnts = [["ephemeral0", "/mnt", "auto", defvals[3], "0", "2"], ["swap", "none", "swap", "sw", "0", "0"]] cfgmnt = [] if "mounts" in cfg: cfgmnt = cfg["mounts"] LOG.debug("mounts configuration is %s", cfgmnt) fstab_lines = [] fstab_devs = {} fstab_removed = [] for line in util.load_file(FSTAB_PATH).splitlines(): if MNT_COMMENT in line: fstab_removed.append(line) continue try: toks = WS.split(line) except Exception: pass fstab_devs[toks[0]] = line fstab_lines.append(line) for i in range(len(cfgmnt)): # skip something that wasn't a list if not isinstance(cfgmnt[i], list): log.warn("Mount option %s not a list, got a %s instead", (i + 1), type_utils.obj_name(cfgmnt[i])) continue start = str(cfgmnt[i][0]) sanitized = sanitize_devname(start, cloud.device_name_to_device, log) if sanitized != start: log.debug("changed %s => %s" % (start, sanitized)) if sanitized is None: log.debug("Ignoring nonexistent named mount %s", start) continue elif sanitized in fstab_devs: log.info("Device %s already defined in fstab: %s", sanitized, fstab_devs[sanitized]) continue cfgmnt[i][0] = sanitized # in case the user did not quote a field (likely fs-freq, fs_passno) # but do not convert None to 'None' (LP: #898365) for j in range(len(cfgmnt[i])): if cfgmnt[i][j] is None: continue else: cfgmnt[i][j] = str(cfgmnt[i][j]) for i in range(len(cfgmnt)): # fill in values with defaults from defvals above for j in range(len(defvals)): if len(cfgmnt[i]) <= j: cfgmnt[i].append(defvals[j]) elif cfgmnt[i][j] is None: cfgmnt[i][j] = defvals[j] # if the second entry in the list is 'None' this # clears all previous entries of that same 'fs_spec' # (fs_spec is the first field in /etc/fstab, ie, that device) if cfgmnt[i][1] is None: for j in range(i): if cfgmnt[j][0] == cfgmnt[i][0]: cfgmnt[j][1] = None # for each of the "default" mounts, add them only if no other # entry has the same device name for defmnt in defmnts: start = defmnt[0] sanitized = sanitize_devname(start, cloud.device_name_to_device, log) if sanitized != start: log.debug("changed default device %s => %s" % (start, sanitized)) if sanitized is None: log.debug("Ignoring nonexistent default named mount %s", start) continue elif sanitized in fstab_devs: log.debug("Device %s already defined in fstab: %s", sanitized, fstab_devs[sanitized]) continue defmnt[0] = sanitized cfgmnt_has = False for cfgm in cfgmnt: if cfgm[0] == defmnt[0]: cfgmnt_has = True break if cfgmnt_has: log.debug(("Not including %s, already" " previously included"), start) continue cfgmnt.append(defmnt) # now, each entry in the cfgmnt list has all fstab values # if the second field is None (not the string, the value) we skip it actlist = [] for x in cfgmnt: if x[1] is None: log.debug("Skipping nonexistent device named %s", x[0]) else: actlist.append(x) swapret = handle_swapcfg(cfg.get('swap', {})) if swapret: actlist.append([swapret, "none", "swap", "sw", "0", "0"]) if len(actlist) == 0: log.debug("No modifications to fstab needed") return cc_lines = [] needswap = False need_mount_all = False dirs = [] for line in actlist: # write 'comment' in the fs_mntops, entry, claiming this line[3] = "%s,%s" % (line[3], MNT_COMMENT) if line[2] == "swap": needswap = True if line[1].startswith("/"): dirs.append(line[1]) cc_lines.append('\t'.join(line)) mount_points = [v['mountpoint'] for k, v in util.mounts().items() if 'mountpoint' in v] for d in dirs: try: util.ensure_dir(d) except Exception: util.logexc(log, "Failed to make '%s' config-mount", d) # dirs is list of directories on which a volume should be mounted. # If any of them does not already show up in the list of current # mount points, we will definitely need to do mount -a. if not need_mount_all and d not in mount_points: need_mount_all = True sadds = [WS.sub(" ", n) for n in cc_lines] sdrops = [WS.sub(" ", n) for n in fstab_removed] sops = (["- " + drop for drop in sdrops if drop not in sadds] + ["+ " + add for add in sadds if add not in sdrops]) fstab_lines.extend(cc_lines) contents = "%s\n" % ('\n'.join(fstab_lines)) util.write_file(FSTAB_PATH, contents) activate_cmds = [] if needswap: activate_cmds.append(["swapon", "-a"]) if len(sops) == 0: log.debug("No changes to /etc/fstab made.") else: log.debug("Changes to fstab: %s", sops) need_mount_all = True if need_mount_all: activate_cmds.append(["mount", "-a"]) if uses_systemd: activate_cmds.append(["systemctl", "daemon-reload"]) fmt = "Activating swap and mounts with: %s" for cmd in activate_cmds: fmt = "Activate mounts: %s:" + ' '.join(cmd) try: util.subp(cmd) log.debug(fmt, "PASS") except util.ProcessExecutionError: log.warn(fmt, "FAIL") util.logexc(log, fmt, "FAIL")