Reputation: 44565
I'm using pyinfra
to provision some files. I would like to know the best place to put custom modules.
Example
Given a custom fact that returns True
if a system is not headless:
class HasGui(FactBase):
default = list
command = 'ls /usr/share/xsessions/*.desktop || true'
def process(self, output):
return output
Questions
Where do I put this? I imagine I can code this snippet directly into an "operation" file, but what if I want to reuse this code in several modules? How do I abstract this into a separate module or access it from the API?
While data can be shared across modules, the recommended layout does not appear to easily permit custom modules to hook into the API.
Approaches
sys.path
, but I'd prefer a cleaner option.Upvotes: 2
Views: 809
Reputation: 21
In actual version, for me, it works like this:
base: /home/pyinfra
i have a subdir (custom/facts) with custom facts and ops (and __init__.py
file):
for example /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
Then in my task i can import and call it via
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!")
(dont hang me if the code itself is imperfect, although helpful input is appreciated, its sufficient for my case)
Upvotes: 1
Reputation: 44565
This bug suggests custom facts can be detected from a top-level config.py
file located next to "deploy" files.
Code
A custom fact coded into the config (optional). See also a sample layout:
# 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
Note: the trailing || true
keeps pyinfra from erroring out on fails. Failures seem to be handled internally despite the continuation.
When a custom fact subclasses FactBase
, it is added to a facts index. You can access them via snake-cased attributes:
# tasks/operation.py
from pyinfra import host
if host.fact.has_gui:
# Insert operation
...
Demo
Run in command line.
> 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
Upvotes: 2