Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
Massive refactor of ioc_fstab
Browse files Browse the repository at this point in the history
- Create reusable single instance of fstab
- Validates fstab before loading it now (unless using list, that's for users to spot the issues themselves)
- Check for duplicate entries
- Check if destination exists
- Check if source/destination is a directory
- Check if source/destination is an absolute path
- Check if dump/pass are single proper integers

Closes #702
  • Loading branch information
Brandon Schneider committed Dec 5, 2018
1 parent c363f0b commit 4cc8ec2
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 47 deletions.
4 changes: 4 additions & 0 deletions iocage_lib/ioc_exceptions.py
Expand Up @@ -60,3 +60,7 @@ class JailCorruptConfiguration(JailMisconfigured):

class JailMissingConfiguration(JailMisconfigured):
pass


class ValidationFailed(ExceptionWithMsg):
pass
206 changes: 159 additions & 47 deletions iocage_lib/ioc_fstab.py
Expand Up @@ -27,10 +27,12 @@
import shutil
import subprocess as su
import tempfile
import pathlib

import iocage_lib.ioc_common
import iocage_lib.ioc_json
import iocage_lib.ioc_list
import iocage_lib.ioc_exceptions
import texttable


Expand Down Expand Up @@ -61,41 +63,155 @@ def __init__(self, uuid, action, source, destination, fstype, fsoptions,
self.callback = callback

if action != "list":
self.fstab = list(self.__read_fstab__())
self.dests = self.__validate_fstab__(self.fstab, 'all')
self.__fstab_parse__()

def __fstab_parse__(self):
"""
Checks which action the user is asking for and calls the
appropriate methods.
"""
actions = ['add', 'remove', 'edit', 'replace']

if self.action not in actions:
raise RuntimeError("Type of operation not specified!")

if self.action == "add":
self.__validate_fstab__([self.mount])
self.__fstab_add__()
self.__fstab_mount__()

try:
self.__fstab_mount__()
except RuntimeError:
iocage_lib.ioc_common.logit({
'level': 'WARNING',
'message': 'Mounting entry failed, check \'mount\''
},
_callback=self.callback,
silent=self.silent
)
elif self.action == "remove":
dest = self.__fstab_remove__()
self.__fstab_umount__(dest)

try:
self.__fstab_umount__(dest)
except RuntimeError:
iocage_lib.ioc_common.logit({
'level': 'WARNING',
'message': 'Unmounting entry failed, check \'mount\''
},
_callback=self.callback,
silent=self.silent
)
elif self.action == "edit":
self.__fstab_edit__()
elif self.action == "replace":
self.__validate_fstab__([self.mount])
self.__fstab_edit__(_string=True)
self.__fstab_mount__()
else:
raise RuntimeError("Type of operation not specified!")

def __read_fstab__(self):
with open(f"{self.iocroot}/jails/{self.uuid}/fstab", "r") as f:
for line in f:
yield line.rstrip()

def __get_fstab_dests_(self):
dests = []

for line in self.fstab:
source, destination, fstype, options, \
dump, _pass = line.split()[0:6]
dests.append(destination)

return dests

def __validate_fstab__(self, fstab, mode='single'):
dests = []
verrors = []
jail_root = f'{self.iocroot}/jails/{self.uuid}/root'

for line in fstab:
source, destination, fstype, options, \
dump, _pass = line.split()[0:6]
source = pathlib.Path(source)
missing_root = False
dest = pathlib.Path(destination)

if mode != 'all' and (
self.action == 'add' or self.action == 'replace'
):
if destination in self.dests:
verrors.append(f'Destination: {self.dest} already exists!')
break

if jail_root not in self.dest:
verrors.append(
f'Destination: {self.dest} must include '
f'jail\'s mountpoint! ({jail_root})'
)
break
else:
if jail_root not in destination:
verrors.append(
f'Destination: {destination} does not include '
f'jail\'s mountpoint! ({jail_root})'
)
missing_root = True

if not source.is_dir():
verrors.append(f'Source: {source} does not exist!')
if not source.is_absolute():
verrors.append(f'Source: {source} must use an absolute path!')

if not missing_root:
if not dest.is_dir():
verrors.append(f'Destination: {dest} does not exist!')
if not dest.is_absolute():
verrors.append(
f'Destination: {dest} must use an absolute path!'
)

if not dump.isdecimal():
verrors.append(
f'Dump: {dump} must be a digit!'
)
if len(dump) > 1:
verrors.append(
f'Dump: {dump} must be one digit long!'
)
if not _pass.isdecimal():
verrors.append(
f'Pass: {_pass} must be a digit!'
)
if len(_pass) > 1:
verrors.append(
f'Pass: {_pass} must be one digit long!'
)
dests.append(destination)

if verrors:
iocage_lib.ioc_common.logit({
'level': 'EXCEPTION',
'message': verrors
},
_callback=self.callback,
exception=iocage_lib.ioc_exceptions.ValidationFailed
)

return dests

def __fstab_add__(self):
"""Adds a users mount to the jails fstab"""
with open(f"{self.iocroot}/jails/{self.uuid}/fstab", "r") as fstab:
with iocage_lib.ioc_common.open_atomic(
f"{self.iocroot}/jails/{self.uuid}/fstab",
"w") as _fstab:
# open_atomic will empty the file, we need these still.
with iocage_lib.ioc_common.open_atomic(
f'{self.iocroot}/jails/{self.uuid}/fstab',
'w'
) as fstab:
for line in self.fstab:
fstab.write(f'{line}\n')

for line in fstab.readlines():
_fstab.write(line)

date = datetime.datetime.utcnow().strftime("%F %T")
_fstab.write(f"{self.mount} # Added by iocage on {date}\n")
date = datetime.datetime.utcnow().strftime("%F %T")
fstab.write(f"{self.mount} # Added by iocage on {date}\n")

iocage_lib.ioc_common.logit({
"level": "INFO",
Expand All @@ -113,21 +229,19 @@ def __fstab_remove__(self):
removed = False
index = 0

with open(f"{self.iocroot}/jails/{self.uuid}/fstab", "r") as fstab:
with iocage_lib.ioc_common.open_atomic(
f"{self.iocroot}/jails/{self.uuid}/fstab",
"w") as _fstab:

for line in fstab.readlines():
if line.rsplit("#")[0].rstrip() == self.mount or index \
== self.index and not removed:
removed = True
dest = line.split()[1]
with iocage_lib.ioc_common.open_atomic(
f"{self.iocroot}/jails/{self.uuid}/fstab",
"w") as fstab:
for line in self.fstab:
if line.rsplit("#")[0].rstrip() == self.mount or index \
== self.index and not removed:
removed = True
dest = line.split()[1]

continue
continue

_fstab.write(line)
index += 1
fstab.write(line)
index += 1

if removed:
iocage_lib.ioc_common.logit({
Expand Down Expand Up @@ -191,26 +305,24 @@ def __fstab_edit__(self, _string=False):

if _string:
matched = False

with open(jail_fstab, "r") as fstab:
with iocage_lib.ioc_common.open_atomic(
jail_fstab, "w") as _fstab:

for i, line in enumerate(fstab.readlines()):
if i == self.index:
date = datetime.datetime.utcnow().strftime("%F %T")
_fstab.write(
f"{self.mount} # Added by iocage on {date}\n")
matched = True

iocage_lib.ioc_common.logit({
"level": "INFO",
"message": f"Index {self.index} replaced."
},
_callback=self.callback,
silent=self.silent)
else:
_fstab.write(line)
with iocage_lib.ioc_common.open_atomic(
jail_fstab, "w") as fstab:

for i, line in enumerate(self.fstab):
if i == self.index:
date = datetime.datetime.utcnow().strftime("%F %T")
fstab.write(
f"{self.mount} # Added by iocage on {date}\n")
matched = True

iocage_lib.ioc_common.logit({
"level": "INFO",
"message": f"Index {self.index} replaced."
},
_callback=self.callback,
silent=self.silent)
else:
fstab.write(line)

if not matched:
iocage_lib.ioc_common.logit({
Expand Down

0 comments on commit 4cc8ec2

Please sign in to comment.