|
|
|
@ -13,13 +13,14 @@ import shutil
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
template_text = '''{% calculate append = 'join' -%}
|
|
|
|
|
{% calculate package = 'dev-lang/python', format = 'samba' -%}
|
|
|
|
|
{% calculate package = 'test-category/test-package', format = 'samba' -%}
|
|
|
|
|
[section one]
|
|
|
|
|
parameter_1 = {{ vars_1.value_1 }}
|
|
|
|
|
!parameter_2
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
backup_template_text = '''{% calculate append = 'join', format = 'samba' -%}
|
|
|
|
|
backup_template_text = '''{% calculate append = 'join', format = 'samba',
|
|
|
|
|
autoupdate -%}
|
|
|
|
|
[section one]
|
|
|
|
|
parameter_1 = value
|
|
|
|
|
parameter_2 = value_2
|
|
|
|
@ -32,6 +33,8 @@ DATAVARS_MODULE = Variables({'vars_1': vars_1})
|
|
|
|
|
|
|
|
|
|
CHROOT_PATH = os.path.join(os.getcwd(), 'tests/templates/testfiles/test_root')
|
|
|
|
|
CL_CONFIG_PATH = os.path.join(CHROOT_PATH, 'var/lib/calculate/config')
|
|
|
|
|
CL_CONFIG_ARCHIVE_PATH = os.path.join(CHROOT_PATH,
|
|
|
|
|
'var/lib/calculate/config-archive')
|
|
|
|
|
|
|
|
|
|
template_engine = TemplateEngine(datavars_module=DATAVARS_MODULE,
|
|
|
|
|
appends_set=APPENDS_SET,
|
|
|
|
@ -54,8 +57,8 @@ class TemplateCollisionError(Exception):
|
|
|
|
|
|
|
|
|
|
class CalculateConfigFile:
|
|
|
|
|
def __init__(self, cl_config_path='/var/lib/calculate/config',
|
|
|
|
|
chroot_path='/'):
|
|
|
|
|
self.chroot_path = chroot_path
|
|
|
|
|
cl_chroot_path='/'):
|
|
|
|
|
self.chroot_path = cl_chroot_path
|
|
|
|
|
|
|
|
|
|
self.cl_config_path = cl_config_path
|
|
|
|
|
|
|
|
|
@ -113,6 +116,8 @@ class CalculateConfigFile:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
|
if not self._unsaved_changes:
|
|
|
|
|
return
|
|
|
|
|
config_file = write_file(self.cl_config_path)
|
|
|
|
|
|
|
|
|
|
for file_name, file_md5 in self._config_dictionary.items():
|
|
|
|
@ -127,13 +132,6 @@ class CalculateConfigFile:
|
|
|
|
|
|
|
|
|
|
return file_path
|
|
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
|
'''При окончании работы исполнительного модуля не забываем сохранить
|
|
|
|
|
изменения внесенные в /var/lib/calculate/config.'''
|
|
|
|
|
if self._unsaved_changes:
|
|
|
|
|
self.save_changes()
|
|
|
|
|
self._config_dictionary = OrderedDict()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TemplateWrapper:
|
|
|
|
|
'''Класс связывающий шаблон с целевым файлом и определяющий параметры
|
|
|
|
@ -145,8 +143,6 @@ class TemplateWrapper:
|
|
|
|
|
chroot_path = '/'
|
|
|
|
|
config_archive_path = '/var/lib/calculate/config-archive'
|
|
|
|
|
|
|
|
|
|
package_atom_parser = PackageAtomParser(chroot_path=chroot_path)
|
|
|
|
|
|
|
|
|
|
_protected_is_set = False
|
|
|
|
|
_protected_set = {'/etc'}
|
|
|
|
|
_unprotected_set = set()
|
|
|
|
@ -156,6 +152,9 @@ class TemplateWrapper:
|
|
|
|
|
self.target_path = target_file_path
|
|
|
|
|
|
|
|
|
|
self.target_package_name = None
|
|
|
|
|
print("TemplateWrapper init chroot: {}".format(self.chroot_path))
|
|
|
|
|
self.package_atom_parser = PackageAtomParser(
|
|
|
|
|
chroot_path=self.chroot_path)
|
|
|
|
|
|
|
|
|
|
# Вспомогательный флаг, включается, если по целевому пути лежит файл,
|
|
|
|
|
# для которого не определился никакой пакет.
|
|
|
|
@ -176,6 +175,7 @@ class TemplateWrapper:
|
|
|
|
|
# Временный флаг для определения того, является ли шаблон userspace.
|
|
|
|
|
self.is_userspace = False
|
|
|
|
|
|
|
|
|
|
print("Getting format class...")
|
|
|
|
|
# Получаем класс соответствующего формата файла.
|
|
|
|
|
if self.parameters.format:
|
|
|
|
|
self.format_class = ParametersProcessor.\
|
|
|
|
@ -184,6 +184,7 @@ class TemplateWrapper:
|
|
|
|
|
# Здесь будет детектор форматов.
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
print("Checking file types conflicts...")
|
|
|
|
|
# Если по этому пути что-то есть -- проверяем конфликты.
|
|
|
|
|
if os.path.exists(target_file_path):
|
|
|
|
|
for file_type, checker in self.type_checks.items():
|
|
|
|
@ -196,6 +197,7 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
self.check_conflicts()
|
|
|
|
|
|
|
|
|
|
print("Checking package collision...")
|
|
|
|
|
self.check_package_collision()
|
|
|
|
|
|
|
|
|
|
# Если целью является файл -- проверяем наличие ._cfg0000_filename
|
|
|
|
@ -287,13 +289,13 @@ class TemplateWrapper:
|
|
|
|
|
raise TemplateCollisionError(
|
|
|
|
|
"'package' parameter is not defined for"
|
|
|
|
|
" template with 'append' parameter.")
|
|
|
|
|
if parameter_package is None:
|
|
|
|
|
elif parameter_package is None:
|
|
|
|
|
self.target_package_name = file_package
|
|
|
|
|
|
|
|
|
|
if file_package is None:
|
|
|
|
|
elif file_package is None:
|
|
|
|
|
self.target_package_name = parameter_package
|
|
|
|
|
|
|
|
|
|
if file_package != parameter_package:
|
|
|
|
|
elif file_package != parameter_package:
|
|
|
|
|
raise TemplateCollisionError(
|
|
|
|
|
"The template package is {0} while target"
|
|
|
|
|
" file package is {1}").format(
|
|
|
|
@ -307,34 +309,59 @@ class TemplateWrapper:
|
|
|
|
|
chroot_path=self.chroot_path)
|
|
|
|
|
|
|
|
|
|
def check_user_changes(self):
|
|
|
|
|
if self.target_type is None:
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
elif self.target_without_package:
|
|
|
|
|
if self.parameters.autoupdate:
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
self.remove_original = True
|
|
|
|
|
else:
|
|
|
|
|
self.md5_matching = False
|
|
|
|
|
|
|
|
|
|
if (self.target_type is None or
|
|
|
|
|
self.target_package is None or
|
|
|
|
|
self.target_type != FILE):
|
|
|
|
|
'''Метод для проверки наличия пользовательских изменений в
|
|
|
|
|
конфигурационных файлах.'''
|
|
|
|
|
# Эта проверка только для файлов.
|
|
|
|
|
if self.target_type != FILE:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
print("Looking for ._cfg files...")
|
|
|
|
|
# Собираем список имеющихся ._cfg файлов.
|
|
|
|
|
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
|
|
|
|
|
"._cfg????_{}".format(
|
|
|
|
|
os.path.basename(self.target_path)))
|
|
|
|
|
self.cfg_list = glob.glob(cfg_pattern)
|
|
|
|
|
|
|
|
|
|
target_md5 = self.target_package.get_md5(self.target_path)
|
|
|
|
|
self.md5_matching = self.target_package.is_md5_equal(
|
|
|
|
|
# Путь к архивной версии файла.
|
|
|
|
|
self.archive_path = self._get_archive_path(self.target_path)
|
|
|
|
|
|
|
|
|
|
if self.parameters.unbound:
|
|
|
|
|
# Если присутствует unbound, то просто модифицируем файл и
|
|
|
|
|
# удаляем его из CONTENTS.
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
elif self.target_type is None:
|
|
|
|
|
print("There is no files in target path...")
|
|
|
|
|
# Если целевой файл отсутствует.
|
|
|
|
|
if self.target_path in self.target_package:
|
|
|
|
|
# Проверка -- был ли файл удален.
|
|
|
|
|
self.md5_matching = False
|
|
|
|
|
else:
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
elif self.target_without_package:
|
|
|
|
|
print("There is file without package in target path...")
|
|
|
|
|
# Если файл по целевому пути не относится к какому-либо пакету.
|
|
|
|
|
if self.parameters.unbound:
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
else:
|
|
|
|
|
self.md5_matching = False
|
|
|
|
|
else:
|
|
|
|
|
print("Check md5 hash...")
|
|
|
|
|
# Если файл есть и он относится к текущему пакету.
|
|
|
|
|
target_md5 = self.target_package.get_md5(self.target_path)
|
|
|
|
|
self.md5_matching = self.target_package.is_md5_equal(
|
|
|
|
|
self.target_path,
|
|
|
|
|
file_md5=target_md5)
|
|
|
|
|
|
|
|
|
|
# Если по целевому пути файл не относящийся к какому-либо пакету и
|
|
|
|
|
# присутствует параметр autoupdate -- удаляем этот файл.
|
|
|
|
|
if self.target_without_package and self.parameters.autoupdate:
|
|
|
|
|
self.remove_original = True
|
|
|
|
|
|
|
|
|
|
self.md5_matching = self.md5_matching or self.parameters.autoupdate
|
|
|
|
|
self.archive_path = self._get_archive_path(self.target_path)
|
|
|
|
|
|
|
|
|
|
# Определяем путей входных и выходных файлов.
|
|
|
|
|
if self.md5_matching:
|
|
|
|
|
print("md5 matches")
|
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
|
if self.parameters.source:
|
|
|
|
|
self.input_path = self.parameters.source
|
|
|
|
@ -343,6 +370,7 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
self.output_path = self.target_path
|
|
|
|
|
else:
|
|
|
|
|
print("md5 does not match")
|
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
|
if self.parameters.source:
|
|
|
|
|
self.input_path = self.parameters.source
|
|
|
|
@ -352,11 +380,13 @@ class TemplateWrapper:
|
|
|
|
|
self.output_path = self._get_cfg_path(self.target_path)
|
|
|
|
|
|
|
|
|
|
def _get_archive_path(self, file_path):
|
|
|
|
|
print("Getting archive path...")
|
|
|
|
|
if self.chroot_path != "/" and file_path.startswith(self.chroot_path):
|
|
|
|
|
file_path = file_path[len(self.chroot_path):]
|
|
|
|
|
return join_paths(self.config_archive_path, file_path)
|
|
|
|
|
|
|
|
|
|
def _get_cfg_path(self, file_path):
|
|
|
|
|
print("Getting ._cfg path...")
|
|
|
|
|
if self.cfg_list:
|
|
|
|
|
last_cfg_name = os.path.basename(self.cfg_list[-1])
|
|
|
|
|
|
|
|
|
@ -376,7 +406,7 @@ class TemplateWrapper:
|
|
|
|
|
return new_cfg_path
|
|
|
|
|
|
|
|
|
|
def remove_from_contents(self):
|
|
|
|
|
pass
|
|
|
|
|
self.target_package.remove_file(self.target_path)
|
|
|
|
|
|
|
|
|
|
def add_to_contents(self, file_md5=None):
|
|
|
|
|
if self.parameters.append == 'link':
|
|
|
|
@ -403,6 +433,10 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
cls._protected_is_set = True
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
|
if self.target_package and not self.parameters.unbound:
|
|
|
|
|
self.target_package.write_contents_file()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TemplateExecutor:
|
|
|
|
|
def __init__(self, datavars_module=Variables(), chroot_path='/',
|
|
|
|
@ -429,7 +463,7 @@ class TemplateExecutor:
|
|
|
|
|
cl_chroot_path=chroot_path)
|
|
|
|
|
|
|
|
|
|
TemplateWrapper.chroot_path = self.chroot_path
|
|
|
|
|
TemplateWrapper.cl_config_archive = cl_config_archive
|
|
|
|
|
TemplateWrapper.config_archive_path = cl_config_archive
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def available_appends(self):
|
|
|
|
@ -449,8 +483,15 @@ class TemplateExecutor:
|
|
|
|
|
template_text=template_text)
|
|
|
|
|
except TemplateTypeConflict as error:
|
|
|
|
|
print('type conflict: {}'.format(str(error)))
|
|
|
|
|
return
|
|
|
|
|
except TemplateCollisionError as error:
|
|
|
|
|
print('collision: {}'.format(str(error)))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Temporary
|
|
|
|
|
print("Wrapper succesfully initialized.")
|
|
|
|
|
print("Input path:", template_object.input_path)
|
|
|
|
|
print("Output path:", template_object.output_path)
|
|
|
|
|
|
|
|
|
|
if template_object.remove_original:
|
|
|
|
|
if template_object.target_type == DIR:
|
|
|
|
@ -459,13 +500,17 @@ class TemplateExecutor:
|
|
|
|
|
self._remove_file(template_object.target_path)
|
|
|
|
|
template_object.target_type = None
|
|
|
|
|
|
|
|
|
|
# Добавить поддержку run, excute и т.д.
|
|
|
|
|
# Добавить поддержку run, execute и т.д.
|
|
|
|
|
if template_object.template_type == DIR:
|
|
|
|
|
self.directory_appends[template_object.parameters.append](
|
|
|
|
|
template_object)
|
|
|
|
|
elif template_object.template_type == FILE:
|
|
|
|
|
self.file_appends[template_object.parameters.append](
|
|
|
|
|
template_object)
|
|
|
|
|
template_object.save_changes()
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
|
self.calculate_config_file.save_changes()
|
|
|
|
|
|
|
|
|
|
def _append_join_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
if template_object.target_type is None:
|
|
|
|
@ -496,7 +541,7 @@ class TemplateExecutor:
|
|
|
|
|
if template_object.md5_matching:
|
|
|
|
|
output_paths = [output_path]
|
|
|
|
|
# Проверка на предмет userspace.
|
|
|
|
|
if template_object.is_userspace:
|
|
|
|
|
if not template_object.is_userspace:
|
|
|
|
|
output_paths.append(template_object.archive_path)
|
|
|
|
|
|
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
@ -529,7 +574,10 @@ class TemplateExecutor:
|
|
|
|
|
self.calculate_config_file.remove_file(template_object.target_path)
|
|
|
|
|
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
if template_object.parameters.unbound:
|
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
|
else:
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
else:
|
|
|
|
|
with open(input_path, 'r') as input_file:
|
|
|
|
|
input_text = input_file.read()
|
|
|
|
@ -546,12 +594,17 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
if not self.calculate_config_file.compare_md5(target_path,
|
|
|
|
|
output_text_md5):
|
|
|
|
|
print("cl is different, create ._cfg")
|
|
|
|
|
with open(output_path, 'w') as output_file:
|
|
|
|
|
output_file.write(output_text)
|
|
|
|
|
self.calculate_config_file.set_files_md5(template_object,
|
|
|
|
|
output_text_md5)
|
|
|
|
|
self.calculate_config_file.set_files_md5(
|
|
|
|
|
template_object.target_path,
|
|
|
|
|
output_text_md5)
|
|
|
|
|
print("current config: ",
|
|
|
|
|
self.calculate_config_file._config_dictionary)
|
|
|
|
|
else:
|
|
|
|
|
# Действия если CL совпало. Пока ничего не делаем.
|
|
|
|
|
print("cl is similar...")
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
@ -771,9 +824,13 @@ class TemplateExecutor:
|
|
|
|
|
self.output.set_error('error with owner: {}'.format(owner))
|
|
|
|
|
|
|
|
|
|
def check_filesystem(self, target_path):
|
|
|
|
|
'''Метод, который предположительно будет использоваться для проверки
|
|
|
|
|
файловой системы перед применением шаблона.'''
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def is_vfat(self, path):
|
|
|
|
|
'''Метод, проверяющий является ли файловая система vfat. Нужно для того,
|
|
|
|
|
чтобы заранее знать о возможности применения chown, chmod и т.д.'''
|
|
|
|
|
if self.mounts is None:
|
|
|
|
|
self.mounts = Mounts()
|
|
|
|
|
if self.mounts.get_from_fstab(what=self.mounts.TYPE,
|
|
|
|
@ -798,17 +855,25 @@ template_engine.process_template_from_string(template_text, FILE)
|
|
|
|
|
template_parameters = template_engine.parameters
|
|
|
|
|
template_text = template_engine.template_text
|
|
|
|
|
|
|
|
|
|
template_action_obj = TemplateExecutor(datavars_module=DATAVARS_MODULE,
|
|
|
|
|
chroot_path=CHROOT_PATH)
|
|
|
|
|
|
|
|
|
|
result = template_action_obj.use_file_template(target_path,
|
|
|
|
|
template_parameters,
|
|
|
|
|
template_text=template_text)
|
|
|
|
|
print('MAIN TEST TEMPLATE IS USED')
|
|
|
|
|
# Применение шаблона бэкапа:
|
|
|
|
|
template_executor_obj = TemplateExecutor(
|
|
|
|
|
datavars_module=DATAVARS_MODULE,
|
|
|
|
|
chroot_path=CHROOT_PATH,
|
|
|
|
|
cl_config_archive=CL_CONFIG_ARCHIVE_PATH,
|
|
|
|
|
cl_config_path=CL_CONFIG_PATH)
|
|
|
|
|
template_executor_obj.execute_template(target_path,
|
|
|
|
|
template_parameters,
|
|
|
|
|
FILE, template_text=template_text)
|
|
|
|
|
template_executor_obj.save_changes()
|
|
|
|
|
input()
|
|
|
|
|
template_engine.process_template_from_string(backup_template_text, FILE)
|
|
|
|
|
result = template_action_obj.use_file_template(
|
|
|
|
|
target_path,
|
|
|
|
|
template_engine.parameters,
|
|
|
|
|
template_text=template_engine.template_text)
|
|
|
|
|
print('BACKUP TEMPLATE IS USED')
|
|
|
|
|
template_parameters = template_engine.parameters
|
|
|
|
|
template_text = template_engine.template_text
|
|
|
|
|
template_executor_obj = TemplateExecutor(
|
|
|
|
|
datavars_module=DATAVARS_MODULE,
|
|
|
|
|
chroot_path=CHROOT_PATH,
|
|
|
|
|
cl_config_archive=CL_CONFIG_ARCHIVE_PATH,
|
|
|
|
|
cl_config_path=CL_CONFIG_PATH)
|
|
|
|
|
template_executor_obj.execute_template(target_path,
|
|
|
|
|
template_parameters,
|
|
|
|
|
FILE, template_text=template_text)
|
|
|
|
|
template_executor_obj.save_changes()
|
|
|
|
|