#python #provisioning #pyinfra
#python #подготовка #pyinfra
Вопрос:
Я использую pyinfra
для подготовки некоторых файлов. Я хотел бы знать, где лучше всего разместить пользовательские модули.
Пример
Учитывая пользовательский факт, который возвращается True
, если система не является безголовой:
class HasGui(FactBase):
default = list
command = 'ls /usr/share/xsessions/*.desktop || true'
def process(self, output):
return output
Вопросы
Куда мне это поместить? Я полагаю, что могу закодировать этот фрагмент непосредственно в «операционный» файл, но что, если я захочу повторно использовать этот код в нескольких модулях? Как мне абстрагировать это в отдельный модуль или получить к нему доступ из API?
Хотя данные могут быть разделены между модулями, рекомендуемая компоновка, по-видимому, не позволяет легко подключать пользовательские модули к API.
Подходы
- Я пытался создать отдельный модуль уровня задачи, но он не распознается при вызове из командной строки.
- Последним средством может быть добавление пути к
sys.path
, но я бы предпочел более чистый вариант.
Ответ №1:
Эта ошибка предполагает, что пользовательские факты могут быть обнаружены из config.py
файла верхнего уровня, расположенного рядом с файлами «deploy».
Код
Пользовательский факт, закодированный в конфигурации (необязательно). Смотрите также пример макета:
# config.py
from pyinfra.api import FactBase
class HasGui(FactBase):
default = list
command = 'ls /usr/share/xsessions/*.desktop || true'
def process(self, output):
return output
Примечание: завершение не позволяет pyinfra || true
выдавать ошибки при сбое. Сбои, похоже, обрабатываются внутренне, несмотря на продолжение.
Когда пользовательский подкласс fact FactBase
добавляется в индекс facts . Вы можете получить к ним доступ через атрибуты в змеином корпусе:
# tasks/operation.py
from pyinfra import host
if host.fact.has_gui:
# Insert operation
...
ДЕМОНСТРАЦИЯ
Запустите в командной строке.
> pyinfra @local tasks/operation.py
[@local] Successful: 1 Errors: 0 Commands: 1/1
> pyinfra @<server> tasks/operation.py
[@local] Successful: 0 Errors: 0 Commands: 1/1
Ответ №2:
В реальной версии, для меня, это работает следующим образом:
база: /home/pyinfra
у меня есть поддиректор (пользовательский / факты) с пользовательскими фактами и операциями (и __init__.py
файлом):
например /home/pyinfra/custom/facts/FileFacts.py
from pyinfra.api import FactBase
class FileExists(FactBase):
'''
Returns if file exists (true/false)
'''
__filepath = ""
def command(self, path):
""" Checks if app exists via linux ls command """
self.__filepath = path
return 'ls {0}'.format(path)
def process(self, output):
# ls should return the path itself if it exists
if str(output[0]) == self.__filepath:
return True
return False
Затем в моей задаче я могу импортировать и вызывать его через
from custom.facts.FileFacts import FileExists
if host.get_fact(FileExists, "/etc/app/config"):
logger.info("File already exits!")
else:
logger.info("File does not exist!")
(не вешайте меня, если сам код несовершенен, хотя полезный ввод приветствуется, его достаточно для моего случая)
Комментарии:
1. Выглядит как отличный пример передачи аргументов в пользовательский факт.