Skip to content

Commit

Permalink
Move functions to parent, set properties easily
Browse files Browse the repository at this point in the history
  • Loading branch information
johnramsden committed Jun 3, 2018
1 parent 341f6fd commit f1721be
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 122 deletions.
142 changes: 135 additions & 7 deletions zedenv/plugins/configuration.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import shutil
import os
import re

import click
import zedenv.lib.be
from zedenv.lib.logger import ZELogger

allowed_keys = (
Expand Down Expand Up @@ -30,13 +33,39 @@ def __init__(self, zedenv_data: dict):
self.noop = zedenv_data['noop']
self.be_root = zedenv_data['boot_environment_root']

def recurse_move(self, source, dest):
self.zedenv_properties = {}

def plugin_property_error(self, prop):
ZELogger.log({
"level": "EXCEPTION",
"message": (f"To use the {self.bootloader} plugin, use default{prop}, or set props\n"
f"To set it use the command (replacing with your pool and dataset)\n'"
f"zfs set org.zedenv:{prop}='<new mount>' zpool/ROOT/default\n")
}, exit_on_error=True)

def check_zedenv_properties(self):
"""
Get zedenv properties in format:
{"property": <property val>}
If prop unset, leave default
"""
for prop in self.zedenv_properties:
prop_val = zedenv.lib.be.get_property(
"/".join([self.be_root, self.boot_environment]),
f"org.zedenv:{prop}")

if prop_val is not None and prop_val != "-":
self.zedenv_properties[prop] = prop_val

ZELogger.log({"level": "INFO", "message": f"Found: {prop}"})

def recurse_move(self, source, dest, overwrite=False):
for tf in os.listdir(source):
tf_path_src = os.path.join(source, tf)
tf_path_dst = os.path.join(dest, tf)

if os.path.isfile(tf_path_src):
if os.path.isfile(tf_path_dst):
if os.path.isfile(tf_path_dst) and not overwrite:
ZELogger.verbose_log({
"level": "INFO",
"message": f"File {tf_path_dst} already exists, will not modify.\n"
Expand All @@ -47,25 +76,30 @@ def recurse_move(self, source, dest):
except PermissionError:
ZELogger.log({
"level": "EXCEPTION",
"message": (f"Require Privileges to write to "
f"'{tf_path_dst}.bak'\n")

"message": f"Require Privileges to write to '{tf_path_dst}.'\n"
}, exit_on_error=True)
ZELogger.verbose_log({
"level": "INFO",
"message": f"Copied file {tf_path_src} -> {tf_path_dst}\n"
}, self.verbose)
elif os.path.isdir(tf_path_src):
if os.path.isdir(tf_path_dst):
if os.path.isdir(tf_path_dst) and not overwrite:
ZELogger.verbose_log({
"level": "INFO",
"message": f"Directory {tf_path_dst} already exists, will not modify.\n"
}, self.verbose)

# Call again, may be empty
self.recurse_move(tf_path_src, tf_path_dst)
self.recurse_move(tf_path_src, tf_path_dst, overwrite=overwrite)

else:
if os.path.isdir(tf_path_dst):
shutil.move(tf_path_dst, f"{tf_path_dst}.bak")
ZELogger.verbose_log({
"level": "INFO",
"message": (f"Directory {tf_path_dst} already exists, "
f"creating backup {tf_path_dst}.bak.\n")
}, self.verbose)
try:
shutil.copytree(tf_path_src, tf_path_dst)
except PermissionError as e:
Expand All @@ -83,6 +117,100 @@ def recurse_move(self, source, dest):
"message": f"Copied dir {tf_path_src} -> {tf_path_dst}\n"
}, self.verbose)

def modify_fstab(self, be_mountpoint: str, replace_pattern: str, new_entry: str):
"""
Modify fstab, changing pattern.
"""

be_fstab = os.path.join(be_mountpoint, "etc/fstab")
temp_fstab = os.path.join(be_mountpoint, "fstab.zedenv.new")

try:
shutil.copy(be_fstab, temp_fstab)
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {temp_fstab}\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {temp_fstab}\n{e}"
}, exit_on_error=True)

