Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 1 | # Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """Django database Router |
| 6 | |
| 7 | Django gets configured with three database connections in frontend/settings.py. |
| 8 | - The default database |
| 9 | - This database should be used for most things. |
| 10 | - For the master, this is the global database. |
| 11 | - For shards, this this is the shard-local database. |
| 12 | - The global database |
| 13 | - For the master, this is the same database as default, which is the global |
| 14 | database. |
| 15 | - For the shards, this is the global database (the same as for the master). |
| 16 | - The readonly connection |
| 17 | - This should be the same database as the global database, but it should |
| 18 | use an account on the database that only has readonly permissions. |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 19 | - The server database |
| 20 | - This is the database stores information about all servers in the Autotest |
| 21 | instance. Each instance, master or shard should have its own server |
| 22 | database is use_server_db is enabled in global config. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 23 | |
| 24 | The reason shards need two distinct databases for different objects is, that |
| 25 | the tko parser should always write to the global database. Otherwise test |
| 26 | results wouldn't be synced back to the master and would not be accessible in one |
| 27 | place. |
| 28 | |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 29 | Therefore this class will route all queries for tables starts with `server` |
| 30 | prefix to server database, route all queries for tables that involve |
| 31 | `tko_`-prefixed tables to the global database. For all others this router will |
| 32 | not give a hint, which means the default database will be used. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 33 | """ |
| 34 | |
| 35 | class Router(object): |
| 36 | """ |
| 37 | Decide if an object should be written to the default or to the global db. |
| 38 | |
| 39 | This is an implementaton of Django's multi-database router interface: |
| 40 | https://docs.djangoproject.com/en/1.5/topics/db/multi-db/ |
| 41 | """ |
| 42 | |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 43 | def _should_be_in_server_db(self, model): |
| 44 | """Return True if the model should be stored in the server db. |
| 45 | |
| 46 | @param model: Model to decide for. |
| 47 | |
| 48 | @return: True if querying the model requires server database. |
| 49 | """ |
| 50 | return model._meta.db_table.startswith('server') |
| 51 | |
| 52 | |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 53 | def _should_be_in_global(self, model): |
| 54 | """Returns True if the model should be stored in the global db. |
| 55 | |
| 56 | @param model: Model to decide for. |
| 57 | |
| 58 | @return: True if querying the model requires global database. |
| 59 | """ |
| 60 | return model._meta.db_table.startswith('tko_') |
| 61 | |
| 62 | |
| 63 | def db_for_read(self, model, **hints): |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 64 | """Return the database for a reading access. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 65 | |
| 66 | @param model: Model to decide for. |
| 67 | @param hints: Optional arguments to determine which database for read. |
| 68 | |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 69 | @returns: 'server' for all server models. 'global' for all tko models, |
| 70 | None otherwise. None means the router doesn't have an opinion. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 71 | """ |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 72 | if self._should_be_in_server_db(model): |
| 73 | return 'server' |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 74 | if self._should_be_in_global(model): |
| 75 | return 'global' |
| 76 | return None |
| 77 | |
| 78 | |
| 79 | def db_for_write(self, model, **hints): |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 80 | """Return the database for a writing access. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 81 | |
| 82 | @param model: Model to decide for. |
| 83 | @param hints: Optional arguments to determine which database for write. |
| 84 | |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 85 | @returns: 'server' for all server models. 'global' for all tko models, |
| 86 | None otherwise. None means the router doesn't have an opinion. |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 87 | """ |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 88 | if self._should_be_in_server_db(model): |
| 89 | return 'server' |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 90 | if self._should_be_in_global(model): |
| 91 | return 'global' |
| 92 | return None |
| 93 | |
| 94 | |
| 95 | def allow_relation(self, obj1, obj2, **hints): |
| 96 | """ |
| 97 | Allow relations only if either both are in tko_ tables or none is. |
| 98 | |
| 99 | @param obj1: First object involved in the relation. |
| 100 | @param obj2: Second object involved in the relation. |
| 101 | @param hints: Optional arguments to determine if relation is allowed. |
| 102 | |
| 103 | @returns False, if the relation should be prohibited, |
| 104 | None, if the router doesn't have an opinion. |
| 105 | """ |
Dan Shi | 9a535c9 | 2014-11-24 08:52:40 -0800 | [diff] [blame] | 106 | if (not self._should_be_in_server_db(type(obj1)) == |
| 107 | self._should_be_in_server_db(type(obj2))): |
| 108 | return False |
Jakob Juelich | 8a764d1 | 2014-10-14 19:24:21 -0700 | [diff] [blame] | 109 | if (not self._should_be_in_global(type(obj1)) == |
| 110 | self._should_be_in_global(type(obj2))): |
| 111 | return False |
| 112 | return None |