1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Support for schedulers in the database
18 """
19
20 from buildbot.util import json
21 import sqlalchemy as sa
22 import sqlalchemy.exc
23 from twisted.python import log
24 from buildbot.db import base
25
27 """
28 A DBConnectorComponent to handle maintaining schedulers' state in the db.
29 """
30
32 """Get this scheduler's state, as a dictionary. Returs a Deferred"""
33 def thd(conn):
34 schedulers_tbl = self.db.model.schedulers
35 q = sa.select([ schedulers_tbl.c.state ],
36 whereclause=(schedulers_tbl.c.schedulerid == schedulerid))
37 row = conn.execute(q).fetchone()
38 if not row:
39 return {}
40 try:
41 return json.loads(row.state)
42 except:
43 log.msg("JSON error loading state for scheduler #%s" % (schedulerid,))
44 return {}
45 return self.db.pool.do(thd)
46
48 """Set this scheduler's stored state, represented as a JSON-able
49 dictionary. Returs a Deferred. Note that this will overwrite any
50 existing state; be careful with updates!"""
51 def thd(conn):
52 schedulers_tbl = self.db.model.schedulers
53 q = schedulers_tbl.update(
54 whereclause=(schedulers_tbl.c.schedulerid == schedulerid))
55 conn.execute(q, state=json.dumps(state))
56 return self.db.pool.do(thd)
57
58
60 """Record a collection of classifications in the scheduler_changes
61 table. CLASSIFICATIONS is a dictionary mapping CHANGEID to IMPORTANT
62 (boolean). Returns a Deferred."""
63 def thd(conn):
64 tbl = self.db.model.scheduler_changes
65 ins_q = tbl.insert()
66 upd_q = tbl.update(
67 ((tbl.c.schedulerid == schedulerid)
68 & (tbl.c.changeid == sa.bindparam('wc_changeid'))))
69 for changeid, important in classifications.items():
70
71
72 imp_int = important and 1 or 0
73 try:
74 conn.execute(ins_q,
75 schedulerid=schedulerid,
76 changeid=changeid,
77 important=imp_int)
78 except (sqlalchemy.exc.ProgrammingError,
79 sqlalchemy.exc.IntegrityError):
80
81 conn.execute(upd_q,
82 wc_changeid=changeid,
83 important=imp_int)
84
85 return self.db.pool.do(thd)
86
88 """
89 Flush all scheduler_changes for L{schedulerid}, limiting to those less
90 than C{less_than} if the parameter is supplied. Returns a Deferred.
91 """
92 def thd(conn):
93 scheduler_changes_tbl = self.db.model.scheduler_changes
94 wc = (scheduler_changes_tbl.c.schedulerid == schedulerid)
95 if less_than is not None:
96 wc = wc & (scheduler_changes_tbl.c.changeid < less_than)
97 q = scheduler_changes_tbl.delete(whereclause=wc)
98 conn.execute(q)
99 return self.db.pool.do(thd)
100
103 """
104 Return the scheduler_changes rows for this scheduler, in the form of a
105 dictionary mapping changeid to a boolean (important). Returns a
106 Deferred.
107
108 @param schedulerid: scheduler to look up changes for
109 @type schedulerid: integer
110
111 @param branch: limit to changes with this branch
112 @type branch: string or None (for default branch)
113
114 @returns: dictionary via Deferred
115 """
116 def thd(conn):
117 scheduler_changes_tbl = self.db.model.scheduler_changes
118 changes_tbl = self.db.model.changes
119
120 wc = (scheduler_changes_tbl.c.schedulerid == schedulerid)
121 if branch is not self.Thunk:
122 wc = wc & (
123 (scheduler_changes_tbl.c.changeid == changes_tbl.c.changeid) &
124 (changes_tbl.c.branch == branch))
125 q = sa.select(
126 [ scheduler_changes_tbl.c.changeid, scheduler_changes_tbl.c.important ],
127 whereclause=wc)
128 return dict([ (r.changeid, [False,True][r.important]) for r in conn.execute(q) ])
129 return self.db.pool.do(thd)
130
132 """
133 Get the schedulerid for the given scheduler, creating a new schedulerid
134 if none is found.
135
136 Note that this makes no attempt to "claim" the schedulerid: schedulers
137 with the same name and class, but running in different masters, will be
138 assigned the same schedulerid - with disastrous results.
139
140 @param sched_name: the scheduler's configured name
141 @param sched_class: the class name of this scheduler
142 @returns: schedulerid, via a Deferred
143 """
144 def thd(conn):
145
146 schedulers_tbl = self.db.model.schedulers
147 q = schedulers_tbl.select(
148 whereclause=(
149 (schedulers_tbl.c.name == sched_name) &
150 ((schedulers_tbl.c.class_name == sched_class) |
151 (schedulers_tbl.c.class_name == ''))))
152 res = conn.execute(q)
153 row = res.fetchone()
154 res.close()
155
156
157
158
159
160 if not row:
161 q = schedulers_tbl.insert()
162 res = conn.execute(q,
163 name=sched_name,
164 class_name=sched_class,
165 state='{}')
166 return res.inserted_primary_key[0]
167
168
169 if row.class_name == '':
170 q = schedulers_tbl.update(
171 whereclause=(
172 (schedulers_tbl.c.name == sched_name) &
173 (schedulers_tbl.c.class_name == '')))
174 conn.execute(q, class_name=sched_class)
175 return row.schedulerid
176 return self.db.pool.do(thd)
177