mitogen
mitogen copied to clipboard
`No module named my.custom.module` when trying to use `call_async()` from a Python package
I can't use mitogen to run functions in my code on remote nodes, even though they do run functions out of the Python standard library just fine. My code is not just a single file script, it's a Python package installable from pip. Is running mitogen from a Python package supported? Is there another way to accomplish what I want to do?
Info about my use case:
- Not using Ansible
- Building a command-line tool that sometimes has to ssh to remote machines
- My tool is built as a Python package with multiple files and sub-packages; it's not a single script
- I'm using the tip of the master branch of Mitogen, which reports its
__version__
attribute as(0, 3, 4, 'dev0')
- I'm running my code inside Linux (an Alpine Docker container on macOS) running Python 3.10.5
- Remote nodes are running Alpine Linux running Python 3.10.4
When I try to pass one of my own functions to call_async()
, it logs a DEBUG message that says progfiguration.remoting is submodule of a locally loaded package
, and terminates with an error No module named 'progfiguration.remoting'
, where progfiguration.remoting
is the name of the Python package containing my code. However, passing a function from the Python standard library works just fine.
Here's what my code looks like:
def mitogen_example_remote_function():
return "I am an example function intended to be run on remote hosts by mitogen"
def mitogen_example():
hostnames = [
"jesseta.home.micahrl.com",
"kenasus.home.micahrl.com",
"zalas.home.micahrl.com",
]
broker = Broker()
router = Router(broker)
try:
# hostname:context pairs
contexts = {n: router.ssh(hostname=n, username="root", python_path="python3") for n in hostnames}
# context_id:hostname pairs
# Used to get the hostname for a given response
hostname_by_context_id = {context.context_id: hostname for hostname, context in contexts.items()}
# This doesn't work at all, showing log lines including
# [2022-10-05 17:34:28,245] [mitogen.importer.[ssh.kenasus.home.micahrl.com]] [DEBUG] progfiguration.remoting is submodule of a locally loaded package
# and
# mitogen.core.CallError: builtins.ModuleNotFoundError: No module named 'progfiguration.remoting'
# (progfiguration.remoting is the name of this module)
print("Calling a function defined in this Python module")
calls = [ctx.call_async(mitogen_example_remote_function) for ctx in contexts.values()]
for msg in Select(calls):
hostname = hostname_by_context_id[msg.src_id]
result = msg.unpickle()
print(f"{hostname}: {result}")
finally:
broker.shutdown()
If instead of calling my example remote function, I call something from the Python standard library, that does work.
print("Calling a function that's part of the Python standard library which returns a string")
calls = [ctx.call_async(socket.gethostname) for ctx in contexts.values()]
for msg in Select(calls):
hostname = hostname_by_context_id[msg.src_id]
result = msg.unpickle()
for line in result.split("\n"):
print(f"{hostname}: {line}")
# This works just fine, returns lines like
# jesseta.home.micahrl.com: jesseta