CrontabManager.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import logging
  2. from crontab import CronSlices
  3. from crontab import CronTab
  4. from core import Utils
  5. from core.Models import Event
  6. logging.basicConfig()
  7. logger = logging.getLogger("kalliope")
  8. class InvalidCrontabPeriod(Exception):
  9. """
  10. Event are based on the Crontab. The Period must be corresponding to the Crontab format
  11. .. seealso:: Event
  12. """
  13. pass
  14. CRONTAB_COMMENT = "KALLIOPE"
  15. KALLIOPE_ENTRY_POINT_SCRIPT = "kalliope.py"
  16. class CrontabManager:
  17. def __init__(self, brain=None):
  18. self.my_user_cron = CronTab(user=True)
  19. self.brain = brain
  20. self.base_command = self._get_base_command()
  21. def load_events_in_crontab(self):
  22. """
  23. Remove all line in crontab with the CRONTAB_COMMENT
  24. Then add back line from event in the brain.yml
  25. """
  26. # clean the current crontab from all Kalliope event
  27. self._remove_all_job()
  28. # load the brain file
  29. for synapse in self.brain.synapses:
  30. for signal in synapse.signals:
  31. # print signal
  32. # if the signal is an event we add it to the crontab
  33. if type(signal) == Event:
  34. # for all synapse with an event, we add the task id to the crontab
  35. self._add_event(period_string=signal.period, event_id=synapse.name)
  36. def _add_event(self, period_string, event_id):
  37. """
  38. Add a single event in the crontab.
  39. Will add a line like:
  40. <period_string> python /path/to/kalliope.py start --brain-file /path/to/brain.yml --run-synapse "<event_id>"
  41. E.g:
  42. 30 7 * * * python /home/me/kalliope/kalliope.py start --brain-file /home/me/brain.yml --run-synapse "Say-hello"
  43. :param period_string: crontab period
  44. :type period_string: str
  45. :param event_id:
  46. :type event_id: str
  47. :return:
  48. """
  49. my_user_cron = CronTab(user=True)
  50. job = my_user_cron.new(command=self.base_command+" "+str("\"" + event_id + "\""), comment=CRONTAB_COMMENT)
  51. if CronSlices.is_valid(period_string):
  52. job.setall(period_string)
  53. job.enable()
  54. else:
  55. raise InvalidCrontabPeriod("The crontab period %s is not valid" % period_string)
  56. # write the file
  57. my_user_cron.write()
  58. Utils.print_info("Synapse \"%s\" added to the crontab" % event_id)
  59. def get_jobs(self):
  60. """
  61. Return all current jobs in the crontab
  62. :return:
  63. """
  64. return self.my_user_cron.find_comment(CRONTAB_COMMENT)
  65. def _remove_all_job(self):
  66. """
  67. Remove all line in crontab that are attached to Kalliope
  68. """
  69. iter_item = self.my_user_cron.find_comment(CRONTAB_COMMENT)
  70. for job in iter_item:
  71. logger.debug("remove job %s from crontab" % job)
  72. self.my_user_cron.remove(job)
  73. # write the file
  74. self.my_user_cron.write()
  75. # this is a fix for the CronTab lib
  76. # see https://github.com/peak6/python-crontab/issues/1
  77. new_iter = self.my_user_cron.find_comment(CRONTAB_COMMENT)
  78. sum_job = sum(1 for _ in new_iter)
  79. while sum_job > 0:
  80. self._remove_all_job()
  81. def _get_base_command(self):
  82. """
  83. Return the path of the entry point of Kalliope
  84. Example: /home/user/kalliope/kalliope.py
  85. :return: The path of the entry point script kalliope.py
  86. :rtype: str
  87. """
  88. import inspect
  89. import os
  90. # get current script directory path. We are in /an/unknown/path/kalliope/core
  91. cur_script_directory = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
  92. # get parent dir. Now we are in /an/unknown/path/kalliope
  93. parent_dir = os.path.normpath(cur_script_directory + os.sep + os.pardir)
  94. # we add the kalliope.py file name
  95. real_entry_point_path = parent_dir + os.sep + KALLIOPE_ENTRY_POINT_SCRIPT
  96. # We test that the file exist before return it
  97. logger.debug("Real Kalliope.py path: %s" % real_entry_point_path)
  98. if os.path.isfile(real_entry_point_path):
  99. crontab_cmd = "python %s start --brain-file %s --run-synapse " % (real_entry_point_path,
  100. self.brain.brain_file)
  101. return crontab_cmd
  102. raise IOError("kalliope.py file not found")