target = re.compile(replace_pattern)

"""
Find match for: $esp/$env_dir/$boot_environment $boot_location <fstab stuff>
eg: /mnt/efi/env/default-3 /boot none rw,defaults,bind 0 0
"""

with open(temp_fstab) as in_f:
lines = in_f.readlines()

match = next(
((i, target.search(m)) for i, m in enumerate(lines) if target.search(m)), None)

"""
Replace BE name with new one
"""

if match:
old_fstab_entry = lines[match[0]]
new_fstab_entry = re.sub(
replace_pattern, r"\1" + new_entry + r"\3", lines[match[0]])

lines[match[0]] = new_fstab_entry

with open(temp_fstab, 'w') as out_f:
out_f.writelines(lines)
else:
ZELogger.log({
"level": "INFO",
"message": (f"Couldn't find bindmounted directory to replace, your system "
"may not be configured for boot environments with systemdboot.")
})

if not self.noop:
try:
shutil.copy(be_fstab, f"{be_fstab}.bak")
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {be_fstab}.bak\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {be_fstab}.bak\n{e}"
}, exit_on_error=True)

if not self.noconfirm:
if click.confirm(
"Would you like to edit the generated 'fstab'?", default=True):
click.edit(filename=temp_fstab)

try:
shutil.copy(temp_fstab, be_fstab)
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {be_fstab}\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {be_fstab}\n{e}"
}, exit_on_error=True)

ZELogger.log({
"level": "INFO",
"message": (f"Replaced fstab entry:\n{old_fstab_entry}\nWith new entry:\n"
f"{new_fstab_entry}\nIn the boot environment's "
f"'/etc/fstab'. A copy of the original "
"'/etc/fstab' can be found at '/etc/fstab.bak'.\n")
})

def post_activate(self):
pass

Expand Down
132 changes: 17 additions & 115 deletions zedenv/plugins/systemdboot.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,127 +28,25 @@ def __init__(self, zedenv_data: dict):
self.old_entry = f"{self.entry_prefix}-{self.old_boot_environment}"
self.new_entry = f"{self.entry_prefix}-{self.boot_environment}"

esp = zedenv.lib.be.get_property(
"/".join([self.be_root, self.boot_environment]), "org.zedenv:esp")
if esp is None or esp == "-":
self.esp = "/mnt/efi"
else:
self.esp = esp
# Set defaults
self.zedenv_properties["esp"] = "/mnt/efi"

self.check_zedenv_properties()

ZELogger.verbose_log({
"level": "INFO",
"message": f"esp set to {esp}\n"
"message": f"esp set to {self.zedenv_properties['esp']}\n"
}, self.verbose)

if not os.path.isdir(self.esp):
ZELogger.log({
"level": "EXCEPTION",
"message": ("To use the systemdboot plugin, an 'esp' must be mounted at the "
"default location of `/mnt/esp`, or at another location, with the "
"property 'org.zedenv:esp' set on the dataset. To set it use the "
"command (replacing with your pool and dataset)\n'"
"zfs set org.zedenv:esp='/mnt/efi' zpool/ROOT/default\n")
}, exit_on_error=True)

def modify_fstab(self, be_mountpoint: str):

be_fstab = os.path.join(be_mountpoint, "etc/fstab")
temp_fstab = os.path.join(be_mountpoint, "fstab.zedenv.new")

try:
shutil.copy(be_fstab, temp_fstab)
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {temp_fstab}\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {temp_fstab}\n{e}"
}, exit_on_error=True)

replace_pattern = r'(^{esp}/{env}/?)(.*)(\s.*{boot}\s.*$)'.format(
esp=self.esp, env=self.env_dir, boot=self.boot_mountpoint)

target = re.compile(replace_pattern)

"""
Find match for: $esp/$env_dir/$boot_environment $boot_location <fstab stuff>
eg: /mnt/efi/env/default-3 /boot none rw,defaults,bind 0 0
"""

with open(temp_fstab) as in_f:
lines = in_f.readlines()

match = next(
((i, target.search(m)) for i, m in enumerate(lines) if target.search(m)), None)

