简体   繁体   中英

Python script not executed from Cron

I am trying to run a Python script from Cron but it does not work. I have already tried everything I have seen in multiple Stackoverflow questions.The machine is a Raspberry running Raspbian. The following piece of code is the edition of crontab :

PATH=/usr/sbin:/usr/bin:/sbin/bin:/sbin:/bin:/home/pi/miniconda/bin:/usr/local/bin:/usr/local/sbin

*/5 * * * * rsync -az --timeout=10 --progress pritms@bigdata.trainhealthmanagement.com:Upload/*.csv /home/pi/PAD-S100/PAD-S100-Bloque_Motor/from_repo/ | /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/adddate_to_logs.sh >> /home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log 2>&1
*/5 * * * * /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/from_repo/launcher.sh | /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/adddate_to_logs.sh >> /home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log 2>&1
*/30 * * * * rm /home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log
* * * * * /usr/bin/python /home/pi/PAD-S100/PAD-S100-Bloque_Motor/from_repo/event_management.py | /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/adddate_to_logs.sh >> home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log 2>&1
0 0 * * * rm /home/pi/PAD-S100/PAD-S100-Bloque_Motor/from_repo/*.csv | /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/adddate_to_logs.sh >> /home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log 2>&1

Crontab Observations:

  • The Path obtained from echo $PATH is included.
  • launcher.sh , addddate_to_logs.sh and event_management are executables using the command sudo chmod a+x <file_name> .

The log.log file does not show anything strange. The system log file /var/log/syslog has the following logs:

Feb 27 15:11:08 raspberrypi cron[21814]: sendmail: Cannot open :25
Feb 27 15:12:01 raspberrypi rsyslogd-2007: action 'action 17' suspended, next retry is Mon Feb 27 15:13:31 2017 [try http://www.rsyslog.com/e/2007 ]
Feb 27 15:12:01 raspberrypi CRON[22209]: (pi) CMD (/usr/bin/python /home/pi/PAD-S100/PAD-S100-Bloque_Motor/from_repo/event_management.py | /bin/sh /home/pi/PAD-S100/PAD-S100-Bloque_Motor/adddate_to_logs.sh >> home/pi/PAD-S100/PAD-S100-Bloque_Motor/log.log 2>&1)
Feb 27 15:12:09 raspberrypi sSMTP[22212]: Unable to set UsesSTARTTILS=""
Feb 27 15:12:09 raspberrypi sSMTP[22212]: Unable to locate
Feb 27 15:12:09 raspberrypi cron[21814]: sendmail: Cannot open :25
Feb 27 15:12:09 raspberrypi sSMTP[22212]: Cannot open :25
Feb 27 15:12:09 raspberrypi CRON[22205]: (pi) MAIL (mailed 178 bytes of output but got status 0x0001 from MTA#012)

We can observe that it is probable that the failing crontab line is the one of the python script. As I am not an expert in Linux I believe it may be something related to the sSMTP . The same kind of error log appears after every call of the cron python script. But I have no idea of how to fix it or configure the local email.

Here is the piece of code of event_management.py file :

#!/usr/bin/python
# -*- coding: utf-8 -*-
import imaplib
import email
import csv
import datetime


EMAIL = <email_user>
FROM_PWD = <password>
SMTP_SERVER = 'mail.o365.alstom.com'
datum = dict()
translate = {'#09': 1, '#0A': 2, '#0B': 3, '#0C': 4}


def connect_imap():
    mail = imaplib.IMAP4_SSL(SMTP_SERVER)
    mail.login(EMAIL, FROM_PWD)
    return mail


def read_email_from_gmail(writer, mail):
    mail.select('BRMS')

    kind, data = mail.search(None, 'ALL')
    mail_ids = data[0]
    id_list = mail_ids.split()
    first_email_id = int(id_list[0])
    latest_email_id = int(id_list[-1])

    for i in range(latest_email_id, first_email_id, -1):
        typ, data = mail.fetch(i, '(RFC822)')

        for response_part in data:
            if isinstance(response_part, tuple):
                msg = email.message_from_string(response_part[1])
                for part in msg.walk():
                    if part.get_content_type() == 'text/html':
                        content = part.get_payload()
                        manage_email_content(content, writer)

    return 0


def manage_email_content(content, writer):
    content = content.split('\n')
    for i, line in enumerate(content):
        if 'Alert description' in line:
            line = line.split()
            datum['Event code'] = line[-1][4:]
            if line[-1][:3] in translate:
                datum['Motor block num'] = translate[line[-1][:3]]
            else:
                datum['Motor block num'] = 'Defecto ajeno al bloque motor'
        elif 'Alert condition' in line:
            line = line.split()
            datum['Code description'] = ' '.join(line[4:])
        elif 'Unit id' in line:
            line = line.split()
            datum['Train num'] = line[3][3:]
        elif 'Alert raised' in line:
            line = line.split()
            datum['Date'] = line[4][:10]
            datum['Time'] = line[4][11:]
    writer.writerow(datum)
    print datum
    return 0


def move_to_trash_before_date(mail, folder, days_before):
    # required to perform search, m.list() for all lables, '[Gmail]/Sent Mail'
    no_of_msgs = int(mail.select(folder)[1][0])
    print("- Found a total of {1} messages in '{0}'.".format(folder, no_of_msgs))

    before_date = (datetime.date.today() - datetime.timedelta(days_before)).strftime("%d-%b-%Y")
    typ, data = mail.search(None, '(BEFORE {0})'.format(before_date))  # search pointer for msgs before before_date

    if data != ['']:  # if not empty list means messages exist
        no_msgs_del = data[0].split()[-1]  # last msg id in the list
        print("- Marked {0} messages for removal with dates before {1} in '{2}'.".format(no_msgs_del, before_date, folder))
        mail.store("1:{0}".format(no_msgs_del), '+X-GM-LABELS', '\\Trash')  # move to trash
        empty_folder(mail, 'Elementos eliminados', do_expunge=True)  # can send do_expunge=False, default True
    else:
        print("- Nothing to remove.")

    return 0


def empty_folder(mail, folder, do_expunge=True):
    mail.select(folder)  # select all trash
    mail.store("1:*", '+FLAGS', '\\Deleted')  # Flag all Trash as Deleted
    if do_expunge:  # See Gmail Settings -> Forwarding and POP/IMAP -> Auto-Expunge
        mail.expunge()  # not need if auto-expunge enabled
    else:
        print("Expunge was skipped.")
    return 0


def disconnect_imap(mail):
    mail.close()
    mail.logout()
    return 0


def main():
    with open('email_data.csv', 'w') as f:
        writer = csv.DictWriter(f, fieldnames=['Time', 'Date', 'Train num', 'Motor block num',
                                               'Event code', 'Code description'], delimiter=';')
        try:
            m = connect_imap()
            writer.writeheader()
            read_email_from_gmail(writer, m)
            move_to_trash_before_date(m, 'BRMS', 15)  # inbox cleanup, before 15 days
            disconnect_imap(m)

        except Exception, e:
            print str(e)

if __name__ == "__main__":
    main()

event_management file connects to an Outlook email folder, reads the emails and builds a CSV file with data extracted from the the emails' contents. This file works properly, it is already tested; and it works fine when executed manually (not using Cron). So I not sure it is related to the sSMTP issue appearing in the system log.

I will apreciate every kind of help or suggestions!

After some test and reading other users' answers, I have found the problem. It is a combination of two different issues that are not directly related, but together made this problem a pain in the ass to debug.


First Problem:

log.log file contains logs and errors from three different executables, hence I did not notice that evet_management file did not have the correct permissions. I did not apply chmod command well, and I have not notice it as it contained a lot of data.

Conclussion 1: One cronjob , one log file.

Conclussion 2: /var/log/syslog contains a lot of data, from various resources, hence it may confuse you when trying to debug. Better to produce log files apart.


Second Problem:

I have two Python distributions installed in my machine. When I execute manually the script, one is used. When Cron executes the script the other one is used. Furthermore I noticed it when first problem was fixed. I got an error of module not found when running the Python script by Cron in the log file, but perfectly worked when manually executed. Hence I have seen that when using pip install <module-name> , it is just for one distro. To check wich version of Python I was using:

which Python

Conclussion: Be smart, don't be like me, don't mess with multiple Python distributions.


Bonus: Always use full paths to be clear. Cron has different env than yours.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM