jobs.py 3.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
class SaltJobsError(Exception):
    """Base class of :class:`SaltJobs` exceptions

    """


class SaltJobsErrorDbConnectionError(SaltJobsError):
    """Raised when an error occurs with the connection to the database

    """


class SaltJobsErrorListError(SaltJobsError):
    """Raised when an error occurs during the listing of the jobs

    """


class SaltJobsErrorMissingJobId(SaltJobsError):
    """Raised when the `JId` is missing in the describe request

    """

class SaltJobsErrorJobIdTypeError(SaltJobsError):
    """Raised when the `JId` keyword argument is not a string

    """


class SaltJobsErrorUnknownJobId(SaltJobsError):
    """Raised when the `JId` is unknown in the database

    """


class SaltJobs():
    """SaltStack jobs

    """


    fetch_all_jobs = '''
    SELECT
        jids.jid,
        (
            SELECT count(jid) > 0
            FROM salt_returns
            WHERE jids.jid = salt_returns.jid
        ) AS executed,
        salt_returns.full_ret->>'retcode' AS retcode,
        salt_returns.full_ret->>'id' AS minion,
        load->>'fun' AS fun,
        load->'arg' AS fun_args,
        load->>'tgt' AS target
    FROM jids
    LEFT JOIN salt_returns ON salt_returns.jid = jids.jid
    WHERE load @> '{"tgt": "%s"}'
    ORDER BY jids.jid DESC;
    '''

    fetch_job = '''
    SELECT
        jids.jid,
        (
            SELECT count(jid) > 0
            FROM salt_returns
            WHERE jids.jid = salt_returns.jid
        ) AS executed,
        salt_returns.full_ret->>'retcode' AS retcode,
        salt_returns.full_ret->>'return' AS return,
        salt_returns.full_ret->>'id' AS minion,
        load->>'fun' AS fun,
        load->'arg' AS fun_args,
        load->>'tgt' AS target
    FROM jids
    LEFT JOIN salt_returns ON salt_returns.jid = jids.jid
    WHERE jids.jid = %s;
    '''

    def __init__(self, config):
        self.config = config
        self.db_connection = None

84
    def job_to_dict(self, job, with_returns=True):
85 86 87 88 89 90 91 92 93 94 95 96 97
        dico = {
            "jid": job['jid'],
            "executed": job['executed'],
        }
        if job['fun'] == 'state.apply' and job.get('fun_args') == ['eole.configuration.deploy']:
            dico['command'] = 'deploy'
        else:
            dico["command"] = job['fun']
            if job['fun_args'] is not None:
                dico["arg"] = " ".join(job['fun_args'])
        if job['retcode'] is not None:
            dico["retcode"] = int(job['retcode'])
            dico["success"] = dico['retcode'] == 0
98 99
            if with_returns:
                dico["return"] = job['return']
100 101 102 103 104 105 106 107 108 109 110 111 112 113
            dico["minion"] = job['minion']
        else:
            dico["minion"] = job['target']
        return dico

    def list_jobs(self, cursor, minion_pattern):
        """Fetch SaltStack jobs asynchronously from database

        :return `list`: jobs list as `dict` `{jid: str, completed: bool, fun: str, arg: []str}`
        """
        if not minion_pattern.isalnum():
            raise Exception(_('only alphanum are allowed for a minion ID'))
        rows = cursor.execute(self.fetch_all_jobs % (minion_pattern,))
        for row in cursor.fetchall():
114
            ret = self.job_to_dict(row, False)
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
            if ret is not None:
                yield ret

    def describe_job(self, cursor, jid):
        """Get job information asynchronously from database

        :param `str` jid: identifier of the SaltStack job
        :return `list`: list of job information per minion
        """
        print('Salt jobs: retrieve job “{}” from database'.format(jid))
        cursor.execute(self.fetch_job, (jid,))

        resultset = []
        for row in cursor.fetchall():
            ret = self.job_to_dict(row)
            if ret is not None:
                resultset.append(ret)

        if not len(resultset):
            raise SaltJobsErrorUnknownJobId('The jid “{}” is unknown'.format(jid))
        return resultset