"""
Replace BE name with new one
"""

if match:
old_fstab_entry = lines[match[0]]
new_fstab_entry = re.sub(
replace_pattern, r"\1" + self.new_entry + r"\3", lines[match[0]])

lines[match[0]] = new_fstab_entry

with open(temp_fstab, 'w') as out_f:
out_f.writelines(lines)
else:
ZELogger.log({
"level": "INFO",
"message": (f"Couldn't find bindmounted directory to replace, your system "
"may not be configured for boot environments with systemdboot.")
})

if not self.noop:
try:
shutil.copy(be_fstab, f"{be_fstab}.bak")
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {be_fstab}.bak\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {be_fstab}.bak\n{e}"
}, exit_on_error=True)

if not self.noconfirm:
if click.confirm(
"Would you like to edit the generated 'fstab'?", default=True):
click.edit(filename=temp_fstab)

try:
shutil.copy(temp_fstab, be_fstab)
except PermissionError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"Require Privileges to write to {be_fstab}\n{e}"
}, exit_on_error=True)
except IOError as e:
ZELogger.log({
"level": "EXCEPTION",
"message": f"IOError writing to {be_fstab}\n{e}"
}, exit_on_error=True)

ZELogger.log({
"level": "INFO",
"message": (f"Replaced fstab entry:\n{old_fstab_entry}\nWith new entry:\n"
f"{new_fstab_entry}\nIn the boot environment's "
f"'/etc/fstab'. A copy of the original "
"'/etc/fstab' can be found at '/etc/fstab.bak'.\n")
})
if not os.path.isdir(self.zedenv_properties["esp"]):
self.plugin_property_error(self.zedenv_properties)

def edit_bootloader_entry(self, temp_esp: str):
temp_entries_dir = os.path.join(temp_esp, "loader/entries")
temp_bootloader_file = os.path.join(temp_entries_dir,
f"{self.new_entry}.conf")

real_entries_dir = os.path.join(self.esp, "loader/entries")
real_entries_dir = os.path.join(self.zedenv_properties["esp"], "loader/entries")
real_bootloader_file = os.path.join(
real_entries_dir, f"{self.old_entry}.conf")

Expand Down Expand Up @@ -232,7 +130,7 @@ def edit_bootloader_entry(self, temp_esp: str):

def modify_bootloader(self, temp_esp: str,):

real_kernel_dir = os.path.join(self.esp, "env")
real_kernel_dir = os.path.join(self.zedenv_properties["esp"], "env")
temp_kernel_dir = os.path.join(temp_esp, "env")

real_old_dataset_kernel = os.path.join(real_kernel_dir, self.old_entry)
Expand Down Expand Up @@ -275,7 +173,7 @@ def modify_bootloader(self, temp_esp: str,):
}, exit_on_error=True)

def edit_bootloader_default(self, temp_esp: str, overwrite: bool):
real_loader_dir_path = os.path.join(self.esp, "loader")
real_loader_dir_path = os.path.join(self.zedenv_properties["esp"], "loader")
temp_loader_dir_path = os.path.join(temp_esp, "loader")

real_loader_conf_path = os.path.join(real_loader_dir_path, "loader.conf")
Expand Down Expand Up @@ -381,7 +279,7 @@ def post_activate(self):

self.edit_bootloader_entry(t_esp)

self.recurse_move(t_esp, self.esp)
self.recurse_move(t_esp, self.zedenv_properties["esp"])

self.edit_bootloader_default(t_esp, overwrite=True)

Expand All @@ -392,4 +290,8 @@ def mid_activate(self, be_mountpoint: str):
"level": "INFO",
"message": f"Running {self.bootloader} mid activate.\n"
}, self.verbose)
self.modify_fstab(be_mountpoint)

replace_pattern = r'(^{esp}/{env}/?)(.*)(\s.*{boot}\s.*$)'.format(
esp=self.zedenv_properties["esp"], env=self.env_dir, boot=self.boot_mountpoint)

self.modify_fstab(be_mountpoint, replace_pattern, self.new_entry)

0 comments on commit f1721be

Please sign in to comment.