Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / docs / automating_rt.pod
1 =head1 Automating Tasks in RT
2
3 As RT tickets are created, worked on, and resolved, there are sometimes
4 updates or notifications that have defined rules and could be automatic.
5 These might include increasing ticket priority over time so tickets don't
6 get lost, resolving old tickets that haven't had any activity for a period of
7 time, or sending email notifications based on some ticket criteria like
8 being 3 days old and still having a status of new.
9
10 The tool for automating RT tasks is L<rt-crontool>. It's designed to be
11 run from the cron scheduler and accepts a set of parameters that define
12 what RT objects it should operate on and what it should do. The sections
13 below describe some common L<rt-crontool> tasks as examples of the
14 different ways you can automate tasks.
15
16 All of the options for L<rt-crontool> are documented with the tool itself:
17
18     $ perldoc /opt/rt4/bin/rt-crontool
19
20 and on the Best Practical web site.
21
22 =head2 Running C<rt-crontool>
23
24 As you'll see in the examples below, this tool gives full access to RT.
25 To manage the scope of changes that could be performed by the tool, we
26 recommended creating a dedicated unix user with limited privileges for
27 this purpose. Then create a user in RT with just enough access to
28 perform the changes you need to automate, and set the "Unix login" field
29 of the RT user to the username of the unix user you created. See the
30 L<rt-crontool> documentation for more information.
31
32 =head2 Testing Tips
33
34 When setting up a new automated crontool job, keep in mind that you might be
35 modifying a large number of tickets, especially the first time you run it.
36 Changes to tickets can trigger scrips just like the same change made via
37 the user interface. For example, changing the status to resolved will trigger
38 the 'On Resolve' scrips, which often means sending email. Depending on the
39 modification, you could end up sending a lot of email or triggering other
40 actions.
41
42 You can test your TicketSQL search queries in the RT web interface
43 (using the Advanced tab of ticket search), and use bulk update if you
44 want to prepare things for your new automated job. You can also disable
45 scrips which you wish to avoid, or turn off outgoing mail with the
46 L<RT_Config.pm/"$MailCommand"> option. This can be useful if you want to
47 clean up older tickets without sending notifications to requestors for
48 tickets that were resolved years ago.
49
50 To help with debugging, the C<--verbose> option will give you more output.
51 The C<--log> option accepts all of the valid log levels for RT and allows
52 you to change the logging level just for the automated job. While testing,
53 it's often convenient to set:
54
55     --log debug
56
57 to see what's happening.
58
59 =head1 A Simple Search
60
61 Starting with a simple example, this command performs a search and
62 displays output, but doesn't do anything to the returned tickets.
63 This can be useful for safely testing search criteria.
64
65     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
66         --search-arg "Owner = 'root'" \
67         --action RT::Action \
68         --verbose \
69         --log debug
70
71 The C<--search> argument sets the search module RT should use, in this
72 case L<RT::Search::FromSQL> which processes TicketSQL. The second
73 argument, C<--search-arg>, is the search query to use. These are
74 the same queries you create in the RT search interface, so can use
75 the RT web UI to refine your queries before setting up your job.
76
77 The C<--action> argument is set to L<RT::Action> which is the base class
78 for RT actions. Since this class doesn't perform any action itself, this
79 command will just output the results of the TicketSQL search.
80
81 =head1 Auto-resolve Aged Tickets
82
83 You can auto-set status based on any criteria you can define in
84 a TicketSQL statement. For example, this command will resolve all
85 active tickets that haven't been acted on in a month or more:
86
87     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
88         --search-arg "(Status != 'resolved' AND Status != 'rejected') \
89                        AND LastUpdated <= '1 month ago'" \
90         --action RT::Action::SetStatus \
91         --action-arg resolved
92
93 The search is similar to the previous example with a slightly more
94 complicated search argument.  Note that since LastUpdated is treated as
95 a timestamp (which increases over time) C<LastUpdated <= '1 month ago'>
96 means "the timestamp when it was updated is before the timestamp one
97 month ago" and not "updated less than a month ago."
98
99 The C<--action> in this case uses the L<RT::Action::SetStatus> module
100 with an C<--action-arg> of C<resolved>.  For each of the tickets
101 returned from the search query, the status is set to resolved. When
102 setting up automated tasks, you can use actions provided as part of RT,
103 actions available from extensions, or actions you create yourself.
104
105 As noted previously, the normal RT rules apply when running actions
106 with L<rt-crontool>, so for this example applicable 'On Resolve'
107 scrips will run. If a ticket has unresolved dependencies, it will
108 log an error since tickets can't be resolved until dependencies are
109 resolved. Also, the status argument must be valid for the lifecycle of
110 the selected tickets, and the transition must be allowed.
111
112 =head1 Commenting and Corresponding on a Ticket
113
114 The following command records a comment on all tickets returned from the
115 query -- in this case, tickets that are new and unowned after 3 days.
116
117     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
118         --search-arg "Owner = 'Nobody' AND Status = 'new' \
119                       AND Created < '3 days ago'" \
120         --action RT::Action::RecordComment \
121         --template 'Unowned tickets'
122
123 The L<RT::Action::RecordComment> action does just that, it records a
124 comment just like replying to a comment email or commenting in the
125 RT UI. It uses the global RT template defined by C<--template>, so you
126 could put whatever you like in that template. For example:
127
128     Subject: {$Ticket->id} new and unowned
129     RT-Send-Cc: support-backup@example.com
130
131     Ticket {$Ticket->id} is still new and unowned after 3 days!
132
133 You can set up a similar command to send a reply rather than a comment
134 using the L<RT::Action::RecordCorrespondence> module.
135
136 =head1 Sending Notifications
137
138 While the example above sends notifications as a side-effect of recording
139 a comment, you can also send notifications directly.
140
141     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
142         --search-arg "(Status != 'resolved' AND Status != 'rejected') \
143                       AND Queue = 'Project Work'" \
144         --condition RT::Condition::Overdue \
145         --action RT::Action::NotifyGroup \
146         --action-arg 'project-manager@example.com' \
147         --template 'Overdue task'
148
149 This example shows the C<--condition> argument and the
150 L<RT::Condition::Overdue> module, which returns true if the current
151 time (the time the cron job is running) is past the Due date on the
152 ticket. Like the C<--action> argument, you can use conditions
153 provided with RT, added from extensions, or conditions you have
154 created.
155
156 L<RT::Action::NotifyGroup>, despite the "Group" in the name, can accept a
157 bare email address or list of addresses as the action argument and it will
158 send mail to them. A combination of email addresses and group names separated
159 by commas also works. RT usernames are valid unless they conflict with group
160 names.
161
162 The action sends email, but unlike comment and correspond above, it
163 doesn't record a transaction in the ticket history.
164
165 =head1 Escalating Priority
166
167 RT has a built-in ticket priority system with priority values from
168 0 to 99. Depending on how you configure your queues, you can set 1 as the
169 top priority with lower numbers meaning more important, or 99 can be the
170 top priority with higher numbers meaning more important. You can set this
171 in your queue configuration at Tools -> Configuration -> Queues. On the queue
172 configuration page, set "Priority starts at" and "Over time, priority moves
173 toward".
174
175 Whichever scheme you choose, RT's L<RT::Action::EscalatePriority> can
176 escalate the priority over time so tickets that are closer to their due
177 date and are still not resolved have priority escalated automatically.
178
179 This command escalates tickets in a designated queue:
180
181     /opt/rt4/bin/rt-crontool --search RT::Search::ActiveTicketsInQueue \
182         --search-arg "General" \
183         --action RT::Action::EscalatePriority
184
185 The C<--search-arg> is the name of the queue in which to escalate tickets.
186 As shown in previous examples, you can also set your criteria using a
187 TicketSQL query as well:
188
189     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
190         --search-arg "(Status='new' OR Status='open') AND Due > 'Jan 1, 1970'" \
191         --action RT::Action::EscalatePriority
192
193 This example will find new and open tickets in all queues, but will skip tickets
194 with no explicit due dates set. Maybe you only want to bump the priority on tasks
195 that have to be done by a certain date.
196
197 L<RT::Action::LinearEscalate> is an alternative escalation module that
198 handles the "Due date not set" condition for you. It also offers some
199 configuration options to control whether a transaction is recorded on the
200 ticket and whether LastUpdated is modified.
201
202 =head1 Transactions
203
204 Many actions and conditions are also used in RT in scrips and may require
205 a transaction in addition to a ticket. For such cases, L<rt-crontool>
206 provides a C<--transaction> argument to designate a transaction. Valid
207 values are C<first>, C<last>, and C<all> and these are relative to the
208 current ticket being processed. C<first> and C<last> are the first and
209 last transaction on the ticket. Be careful with the C<all> option since
210 it will run the action on all transactions for the ticket.
211
212 Since actions and conditions can be used in different contexts, you
213 may need to provide a transaction object even if it doesn't seem
214 necessary for your automated job. If you're seeing errors about
215 a missing transaction, setting C<--transaction> to C<first> or
216 C<last> is usually safe and will resolve the error.
217
218 You can also target specific transaction types with C<--transation-type>.
219 This argument accepts one or more transaction types as a comma-separated
220 list.
221
222 Using these options together, you can set up a command that sets the
223 appropriate transaction object for your conditions and actions. For
224 example, if you had an action you wanted to perform based on the content
225 of the last reply on stalled tickets, you could do something like:
226
227     /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
228         --search-arg "Status = 'stalled' AND Queue = 'General'" \
229         --action RT::Action::CheckLastCorrespond \
230         --transaction last \
231         --transaction-type Correspond
232
233
234 =cut