- Automating Tasks in RT
  - Running rt-crontool
  - Testing Tips
- A Simple Search
  - Multiple --Action Parameters
- Auto-resolve Aged Tickets
- Commenting and Corresponding on a Ticket
- Sending Notifications
- Escalating Priority
- Transactions
- Combine multiple actions

# Automating Tasks in RT

As RT tickets are created, worked on, and resolved, there are sometimes updates or notifications that have defined rules and could be automatic. These might include increasing ticket priority over time so tickets don't get lost, resolving old tickets that haven't had any activity for a period of time, or sending email notifications based on some ticket criteria like being 3 days old and still having a status of new.

The tool for automating RT tasks is rt-crontool. It's designed to be run from the cron scheduler and accepts a set of parameters that define what RT objects it should operate on and what it should do. The sections below describe some common rt-crontool tasks as examples of the different ways you can automate tasks.

All of the options for rt-crontool are documented with the tool itself:

        $ perldoc /usr/bin/rt-crontool-5

and on the Best Practical web site.

## Running `rt-crontool`

As you'll see in the examples below, this tool gives full access to RT. To manage the scope of changes that could be performed by the tool, we recommended creating a dedicated unix user with limited privileges for this purpose. Then create a user in RT with just enough access to perform the changes you need to automate, and set the "Unix login" field of the RT user to the username of the unix user you created. See the rt-crontool documentation for more information.

## Testing Tips

When setting up a new automated crontool job, keep in mind that you might be modifying a large number of tickets, especially the first time you run it. Changes to tickets can trigger scrips just like the same change made via the user interface. For example, changing the status to resolved will trigger the 'On Resolve' scrips, which often means sending email. Depending on the modification, you could end up sending a lot of email or triggering other actions.

You can test your TicketSQL search queries in the RT web interface (using the Advanced tab of ticket search), and use bulk update if you want to prepare things for your new automated job. You can also disable scrips which you wish to avoid, or turn off outgoing mail with the "$MailCommand" in RT_Config.pm option. This can be useful if you want to clean up older tickets without sending notifications to requestors for tickets that were resolved years ago.

To help with debugging, the `--verbose` option will give you more output. The `--log` option accepts all of the valid log levels for RT and allows you to change the logging level just for the automated job. While testing, it's often convenient to set:

        --log debug

to see what's happening.

# A Simple Search

Starting with a simple example, this command performs a search and displays output, but doesn't do anything to the returned tickets. This can be useful for safely testing search criteria.

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "Owner = 'root'" \
            --action RT::Action \
            --verbose \
            --log debug

The `--search` argument sets the search module RT should use, in this case RT::Search::FromSQL which processes TicketSQL. The second argument, `--search-arg`, is the search query to use. These are the same queries you create in the RT search interface, so can use the RT web UI to refine your queries before setting up your job.

The `--action` argument is set to RT::Action which is the base class for RT actions. Since this class doesn't perform any action itself, this command will just output the results of the TicketSQL search.

## Multiple --Action Parameters

        /opt/rt4/bin/rt-crontool \
          --search RT::Search::FromSQL \
          --search-arg "Status = 'stalled'" \
          --action RT::Action::SetStatus  --action-arg resolved \
          --action RT::Action::Notify \
              --action-arg 'Requestor' \
              --transaction last \
              --template 'Stalled ticket resolved' \

rt-crontool can take more than one --action parameter to perform multiple steps at a time. In the example above two actions are completed, first the SetStatus action then the Notify action.

# Auto-resolve Aged Tickets

You can auto-set status based on any criteria you can define in a TicketSQL statement. For example, this command will resolve all active tickets that haven't been acted on in a month or more:

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "(Status != 'resolved' AND Status != 'rejected') \
                           AND LastUpdated <= '1 month ago'" \
            --action RT::Action::SetStatus \
            --action-arg resolved

The search is similar to the previous example with a slightly more complicated search argument. Note that since LastUpdated is treated as a timestamp (which increases over time) `LastUpdated <= '1 month ago'` means "the timestamp when it was updated is before the timestamp one month ago" and not "updated less than a month ago."

The `--action` in this case uses the RT::Action::SetStatus module with an `--action-arg` of `resolved`. For each of the tickets returned from the search query, the status is set to resolved. When setting up automated tasks, you can use actions provided as part of RT, actions available from extensions, or actions you create yourself.

As noted previously, the normal RT rules apply when running actions with rt-crontool, so for this example applicable 'On Resolve' scrips will run. If a ticket has unresolved dependencies, it will log an error since tickets can't be resolved until dependencies are resolved. Also, the status argument must be valid for the lifecycle of the selected tickets, and the transition must be allowed.

# Commenting and Corresponding on a Ticket

The following command records a comment on all tickets returned from the query -- in this case, tickets that are new and unowned after 3 days.

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "Owner = 'Nobody' AND Status = 'new' \
                          AND Created < '3 days ago'" \
            --action RT::Action::RecordComment \
            --template 'Unowned tickets'

The RT::Action::RecordComment action does just that, it records a comment just like replying to a comment email or commenting in the RT UI. It uses the global RT template defined by `--template`, so you could put whatever you like in that template. For example:

        Subject: {$Ticket->id} new and unowned
        RT-Send-Cc: support-backup@example.com

        Ticket {$Ticket->id} is still new and unowned after 3 days!

You can set up a similar command to send a reply rather than a comment using the RT::Action::RecordCorrespondence module.

# Sending Notifications

While the example above sends notifications as a side-effect of recording a comment, you can also send notifications directly.

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "(Status != 'resolved' AND Status != 'rejected') \
                          AND Queue = 'Project Work'" \
            --condition RT::Condition::Overdue \
            --action RT::Action::NotifyGroup \
            --action-arg 'project-manager@example.com' \
            --template 'Overdue task'

This example shows the `--condition` argument and the RT::Condition::Overdue module, which returns true if the current time (the time the cron job is running) is past the Due date on the ticket. Like the `--action` argument, you can use conditions provided with RT, added from extensions, or conditions you have created.

RT::Action::NotifyGroup, despite the "Group" in the name, can accept a bare email address or list of addresses as the action argument and it will send mail to them. A combination of email addresses and group names separated by commas also works. RT usernames are valid unless they conflict with group names.

The action sends email, but unlike comment and correspond above, it doesn't record a transaction in the ticket history.

# Escalating Priority

RT has a built-in ticket priority system with priority values from 0 to 99. Depending on how you configure your queues, you can set 1 as the top priority with lower numbers meaning more important, or 99 can be the top priority with higher numbers meaning more important. You can set this in your queue configuration at Tools -> Configuration -> Queues. On the queue configuration page, set "Priority starts at" and "Over time, priority moves toward".

Whichever scheme you choose, RT's RT::Action::EscalatePriority can escalate the priority over time so tickets that are closer to their due date and are still not resolved have priority escalated automatically.

This command escalates tickets in a designated queue:

        /usr/bin/rt-crontool-5 --search RT::Search::ActiveTicketsInQueue \
            --search-arg "General" \
            --action RT::Action::EscalatePriority

The `--search-arg` is the name of the queue in which to escalate tickets. As shown in previous examples, you can also set your criteria using a TicketSQL query as well:

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "(Status='new' OR Status='open') AND Due > 'Jan 1, 1970'" \
            --action RT::Action::EscalatePriority

This example will find new and open tickets in all queues, but will skip tickets with no explicit due dates set. Maybe you only want to bump the priority on tasks that have to be done by a certain date.

RT::Action::LinearEscalate is an alternative escalation module that handles the "Due date not set" condition for you. It also offers some configuration options to control whether a transaction is recorded on the ticket and whether LastUpdated is modified.

# Transactions

Many actions and conditions are also used in RT in scrips and may require a transaction in addition to a ticket. For such cases, rt-crontool provides a `--transaction` argument to designate a transaction. Valid values are `first`, `last`, and `all` and these are relative to the current ticket being processed. `first` and `last` are the first and last transaction on the ticket. Be careful with the `all` option since it will run the action on all transactions for the ticket.

Since actions and conditions can be used in different contexts, you may need to provide a transaction object even if it doesn't seem necessary for your automated job. If you're seeing errors about a missing transaction, setting `--transaction` to `first` or `last` is usually safe and will resolve the error.

You can also target specific transaction types with `--transaction-type`. This argument accepts one or more transaction types as a comma-separated list.

Using these options together, you can set up a command that sets the appropriate transaction object for your conditions and actions. For example, if you had an action you wanted to perform based on the content of the last reply on stalled tickets, you could do something like:

        /usr/bin/rt-crontool-5 --search RT::Search::FromSQL \
            --search-arg "Status = 'stalled' AND Queue = 'General'" \
            --action RT::Action::CheckLastCorrespond \
            --transaction last \
            --transaction-type Correspond

# Combine multiple actions

You can combine multiple actions in a single command. For example, you can set up a command that escalates and increases the priority of overdue tickets that are 'new' or 'stalled', and also changes their status to open.

        /opt/rt5/bin/rt-crontool \
            --search RT::Search::FromSQL \
            --search-arg "(Status='new' OR Status = 'stalled')" \
            --condition RT::Condition::Overdue \
            --action RT::Action::SetPriority \
            --action-arg 99 \
            --action RT::Action::LinearEscalate \
            --action-arg "RecordTransaction: 1" \
            --action RT::Action::SetStatus \
            --action-arg open

As shown above, when using multiple actions, each `--action-arg` must come directly after the `--action` it applies to. Any actions that have no `--action-arg` must be added at the end. If order is important, you may need to add an action argument as a placeholder even if it isn't used.

← Back to index