run - python script as a linux service
Usar setup.py para instalar el proyecto python como un servicio systemd (2)
Asegúrese de que su aplicación se pueda ejecutar desde otros directorios, esto parece un caso clásico en el que se supone que el directorio actual es donde existe el script de inicio.
No tiene nada que ver con systemd. También intente ejecutar el comando de inicio desde fuera de su shell de inicio de sesión (los servicios no cargan su perfil).
Tengo un proyecto de python y quiero poder instalarlo usando algo como python setup.py install
para que la instalación cree automáticamente un servicio systemd.
Estoy teniendo problemas, lo más probable es que establezca las rutas o las importaciones correctamente.
Mi entorno:
- Ubuntu 15.04
- Python 2.7 (aunque sería genial hacerlo funcionar en py3 también).
Estructura del proyecto:
+ top-folder
+ super_project
+ folder1
__init__.py
file1.py
+ folder2
__init__.py
file2.py
__init__.py
main.py
setup.py
setup.cfg
setup.py:
from setuptools.command.install import install
from setuptools import setup, find_packages
import subprocess
import os
class CustomInstallCommand(install):
def run(self):
install.run(self)
current_dir_path = os.path.dirname(os.path.realpath(__file__))
create_service_script_path = os.path.join(current_dir_path, ''super_project'', ''install_scripts'', ''create_service.sh'')
subprocess.check_output([create_service_script_path])
setup(
name=''super-project'',
author=''Myself'',
version=''0.0.1'',
description=''My Description'',
packages=find_packages(exclude=[''contrib'', ''docs'']),
# this will create the /usr/local/bin/super-project entrypoint script
entry_points={
''console_scripts'': [
''super-project = super_project.main:main''
]
},
cmdclass={''install'': CustomInstallCommand}
)
main.py
from super_project.folder1.file1 import Class1
from super_project.folder2.file2 import Class2
import logging
def main():
logging.info(''Executing super-project...'')
(...)
logging.info(''super-project execution finished.'')
if __name__ == ''__main__'':
main()
setup.cfg
[bdist_wheel]
universal=1
create_service.sh (más o menos):
SYSTEMD_SCRIPT_DIR=$( cd $(dirname "${BASH_SOURCE:=$0}") && pwd)
cp -f "$SYSTEMD_SCRIPT_DIR/super-project.service" /lib/systemd/system
chown root:root /lib/systemd/system/super-project.service
systemctl daemon-reload
systemctl enable super-project.service
super-proyecto.servicio
[Unit]
Description=Super Description
[Service]
Type=simple
ExecStart=/usr/local/bin/super-service
Restart=always
[Install]
WantedBy=multi-user.target
La instalación del paquete genera el siguiente resultado:
$ sudo python setup.py install --record files.txt
running install
running build
running build_py
copying super_project/main.py - build/lib.linux-x86_64-2.7/super_project
running install_lib
copying build/lib.linux-x86_64-2.7/super_project/__init__.py - /usr/local/lib/python2.7/dist-packages/super_project
copying build/lib.linux-x86_64-2.7/super_project/main.py - /usr/local/lib/python2.7/dist-packages/super_project
copying build/lib.linux-x86_64-2.7/super_project/db/__init__.py - /usr/local/lib/python2.7/dist-packages/super_project/db
copying build/lib.linux-x86_64-2.7/super_project/db/db_gateway.py - /usr/local/lib/python2.7/dist-packages/super_project/db
(...)
byte-compiling /usr/local/lib/python2.7/dist-packages/super_project/__init__.py to
__init__.pyc
byte-compiling /usr/local/lib/python2.7/dist-packages/super_project/main.py to
main.pyc
byte-compiling /usr/local/lib/python2.7/dist-packages/super_project/db/__init__.py to
__init__.pyc
byte-compiling /usr/local/lib/python2.7/dist-packages/super_project/db/db_gateway.py
to db_gateway.pyc
(...)
running install_egg_info
running egg_info
writing requirements to super_project.egg-info/requires.txt
writing super_project.egg-info/PKG-INFO
writing top-level names to super_project.egg-info/top_level.txt
writing dependency_links to super_project.egg-info/dependency_links.txt
writing entry points to super_project.egg-info/entry_points.txt
reading manifest file ''super_project.egg-info/SOURCES.txt''
writing manifest file ''super_project.egg-info/SOURCES.txt''
Copying super_project.egg-info to /usr/local/lib/python2.7/dist-packages/super_project-0.0.1.egg-info
running install_scripts
Installing ai-scenario-qa script to /usr/local/bin
writing list of installed files to ''files.txt''
El archivo de super-project
se crea en / usr / local / bin:
#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: ''super-project==0.0.1'',''console_scripts'',''super-project''
__requires__ = ''super-project==0.0.1''
import sys
from pkg_resources import load_entry_point
if __name__ == ''__main__'':
sys.exit(
load_entry_point(''super-project==0.0.1'', ''console_scripts'', ''super-project'')()
)
La instalación parece exitosa, aunque:
$ systemctl status super-project.service
● super-project.service
Loaded: not-found (Reason: No such file or directory)
Active: inactive (dead)
El error que puedo ver en / var / log / syslog:
Feb 16 20:48:34 systemd[1]: Starting Super Description...
Feb 16 20:48:34 super-project[22517]: Traceback (most recent call last):
Feb 16 20:48:34 super-project[22517]: File "/usr/local/bin/super-project", line 9, in <module
Feb 16 20:48:34 super-project[22517]: load_entry_point(''super-project==0.0.1'', ''console_scripts'', ''super-project'')()
Feb 16 20:48:34 super-project[22517]: File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 521, in load_entry_point
Feb 16 20:48:34 super-project[22517]: return get_distribution(dist).load_entry_point(group, name)
Feb 16 20:48:34 super-project[22517]: File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2632, in load_entry_point
Feb 16 20:48:34 super-project[22517]: return ep.load()
Feb 16 20:48:34 super-project[22517]: File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2312, in load
Feb 16 20:48:34 super-project[22517]: return self.resolve()
Feb 16 20:48:34 super-project[22517]: File "/usr/lib/python2.7/dist-packages/pkg_resources/__init__.py", line 2318, in resolve
Feb 16 20:48:34 super-project[22517]: module = __import__(self.module_name, fromlist=[''__name__''], level=0)
Feb 16 20:48:34 super-project[22517]: ImportError: No module named main
Feb 16 20:48:34 systemd[1]: super-project.service: main process exited, code=exited, status=1/FLURE
Feb 16 20:48:34 systemd[1]: Unit super-project.service entered fled state.
Feb 16 20:48:34 systemd[1]: super-project.service failed.
Feb 16 20:48:34 systemd[1]: super-project.service holdoff time over, scheduling restart.
Feb 16 20:48:34 systemd[1]: start request repeated too quickly for super-project.service
Feb 16 20:48:34 systemd[1]: Failed to start Super Description.
Feb 16 20:48:34 systemd[1]: Unit super-project.service entered fled state.
Feb 16 20:48:34 systemd[1]: super-project.service failed.
Como se puede ver, el módulo main
no se puede encontrar . Este es el problema principal.
Al cambiar el código / conf, elimino el superproyecto / servicio de la siguiente manera:
$ sudo systemctl disable super-project.service
$ sudo rm -f /lib/systemd/system/super-project.service
$ sudo systemctl daemon-reload
$ su
# cat files.txt | xargs rm -r
Por otra parte:
- Si ejecuto
$ super-project
desde/usr/local/bin/
, la secuencia de comandos se inicia correctamente (sin excepción de importación) pero los archivos de configuración no se pueden leer (muy probablemente debido a problemas de ruta relativa / absoluta). - Si ejecuto
$ super-project
desdetop-folder
(carpeta que contiene el código / archivos del proyecto), el script se ejecuta perfectamente
¿Qué me estoy perdiendo? He pasado mucho tiempo buscando cuál podría ser el problema. Parece que el paquete está configurado correctamente en el directorio dist-packages
y todos los archivos de servicio se crean correctamente una vez que se ejecuta la instalación.
He leído cosas sobre el uso from __future__ import absolute_import
, pero no estoy seguro si tengo que agregar eso a mi main.py (no funciona) o a todos los archivos en mi proyecto.
Obtiene un ImportError
porque el módulo en cuestión no está en sys.path
o no es accesible debido a algunos permisos del sistema de archivos.
Aquí hay un script para verificar los permisos del sistema de archivos de una distribución, grupo y nombre dados.
chk_perm.py
from pkg_resources import get_distribution
import os
import sys
dist, group, name = sys.argv[1:]
dist = get_distribution(dist)
location = dist.location
einfo = dist.get_entry_info(group, name)
if not einfo:
print(''No such group "{}" or name "{}"''.format(group, name))
sys.exit(1)
m_name = einfo.module_name
path = format(os.path.join(location, *m_name.split(''.'')))
path = path if os.access(path, os.F_OK) else ''{}.py''.format(path)
print(''If path "{}" exists: {}''.format(path, os.access(path, os.F_OK) if path.endswith(''.py'') else True))
print(''If path "{}" readable: {}''.format(path, os.access(path, os.R_OK)))
Prueba;
$ python chk_perm.py setuptools console_scripts easy_install
If path "lib/python2.7/site-packages/setuptools/command/easy_install.py" exists: True
If path "lib/python2.7/site-packages/setuptools/command/easy_install.py" readable: True
$ foo
Traceback (most recent call last):
File "bin/foo", line 9, in <module>
load_entry_point(''mypkg==0.0.4'', ''console_scripts'', ''foo'')()
File "lib/python2.7/site-packages/pkg_resources/__init__.py", line 549, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "lib/python2.7/site-packages/pkg_resources/__init__.py", line 2542, in load_entry_point
return ep.load()
File "lib/python2.7/site-packages/pkg_resources/__init__.py", line 2202, in load
return self.resolve()
File "lib/python2.7/site-packages/pkg_resources/__init__.py", line 2208, in resolve
module = __import__(self.module_name, fromlist=[''__name__''], level=0)
ImportError: No module named main
$ python chk_perm.py mypkg console_scripts foo
If path "lib/python2.7/site-packages/pkg/main.py" exists: True
If path "lib/python2.7/site-packages/pkg/main.py" readable: False
$ ls -l lib/python2.7/site-packages/pkg/main.py
-rw-rw---- 1 root root 104 Mar 6 22:52 lib/python2.7/site-packages/pkg/main.py
$ sudo chmod o+r lib/python2.7/site-packages/pkg/main.py
$ ls -l lib/python2.7/site-packages/pkg/main.py
-rw-rw-r-- 1 root root 104 Mar 6 22:52 lib/python2.7/site-packages/pkg/main.py
$ python chk_perm.py mypkg console_scripts foo
If path "lib/python2.7/site-packages/pkg/main.py" exists: True
If path "lib/python2.7/site-packages/pkg/main.py" readable: True
$ foo
App is running