blob: d9b6b487aabfa63ca0562d97d8f2279a57c0fd1c [file] [log] [blame]
Lana Brindley5a11bb32014-01-15 14:05:49 +10001Turbo-hipster
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +10002=============
3
Lana Brindley5a11bb32014-01-15 14:05:49 +10004Turbo-hipster works with the existing OpenStack code review system to
5implement testing-related plugins. Historically, whenever code has been
6written for Nova it has been tested against trivial datasets rather than
7real data. This can mean that when users run the updated code on their
8databases they can run into issues that were not found during testing. A
9variety of real-world databases have been collected, anonymized, and added
10to the database migration plugin used by turbo-hipster. Turbo-hipster is
11integrated into the existing code review system, and automatically runs
12tests against these larger test datasets. Turbo-hipster is specifically
13designed to flag issues where changes to the database schema may not work
14due to outliers in real datasets, and to identify situations where a
15migration may take an unreasonable amount of time against a large database.
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +100016
Lana Brindley5a11bb32014-01-15 14:05:49 +100017.. note::
18 Database anonymity is important, and can be very time consuming.
19 The databases used by turbo-hipster to test against are real-world databases
20 that have been anonymized with a database anonymization tool called Fuzzy
21 Happiness. Fuzzy Happiness takes markup in the sqlalchemy models file and
22 uses that to decide what values to anonymize, and how to do so. This feature
23 is still in development, and until it is complete turbo-hipster will not
24 report back to Zuul automatically. See the Release Notes for more detail.
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +100025
Lana Brindley5a11bb32014-01-15 14:05:49 +100026Additionally, turbo-hipster has been designed to be extensible, so it is
27possible to write other plugins to expand its capabilities.
28
29Turbo-hipster and Zuul
30----------------------
31
32Turbo-hipster is a Gearman worker. Zuul provides arguments that turbo-
33hipster uses to check out the patch, perform the database testing, and then
34report back with success or failure. Zuul allows you to specify which jobs
35should be run against which projects. You can create a rule in Zuul for it
36to select jobs that require testing against a database. Turbo-hipster will
37then register as being able to complete that type of job. Gearman handles
38the connection between Zuul and Turbo-Hipster, recognizing when a job
39matches the rule, and passing it to turbo-hipster for testing. When turbo-
40hipster receives the patchset for the job, it creates a virtual environment
41to test it. The result of the test is sent back to Gearman as a json string,
42which contains links to compiled logfiles.
43
44The simplified workflow for Turbo-Hipster:
45
461. Registers as a worker against Zuul's Gearman server
472. Receives jobs from Zuul as they arrive
483. Checks out the patchset
494. Sets up a new virtual environment for testing
505. Loads in a representative subset of the available datasets
516. Runs the migration against each dataset, and checks the result
527. Reports the results to Zuul, using the Gearman protocol
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +100053
54Typical workflow diagram
55------------------------
56
Joshua Hesketh05d01582013-09-09 15:16:08 +100057**clearly this needs a lot of work, however I believe the structure
Joshua Heskethaf26dbb2013-09-11 12:30:38 +100058is mostly there... If you know graphviz please help!**
Joshua Hesketh05d01582013-09-09 15:16:08 +100059
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +100060.. graphviz::
61
62 digraph overview {
63 subgraph cluster_1 {
64 label = "Gerrit"
65 style = filled;
66 color = lightgrey;
67 node [style=filled,color=white];
68
69 g000 [shape=Mdiamond label="start"];
70 g001 [shape=box, label="receive event"];
71 g002 [shape=box, label="notify listeners"];
72
73 g000 -> g001;
74 g001 -> g002;
75 g002 -> g001;
76 }
77
78 subgraph cluster_2 {
79 label = "Zuul pipeline";
80 color = blue
81 node [style=filled];
82
83 z000 [shape=Mdiamond label="start"];
84 z001 [shape=box, label="register gearman server"];
85 z002 [shape=box, label="register launchers"];
86 z003 [shape=box, label="listen for events"];
87 z004 [shape=box, label="receive event"];
88 z005 [shape=box, label="request jobs"];
89 z006 [shape=box, label="receive response"];
90 z007 [shape=box, label="send report"];
91
Joshua Hesketh902ea502013-09-06 11:15:30 +100092 z000 -> z001 -> z002;
93 z003 -> z004 -> z005;
94 z005 -> z006 [dir=none, style=dotted];
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +100095 z006 -> z007;
96
97 }
98
99 subgraph cluster_3 {
100 label = "Gearman";
101 style = filled;
102 color = lightgrey;
103 node [style=filled,color=white];
104
105 gm001 [shape=box, label="receive job method"];
106 gm002 [shape=box, label="request worker do method"];
107 gm003 [shape=box, label="receive results"];
108 gm004 [shape=box, label="return results"];
109
110 gms000 [label="register client"];
111 gms001 [label="register worker"];
112 gms002 [label="register method"];
113
114 gm001 -> gm002;
Joshua Hesketh902ea502013-09-06 11:15:30 +1000115 gm002 -> gm003 [dir=none, style=dotted];
Joshua Hesketh8b0eb6e2013-09-05 13:52:04 +1000116 gm003 -> gm004;
117 }
118
119 subgraph cluster_4 {
120 label = "Turbo Hipster";
121 color = blue
122 node [style=filled];
123
124 th000 [shape=Mdiamond label="start"];
125 th001 [shape=box, label="register as worker"];
126 th002 [shape=box, label="find available tasks"];
127 th003 [shape=box, label="register available job methods"];
128
129 ths001 [shape=box, label="receive method request"];
130 ths002 [shape=box, label="run task"];
131 ths003 [shape=box, label="send results"];
132
133 th000 -> th001 -> th002 -> th003;
134 ths001 -> ths002 -> ths003;
135 }
136
137 z001 -> gms000;
138 z005 -> gm001;
139 gm004 -> z006;
140 z003 -> g002 [dir=both, style=dotted];
141 th001 -> gms001;
142 th003 -> gms002;
143 gm002 -> ths001;
144 ths003 -> gm003;
145
146 }
Joshua Hesketh05d01582013-09-09 15:16:08 +1000147
Lana Brindley5a11bb32014-01-15 14:05:49 +1000148Installation
149============
Joshua Hesketh05d01582013-09-09 15:16:08 +1000150
Lana Brindley5a11bb32014-01-15 14:05:49 +1000151Turbo-hipster is installed directly into your Python ``site-packages``
152directory, and is then run as a service. It is managed using a configuration
153file, which is in .json format.
154
155Installing turbo-hipster
156------------------------
157
1581. Turbo-Hipster can be installed directly to your Python ``site-packages``
159directory::
160
161 $ sudo python setup.py install
162
1632. Copy the configuration file to a convenient location. By default,
164turbo-hipster will look in ``/etc/turbo-hipster/config.json`` ::
165
166 $ cp -R etc/turbo-hipster /etc/
167
1683. The Turbo-Hipster configuration file is in .json format. Open the
169``config.json`` configuration file in your preferred editor and modify it
170for your environment::
171
172 **zuul_server**
173 A dictionary containing details about how to communicate
174 with zuul
175 **git_url**
176 The publicly accessible protocol and URI from where
177 to clone projects and zuul_ references from. For
178 example::
179 http://review.openstack.org/p/
180 or::
181 git://review.example.org
182 **gearman_host**
183 The host of gearman_. zuul talks to its workers via
184 the gearman protocol and while it comes with a built-
185 in gearman server you can use a separate one.
186 **gearman_port**
187 The port that gearman listens on.
188 **debug_log**
189 A path to the debug log. Turbo-hipster will attempt to create
190 the file but must have write permissions.
191 **jobs_working_dir**
192 Each job will likely need to write out log and debug
193 information. This defines where turbo-hipster will do that.
194 **git_working_dir**
195 turbo-hipster needs to take a copy of the git tree of a
196 project to work from. This is the path it'll clone into and
197 work from (if needed).
198 **pip_download_cache**
199 Some of turbo-hipsters task plugins download requirements
200 for projects. This is the cache directory used by pip.
201 **plugins**
202 A list of enabled plugins and their settings in a dictionary.
203 The only required parameters are *name*, which should be the
204 same as the folder containing the plugin module, and
205 *function*, which is the function registered with zuul.
206 Any other parameters are specified by the plugin themselves
207 as required.
208 **publish_logs**
209 Log results from plugins can be published using multiple
210 methods. Currently only a local copy is fully implemented.
211 **type**
212 The type of protocol to copy the log to. eg 'local'
213 **path**
214 A type specific parameter defining the local location
215 destination.
216 **prepend_url**
217 What to prepend to the path when sending the result
218 URL back to zuul. This can be useful as you may want
219 to use a script to authenticate against a swift
220 account or to use *laughing_spice* to format the logs
221 etc.
222
2234. Create a turbo-hipster user:
224
225 $ useradd turbo-hipster
226
2275. Create the directories listed in the configuration file, and give the
228``turbo-hipster`` user write access::
229
230 $ mkdir -p /var/log/turbo-hipster/
231 $ chown turbo-hipster:turbo-hipster /var/log/turbo-hipster/
232
233 $ mkdir -p /var/lib/turbo-hipster/jobs
234 $ chown turbo-hipster:turbo-hipster /var/lib/turbo-hipster/jobs
235
236 $ mkdir -p /var/lib/turbo-hipster/git
237 $ chown turbo-hipster:turbo-hipster /var/lib/turbo-hipster/git
238
239 $ mkdir -p /var/cache/pip
240 $ chown turbo-hipster:turbo-hipster /var/cache/pip
241
2426. Open the MySQL log rotation configuration file in your preferred text
243editor, and edit it to ensure it is writable by ``other``::
244
245 $ vim /etc/logrotate.d/mysql-server
246 # edit create 640 to 644.
247
248.. note::
249 The turbo-hipster source code is also available for download from
250 the `turbo-hipster github page <https://github.com/rcbau/turbo-hipster/>`_
251
252 $ git clone https://github.com/rcbau/turbo-hipster
253
254Starting turbo-hipster
255----------------------
256
257Turbo-hipster can be run from the command line::
258
259 $ ./turbo-hipster/worker_server.py
260
261This option allows you to pass parameters to turbo-hipster. Use the --help
262parameter to see a full list.
263
264+-------+--------------+--------------------------------------------------------+
265| Short | Long | Description |
266+=======+==============+========================================================+
267| -c | --config | Print the path to the configuration file and exit |
268+-------+--------------+--------------------------------------------------------+
269| -b | --background | Run as a daemon in the background |
270+-------+--------------+--------------------------------------------------------+
271| -p | --pidfile | Specify the PID file to lock while running as a daemon |
272+-------+--------------+--------------------------------------------------------+
273
274Alternatively, you can start turbo-hipster as a service.
275
2761. Copy the turbo-hipster init.d script to /etc/init.d/:
277
278 $ sudo cp etc/init.d/turbo-hipster /etc/init.d/
279
2802. Reload the script with the default configuration:
281
282 $ sudo update-rc.d turbo-hipster defaults
283
2843. Start the service:
285
286 $ sudo service turbo-hipster start
287
288Plugins
289=======
290
291Plugins can be used to extend turbo-hipster's capabilities.
292
293.. note::
294 Currently, the only available plugin for turbo-hipster is the
295 Database Migration plugin, ``gate_real_db_upgrade``, which tests code
296 against a variety of real-world databases.
297
298Installing plugins
299------------------
300
301Turbo-hipster plugins are responsible for handling the jobs that are passed
302to it. They must successfully build reports and publish them according to
303their configuration. They must also be able to communicate test results back
304to Zuul using Gearman.
305
306Plugins must take a standard format in order to be able to work correctly
307with turbo-hipster. They must contain a ``task.py`` file with a ``Runner``
308class.
309
310Once you have created a turbo-hipster plugin, you need to configure it in
311the ``config.json`` configuration file.
312
313.. FIXME More config information required here
314
315Plugin: Database migration with ``gate_real_db_upgrade``
316--------------------------------------------------------
317
318The database migration plugin, ``gate_real_db_upgrade``, is used to test
319datasets against real-world, anonymized, databases.
320
321Migrating a database
322--------------------
323
324In order to use turbo-hipster with the ``gate_real_db_upgrade`` plugin, you
325need to set up the databases to test against, and point to the plugin in
326turbo-hipster's configuration file.
327
3281. Create a directory for the datasets:
329
330 $ mkdir -p /var/lib/turbo-hipster/datasets
331
3322. Copy the json dataset to the directory you created:
333
334 $ cp /my/dataset.json /var/lib/turbo-hipster/datasets/
335
3363. Open the ``/etc/turbo-hipster/config.json`` file in your preferred
337editor, locate the plugins section, and add this line::
338
339 **plugins**
340 gate_real_db_upgrade
341
342Testing with turbo-hipster
343==========================
344
345When turbo-hipster completes a test, it sends the result of the test back to
346Gearman. These results contain a link to a compiled logfile for the test.
347
348If the test fails, or takes too long to complete, turbo-hipster will add a
349review to your patchset that looks like this:
350
351.. image:: ../images/THTestResult.png
352
353Reading test reports
354--------------------
355
356An example of a standard log file:
357http://thw01.rcbops.com/results/54/54202/5/check/gate-real-db-upgrade_nova_mysql_devstack_150/ddd6d53/20130910_devstack_applied_to_150.log
358
359An example of the same logfile, using the javascript logviewer:
360http://thw01.rcbops.com/logviewer/?q=/results/54/54202/5/check/gate-real-db-upgrade_nova_mysql_devstack_150/ddd6d53/20130910_devstack_applied_to_150.log
361
362Test failure codes
363------------------
364
365This section gives a list of failure codes, including some steps you can
366take for troubleshooting errors:
367
368 FAILURE - Did not find the end of a migration after a start
369
370If you look at the log you should find that a migration began but never
371finished. Hopefully there'll be a traceroute for you to follow through to
372get some hints about why it failed.
373
374 WARNING - Migration %s took too long
375
376In this case your migration took a long time to run against one of the test
377datasets. You should reconsider what operations your migration is performing
378and see if there are any optimizations you can make, or if it is really
379necessary. If there is no way to speed up your migration you can email us at
380rcbau@rcbops.com for an exception.
381
382 FAILURE - Final schema version does not match expectation
383
384Somewhere along the line the migrations stopped and did not reach the
385expected version. Our datasets start at previous releases and have to
386upgrade all the way through to the most current release. If you see this,
387inspect the log for traceroutes or other hints about the failure.
388
389 FAILURE - Could not setup seed database.
390 FAILURE - Could not find seed database.
391
392These errors are internal errors. If you see either of these, contact us at
393rcbau@rcbops.com to let us know so we can fix and rerun the tests for you.
394
395 FAILURE - Could not import required module.
396
397This error probably shouldn't happen as Jenkins should catch it in the unit
398tests before Turbo-Hipster launches. If you see this, please contact us at
399rcbau@rcbops.com and let us know.
400
401If you receive an error that you think is a false positive, leave a comment
402on the review with the sole contents of "recheck migrations".
403
404If you have any questions/problems please contact us at rcbau@rcbops.com.