Merge lp:~eday/burrow/backend-api-cleanup into lp:burrow

Proposed by Eric Day
Status: Merged
Approved by: Eric Day
Approved revision: 11
Merged at revision: 4
Proposed branch: lp:~eday/burrow/backend-api-cleanup
Merge into: lp:burrow
Diff against target: 1944 lines (+980/-436)
17 files modified
ChangeLog (+40/-0)
bin/burrow (+154/-0)
bin/burrowd (+4/-4)
burrow/__init__.py (+6/-77)
burrow/backend/__init__.py (+52/-50)
burrow/backend/http.py (+103/-0)
burrow/backend/memory.py (+217/-99)
burrow/backend/sqlite.py (+160/-123)
burrow/client.py (+63/-0)
burrow/config.py (+1/-1)
burrow/frontend/__init__.py (+6/-6)
burrow/frontend/wsgi.py (+52/-52)
burrow/server.py (+95/-0)
etc/burrowd.conf (+9/-9)
locale/burrow.pot (+8/-8)
setup.py (+4/-1)
test/frontend/test_wsgi.py (+6/-6)
To merge this branch: bzr merge lp:~eday/burrow/backend-api-cleanup
Reviewer Review Type Date Requested Status
Burrow Core Team Pending
Review via email: mp+56510@code.launchpad.net

Description of the change

A number of cleanup tasks and client support.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'ChangeLog'
--- ChangeLog 2011-03-18 00:47:26 +0000
+++ ChangeLog 2011-04-06 05:49:23 +0000
@@ -1,3 +1,43 @@
12011-03-30 Eric Day <eday@oddments.org>
2
3 Merged burrow and burrowd packages, the interfaces for backend/client can be shared, and this will also allow modular in-process queues.
4
52011-03-18 Eric Day <eday@oddments.org>
6
7 Started SQLite backend cleanup.
8
92011-03-18 Eric Day <eday@oddments.org>
10
11 More backend API cleanup.
12
132011-03-18 Eric Day <eday@oddments.org>
14
15 Further backend API cleanup, started cleanup in memory backend.
16
172011-03-17 Eric Day <eday@oddments.org>
18
19 Removed the need to 'queue_exists' decorator and backend methods.
20
212011-03-17 Eric Day <eday@oddments.org>
22
23 Switched to pass attributes as a dict instead of positional arguments.
24
252011-03-17 Eric Day <eday@oddments.org>
26
27 Switched to pass filters as a dict instead of positional arguments.
28
292011-03-18 Eric Day <eday@oddments.org>
30
31 Started locale support.
32
332011-03-17 Eric Day <eday@oddments.org>
34
35 Started locale support.
36
372011-03-17 Eric Day <eday@oddments.org>
38
39 Python prototype conversion to get new trunk started.
40
12011-03-17 Eric Day <eday@oddments.org>412011-03-17 Eric Day <eday@oddments.org>
242
3 First chunk of code from prototype. Beyond the prototype, configuration, module loading, and log handling was added.43 First chunk of code from prototype. Beyond the prototype, configuration, module loading, and log handling was added.
444
=== modified file 'bin/burrow'
--- bin/burrow 2011-03-17 23:42:41 +0000
+++ bin/burrow 2011-04-06 05:49:23 +0000
@@ -16,3 +16,157 @@
16'''16'''
17Burrow command line client.17Burrow command line client.
18'''18'''
19
20import pwd
21import optparse
22import os
23import sys
24
25# If ../burrow/__init__.py exists, add ../ to the Python search path so
26# that it will override whatever may be installed in the default Python
27# search path.
28BASE_DIRECTORY = os.path.join(os.path.abspath(__file__), os.pardir, os.pardir)
29BASE_DIRECTORY = os.path.normpath(BASE_DIRECTORY)
30if os.path.exists(os.path.join(BASE_DIRECTORY, 'burrow', '__init__.py')):
31 sys.path.insert(0, BASE_DIRECTORY)
32
33import burrow
34
35
36class Burrow(object):
37
38 sections = [
39 dict(name='Global',
40 filters=True,
41 args=[],
42 commands=['delete_accounts', 'get_accounts']),
43 dict(name='Account',
44 account=True,
45 filters=True,
46 args=[],
47 commands=['delete_queues', 'get_queues']),
48 dict(name='Queue',
49 account=True,
50 filters=True,
51 args=['queue'],
52 commands=['delete_messages', 'get_messages', 'update_messages']),
53 dict(name='Message',
54 account=True,
55 args=['queue', 'message'],
56 commands=[
57 'create_message',
58 'delete_message',
59 'get_message',
60 'update_message'])]
61
62 attribute_commands = [
63 'update_messages',
64 'create_message',
65 'update_message']
66
67 stdin_commands = ['create_message']
68
69 def __init__(self):
70 self.parser = optparse.OptionParser(version=burrow.__version__)
71 self.parser.add_option('-c', '--commands', action='store_true',
72 help=_('Print help for the available commands'))
73 self.parser.add_option('-u', '--url', default='http://localhost:8080',
74 help=_('Backend URL to use'))
75 rcfile = os.path.expanduser('~')
76 rcfile = os.path.join(rcfile, '.burrowrc')
77 if not os.path.exists(rcfile):
78 rcfile = None
79 self.parser.add_option('-f', '--files', default=rcfile,
80 help=_('Configuration file(s) to use (comma separated)'))
81 user = pwd.getpwuid(os.getuid())[0]
82 self.parser.add_option('-a', '--account', default=user,
83 help=_('Account to use for queue and message commands'))
84 self.parser.add_option('-w', '--wait',
85 help=_('Number of seconds to wait if no messages match'))
86
87 attributes = optparse.OptionGroup(self.parser,
88 _('Messages attribute options'))
89 attributes.add_option('-t', '--ttl',
90 help=_('TTL attribute in seconds to set for message(s)'))
91 attributes.add_option('-H', '--hide',
92 help=_('Hidden time attribute in seconds to set for message(s)'))
93 self.parser.add_option_group(attributes)
94
95 filters = optparse.OptionGroup(self.parser, _('Filtering options'))
96 filters.add_option('-l', '--limit',
97 help=_('Limit the number of messages to match'))
98 filters.add_option('-m', '--marker',
99 help=_('Only match messages that were inserted after this id'))
100 filters.add_option('-A', '--all', action='store_true',
101 help=_('Match all messages, including those that are hidden'))
102 choices = ['none', 'id', 'attributes', 'all']
103 filters.add_option('-d', '--detail', type='choice', choices=choices,
104 help=_('What message information to return. Options are: %s') %
105 ', '.join(choices))
106 self.parser.add_option_group(filters)
107
108 def run(self):
109 (self.options, args) = self.parser.parse_args()
110 if self.options.commands:
111 self.print_help()
112 if len(args) == 0:
113 self.print_help(_('No command given'))
114 if self.options.files is None:
115 files = []
116 else:
117 files = self.options.files.split(', ')
118 self.client = burrow.Client(url=self.options.url, config_files=files)
119 for section in self.sections:
120 if args[0] in section['commands']:
121 self.run_command(section, args[0], args[1:])
122 self.print_help(_('Command not found'))
123
124 def run_command(self, section, command, args):
125 if len(args) != len(section['args']):
126 self.print_help(_('Wrong number of arguments'))
127 if section.get('account', None):
128 args.insert(0, self.options.account)
129 if command in self.stdin_commands:
130 args.append(sys.stdin.read())
131 if command in self.attribute_commands:
132 attributes = {}
133 if self.options.ttl is not None:
134 attributes['ttl'] = self.options.ttl
135 if self.options.hide is not None:
136 attributes['hide'] = self.options.hide
137 args.append(attributes)
138 if section.get('filters', None):
139 filters = {}
140 if self.options.limit is not None:
141 filters['limit'] = self.options.limit
142 if self.options.marker is not None:
143 filters['marker'] = self.options.marker
144 if self.options.all is not None:
145 filters['match_hidden'] = self.options.all
146 args.append(filters)
147 getattr(self.client.backend, command)(*args)
148 sys.exit(0)
149
150 def print_help(self, message=None):
151 if message:
152 print message
153 print
154 self.parser.print_help()
155 print
156 for section in self.sections:
157 print '%s commands:' % section['name']
158 for command in section['commands']:
159 help = ''
160 if section.get('filters', None):
161 help += ' [filters]'
162 if command in self.attribute_commands:
163 help += ' [attributes]'
164 for arg in section['args']:
165 help += ' <%s>' % arg
166 print ' %s%s' % (command, help)
167 print
168 sys.exit(1)
169
170
171if __name__ == '__main__':
172 Burrow().run()
19173
=== modified file 'bin/burrowd'
--- bin/burrowd 2011-03-17 23:42:41 +0000
+++ bin/burrowd 2011-04-06 05:49:23 +0000
@@ -20,15 +20,15 @@
20import os20import os
21import sys21import sys
2222
23# If ../burrowd/__init__.py exists, add ../ to the Python search path so23# If ../burrow/__init__.py exists, add ../ to the Python search path so
24# that it will override whatever may be installed in the default Python24# that it will override whatever may be installed in the default Python
25# search path.25# search path.
26BASE_DIRECTORY = os.path.join(os.path.abspath(__file__), os.pardir, os.pardir)26BASE_DIRECTORY = os.path.join(os.path.abspath(__file__), os.pardir, os.pardir)
27BASE_DIRECTORY = os.path.normpath(BASE_DIRECTORY)27BASE_DIRECTORY = os.path.normpath(BASE_DIRECTORY)
28if os.path.exists(os.path.join(BASE_DIRECTORY, 'burrowd', '__init__.py')):28if os.path.exists(os.path.join(BASE_DIRECTORY, 'burrow', '__init__.py')):
29 sys.path.insert(0, BASE_DIRECTORY)29 sys.path.insert(0, BASE_DIRECTORY)
3030
31import burrowd31import burrow
3232
33if __name__ == '__main__':33if __name__ == '__main__':
34 burrowd.Burrowd(sys.argv[1:]).run()34 burrow.Server(sys.argv[1:]).run()
3535
=== removed directory 'burrow'
=== renamed directory 'burrowd' => 'burrow'
=== removed file 'burrow/__init__.py'
--- burrow/__init__.py 2011-03-17 23:42:41 +0000
+++ burrow/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
1# Copyright (C) 2011 OpenStack LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15'''Main client module for burrow.'''
16
17
18class Burrow(object):
19 pass
200
=== modified file 'burrow/__init__.py'
--- burrowd/__init__.py 2011-03-18 00:47:26 +0000
+++ burrow/__init__.py 2011-04-06 05:49:23 +0000
@@ -12,99 +12,28 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Main server module for burrow.'''15'''Main module for burrow.'''
1616
17import ConfigParser
18import gettext17import gettext
19import logging18import logging
20import logging.config
21import sys19import sys
2220
23import eventlet21from burrow.client import Client
22from burrow.server import Server
23import burrow.config
2424
25import burrowd.config25__version__ = '0.1'
2626
27# This installs the _(...) function as a built-in so all other modules27# This installs the _(...) function as a built-in so all other modules
28# don't need to.28# don't need to.
29gettext.install('burrow')29gettext.install('burrow')
3030
31# Default configuration values for this module.
32DEFAULT_BACKEND = 'burrowd.backend.sqlite'
33DEFAULT_FRONTENDS = 'burrowd.frontend.wsgi'
34DEFAULT_THREAD_POOL_SIZE = 1000
35
36
37class Burrowd(object):
38 '''Server class for burrow.'''
39
40 def __init__(self, config_files=[], add_default_log_handler=True):
41 '''Initialize a server using the config files from the given
42 list. This is passed directly to ConfigParser.read(), so
43 files should be in ConfigParser format. This will load all
44 frontend and backend classes from the configuration.'''
45 if len(config_files) > 0:
46 logging.config.fileConfig(config_files)
47 self._config = ConfigParser.ConfigParser()
48 self._config.read(config_files)
49 self.config = burrowd.config.Config(self._config, 'burrowd')
50 self.log = get_logger(self.config)
51 if add_default_log_handler:
52 self._add_default_log_handler()
53 self._import_backend()
54 self._import_frontends()
55
56 def _add_default_log_handler(self):
57 '''Add a default log handler it one has not been set.'''
58 root_log = logging.getLogger()
59 if len(root_log.handlers) > 0 or len(self.log.handlers) > 0:
60 return
61 handler = logging.StreamHandler()
62 handler.setLevel(logging.DEBUG)
63 log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
64 handler.setFormatter(logging.Formatter(log_format))
65 root_log.addHandler(handler)
66
67 def _import_backend(self):
68 '''Load backend given in the 'backend' option.'''
69 backend = self.config.get('backend', DEFAULT_BACKEND)
70 config = (self._config, backend)
71 self.backend = import_class(backend, 'Backend')(config)
72
73 def _import_frontends(self):
74 '''Load frontends given in the 'frontends' option.'''
75 self.frontends = []
76 frontends = self.config.get('frontends', DEFAULT_FRONTENDS)
77 for frontend in frontends.split(','):
78 frontend = frontend.split(':')
79 if len(frontend) == 1:
80 frontend.append(None)
81 config = (self._config, frontend[0], frontend[1])
82 frontend = import_class(frontend[0], 'Frontend')
83 frontend = frontend(config, self.backend)
84 self.frontends.append(frontend)
85
86 def run(self):
87 '''Create the thread pool and start the main server loop. Wait
88 for the pool to complete, but possibly run forever if the
89 frontends and backend never remove threads.'''
90 thread_pool_size = self.config.getint('thread_pool_size',
91 DEFAULT_THREAD_POOL_SIZE)
92 thread_pool = eventlet.GreenPool(size=int(thread_pool_size))
93 self.backend.run(thread_pool)
94 for frontend in self.frontends:
95 frontend.run(thread_pool)
96 self.log.info(_('Waiting for all threads to exit'))
97 try:
98 thread_pool.waitall()
99 except KeyboardInterrupt:
100 pass
101
10231
103class Module(object):32class Module(object):
104 '''Common module class for burrow.'''33 '''Common module class for burrow.'''
10534
106 def __init__(self, config):35 def __init__(self, config):
107 self.config = burrowd.config.Config(*config)36 self.config = burrow.config.Config(*config)
108 self.log = get_logger(self.config)37 self.log = get_logger(self.config)
109 self.log.debug(_('Module created'))38 self.log.debug(_('Module created'))
11039
11140
=== modified file 'burrow/backend/__init__.py'
--- burrowd/backend/__init__.py 2011-03-17 23:42:41 +0000
+++ burrow/backend/__init__.py 2011-04-06 05:49:23 +0000
@@ -12,14 +12,14 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Backends for the burrow server.'''15'''Backends for burrow.'''
1616
17import eventlet17import eventlet
1818
19import burrowd19import burrow
2020
2121
22class Backend(burrowd.Module):22class Backend(burrow.Module):
23 '''Interface that backend implementations must provide.'''23 '''Interface that backend implementations must provide.'''
2424
25 def __init__(self, config):25 def __init__(self, config):
@@ -27,62 +27,52 @@
27 self.queues = {}27 self.queues = {}
2828
29 def run(self, thread_pool):29 def run(self, thread_pool):
30 '''Run the backend. This should start any periodic tasks in
31 separate threads and should never block.'''
30 thread_pool.spawn_n(self._clean)32 thread_pool.spawn_n(self._clean)
3133
32 def _clean(self):34 def delete_accounts(self, filters={}):
33 while True:35 pass
34 self.clean()36
35 eventlet.sleep(1)37 def get_accounts(self, filters={}):
3638 return []
37 def delete_accounts(self):39
38 pass40 def delete_queues(self, account, filters={}):
3941 pass
40 def get_accounts(self):42
41 return []43 def get_queues(self, account, filters={}):
4244 return []
43 def delete_account(self, account):45
44 pass46 def delete_messages(self, account, queue, filters={}):
4547 return []
46 def get_queues(self, account):48
47 return []49 def get_messages(self, account, queue, filters={}):
4850 return []
49 def queue_exists(self, account, queue):51
50 return False52 def update_messages(self, account, queue, attributes={}, filters={}):
5153 return []
52 def delete_messages(self, account, queue, limit, marker, match_hidden):54
53 return []55 def create_message(self, account, queue, message, body, attributes={}):
54
55 def get_messages(self, account, queue, limit, marker, match_hidden):
56 return []
57
58 def update_messages(self, account, queue, limit, marker, match_hidden, ttl,
59 hide):
60 return []
61
62 def delete_message(self, account, queue, message_id):
63 return None
64
65 def get_message(self, account, queue, message_id):
66 return None
67
68 def put_message(self, account, queue, message_id, ttl, hide, body):
69 return True56 return True
7057
71 def update_message(self, account, queue, message_id, ttl, hide):58 def delete_message(self, account, queue, message):
72 return None59 return None
7360
74 def clean(self):61 def get_message(self, account, queue, message):
75 '''This method should remove all messages with an expired62 return None
76 TTL and make hidden messages that have an expired hide time63
77 visible again.'''64 def update_message(self, account, queue, message, attributes={}):
78 pass65 return None
7966
80 def notify(self, account, queue):67 def notify(self, account, queue):
68 '''Notify any waiting callers that the account/queue has
69 a visible message.'''
81 queue = '%s/%s' % (account, queue)70 queue = '%s/%s' % (account, queue)
82 if queue in self.queues:71 if queue in self.queues:
83 self.queues[queue].put(0)72 self.queues[queue].put(0)
8473
85 def wait(self, account, queue, seconds):74 def wait(self, account, queue, seconds):
75 '''Wait for a message to appear in the account/queue.'''
86 queue = '%s/%s' % (account, queue)76 queue = '%s/%s' % (account, queue)
87 if queue not in self.queues:77 if queue not in self.queues:
88 self.queues[queue] = eventlet.Queue()78 self.queues[queue] = eventlet.Queue()
@@ -92,3 +82,15 @@
92 pass82 pass
93 if self.queues[queue].getting() == 0:83 if self.queues[queue].getting() == 0:
94 del self.queues[queue]84 del self.queues[queue]
85
86 def clean(self):
87 '''This method should remove all messages with an expired
88 TTL and make hidden messages that have an expired hide time
89 visible again.'''
90 pass
91
92 def _clean(self):
93 '''Thread to run the clean method periodically.'''
94 while True:
95 self.clean()
96 eventlet.sleep(1)
9597
=== added file 'burrow/backend/http.py'
--- burrow/backend/http.py 1970-01-01 00:00:00 +0000
+++ burrow/backend/http.py 2011-04-06 05:49:23 +0000
@@ -0,0 +1,103 @@
1# Copyright (C) 2011 OpenStack LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15'''HTTP backend for burrow using httplib.'''
16
17import httplib
18
19import burrow.backend
20
21
22class Backend(burrow.backend.Backend):
23 '''This backend forwards all requests via HTTP using the httplib
24 module. It is used for clients and proxies.'''
25
26 def __init__(self, config):
27 super(Backend, self).__init__(config)
28 self.server = ('localhost', 8080)
29
30 def delete_accounts(self, filters={}):
31 url = self._add_parameters('/', filters=filters)
32 self._request('DELETE', url)
33
34 def get_accounts(self, filters={}):
35 url = self._add_parameters('/', filters=filters)
36 self._request('GET', url)
37
38 def delete_queues(self, account, filters={}):
39 url = self._add_parameters('/%s' % account, filters=filters)
40 self._request('DELETE', url)
41
42 def get_queues(self, account, filters={}):
43 url = self._add_parameters('/%s' % account, filters=filters)
44 self._request('GET', url)
45
46 def delete_messages(self, account, queue, filters={}):
47 url = '/%s/%s' % (account, queue)
48 url = self._add_parameters(url, filters=filters)
49 self._request('DELETE', url)
50
51 def get_messages(self, account, queue, filters={}):
52 url = '/%s/%s' % (account, queue)
53 url = self._add_parameters(url, filters=filters)
54 self._request('GET', url)
55
56 def update_messages(self, account, queue, attributes={}, filters={}):
57 url = '/%s/%s' % (account, queue)
58 url = self._add_parameters(url, attributes, filters)
59 self._request('POST', url)
60
61 def create_message(self, account, queue, message, body, attributes={}):
62 url = '/%s/%s/%s' % (account, queue, message)
63 url = self._add_parameters(url, attributes)
64 self._request('PUT', url, body=body)
65
66 def delete_message(self, account, queue, message):
67 url = '/%s/%s/%s' % (account, queue, message)
68 self._request('DELETE', url)
69
70 def get_message(self, account, queue, message):
71 url = '/%s/%s/%s' % (account, queue, message)
72 self._request('GET', url)
73
74 def update_message(self, account, queue, message, attributes={}):
75 url = '/%s/%s/%s' % (account, queue, message)
76 url = self._add_parameters(url, attributes)
77 self._request('POST', url)
78
79 def clean(self):
80 pass
81
82 def _add_parameters(self, url, attributes={}, filters={}):
83 separator = '?'
84 for attribute in ['ttl', 'hide']:
85 value = attributes.get(attribute, None)
86 if value is not None:
87 url += '%s%s=%s' % (separator, attribute, value)
88 separator = '&'
89 for filter in ['marker', 'limit', 'match_hidden', 'detail']:
90 value = filters.get(filter, None)
91 if value is not None:
92 url += '%s%s=%s' % (separator, filter, value)
93 separator = '&'
94 return url
95
96 def _request(self, *args, **kwargs):
97 connection = httplib.HTTPConnection(*self.server)
98 connection.request(*args, **kwargs)
99 response = connection.getresponse()
100 if response.status == 200:
101 print response.read()
102 if response.status >= 400:
103 print response.reason
0104
=== modified file 'burrow/backend/memory.py'
--- burrowd/backend/memory.py 2011-03-17 23:42:41 +0000
+++ burrow/backend/memory.py 2011-04-06 05:49:23 +0000
@@ -12,115 +12,117 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Memory backend for the burrow server.'''15'''Memory backend for burrow.'''
1616
17import time17import time
1818
19import burrowd.backend19import burrow.backend
2020
2121
22class Backend(burrowd.backend.Backend):22class Backend(burrow.backend.Backend):
23 '''This backend stores all data using native Python data
24 structures. It uses a linked list of tuples to store data
25 (accounts, queues, and messages) with a dict as a secondary index
26 into this list. This is required so we can have O(1) appends,
27 deletes, and lookups by name, along with easy traversal starting
28 anywhere in the list.'''
2329
24 def __init__(self, config):30 def __init__(self, config):
25 super(Backend, self).__init__(config)31 super(Backend, self).__init__(config)
26 self.accounts = {}32 self.accounts = Accounts()
2733
28 def delete_accounts(self):34 def delete_accounts(self, filters={}):
29 self.accounts.clear()35 self.accounts.delete(filters)
3036
31 def get_accounts(self):37 def get_accounts(self, filters={}):
32 return self.accounts.keys()38 for account in self.accounts.iter(filters):
3339 yield account[0]
34 def delete_account(self, account):40
35 del self.accounts[account]41 def delete_queues(self, account, filters={}):
3642 self.accounts.delete_queues(account, filters)
37 def get_queues(self, account):43
38 if account not in self.accounts:44 def get_queues(self, account, filters={}):
39 return []45 for queue in self.accounts.iter_queues(account, filters):
40 return self.accounts[account].keys()46 yield queue[0]
4147
42 def queue_exists(self, account, queue):48 def delete_messages(self, account, queue, filters={}):
43 return account in self.accounts and queue in self.accounts[account]49 return self._scan_queue(account, queue, filters, delete=True)
4450
45 def delete_messages(self, account, queue, limit, marker, match_hidden):51 def get_messages(self, account, queue, filters={}):
46 messages = self._scan_queue(account, queue, limit, marker,52 return self._scan_queue(account, queue, filters)
47 match_hidden, delete=True)53
48 if len(self.accounts[account][queue]) == 0:54 def update_messages(self, account, queue, attributes={}, filters={}):
49 del self.accounts[account][queue]55 return self._scan_queue(account, queue, filters, attributes)
50 if len(self.accounts[account]) == 0:56
51 del self.accounts[account]57 def create_message(self, account, queue, message, body, attributes={}):
52 return messages58 account, queue = self.accounts.get_queue(account, queue, True)
5359 ttl = attributes.get('ttl', 0)
54 def get_messages(self, account, queue, limit, marker, match_hidden):60 hide = attributes.get('hide', 0)
55 return self._scan_queue(account, queue, limit, marker, match_hidden)61 for index in xrange(0, len(queue[3])):
5662 if queue[3][index]['id'] == message:
57 def update_messages(self, account, queue, limit, marker, match_hidden, ttl,63 message = queue[3][index]
58 hide):
59 return self._scan_queue(account, queue, limit, marker, match_hidden,
60 ttl=ttl, hide=hide)
61
62 def delete_message(self, account, queue, message_id):
63 for index in range(0, len(self.accounts[account][queue])):
64 message = self.accounts[account][queue][index]
65 if message['id'] == message_id:
66 del self.accounts[account][queue][index]
67 if len(self.accounts[account][queue]) == 0:
68 del self.accounts[account][queue]
69 if len(self.accounts[account]) == 0:
70 del self.accounts[account]
71 return message
72 return None
73
74 def get_message(self, account, queue, message_id):
75 for index in range(0, len(self.accounts[account][queue])):
76 message = self.accounts[account][queue][index]
77 if message['id'] == message_id:
78 return message
79 return None
80
81 def put_message(self, account, queue, message_id, ttl, hide, body):
82 if account not in self.accounts:
83 self.accounts[account] = {}
84 if queue not in self.accounts[account]:
85 self.accounts[account][queue] = []
86 for index in range(0, len(self.accounts[account][queue])):
87 message = self.accounts[account][queue][index]
88 if message['id'] == message_id:
89 message['ttl'] = ttl64 message['ttl'] = ttl
90 message['hide'] = hide65 message['hide'] = hide
91 message['body'] = body66 message['body'] = body
92 if hide == 0:67 if hide == 0:
93 self.notify(account, queue)68 self.notify(account[0], queue[0])
94 return False69 return False
95 message = dict(id=message_id, ttl=ttl, hide=hide, body=body)70 message = dict(id=message, ttl=ttl, hide=hide, body=body)
96 self.accounts[account][queue].append(message)71 queue[3].append(message)
97 self.notify(account, queue)72 self.notify(account[0], queue[0])
98 return True73 return True
9974
100 def update_message(self, account, queue, message_id, ttl, hide):75 def delete_message(self, account, queue, message):
101 for index in range(0, len(self.accounts[account][queue])):76 account, queue = self.accounts.get_queue(account, queue)
102 message = self.accounts[account][queue][index]77 if queue is None:
103 if message['id'] == message_id:78 return None
79 for index in xrange(0, len(queue[3])):
80 if queue[3][index]['id'] == message:
81 message = queue[3][index]
82 del queue[3][index]
83 if len(queue[3]) == 0:
84 self.accounts.delete_queue(account[0], queue[0])
85 return message
86 return None
87
88 def get_message(self, account, queue, message):
89 account, queue = self.accounts.get_queue(account, queue)
90 if queue is None:
91 return None
92 for index in xrange(0, len(queue[3])):
93 if queue[3][index]['id'] == message:
94 return queue[3][index]
95 return None
96
97 def update_message(self, account, queue, message, attributes={}):
98 account, queue = self.accounts.get_queue(account, queue)
99 if queue is None:
100 return None
101 ttl = attributes.get('ttl', None)
102 hide = attributes.get('hide', None)
103 for index in xrange(0, len(queue[3])):
104 if queue[3][index]['id'] == message:
105 message = queue[3][index]
104 if ttl is not None:106 if ttl is not None:
105 message['ttl'] = ttl107 message['ttl'] = ttl
106 if hide is not None:108 if hide is not None:
107 message['hide'] = hide109 message['hide'] = hide
108 if hide == 0:110 if hide == 0:
109 self.notify(account, queue)111 self.notify(account[0], queue[0])
110 return message112 return message
111 return None113 return None
112114
113 def clean(self):115 def clean(self):
114 now = int(time.time())116 now = int(time.time())
115 for account in self.accounts.keys():117 for account in self.accounts.iter():
116 for queue in self.accounts[account].keys():118 for queue in account[3].iter():
117 index = 0119 index = 0
118 notify = False120 notify = False
119 total = len(self.accounts[account][queue])121 total = len(queue[3])
120 while index < total:122 while index < total:
121 message = self.accounts[account][queue][index]123 message = queue[3][index]
122 if 0 < message['ttl'] <= now:124 if 0 < message['ttl'] <= now:
123 del self.accounts[account][queue][index]125 del queue[3][index]
124 total -= 1126 total -= 1
125 else:127 else:
126 if 0 < message['hide'] <= now:128 if 0 < message['hide'] <= now:
@@ -128,30 +130,35 @@
128 notify = True130 notify = True
129 index += 1131 index += 1
130 if notify:132 if notify:
131 self.notify(account, queue)133 self.notify(account[0], queue[0])
132 if len(self.accounts[account][queue]) == 0:134 if len(queue[3]) == 0:
133 del self.accounts[account][queue]135 self.accounts.delete_queue(account[0], queue[0])
134 if len(self.accounts[account]) == 0:
135 del self.accounts[account]
136136
137 def _scan_queue(self, account, queue, limit, marker, match_hidden,137 def _scan_queue(self, account, queue, filters, attributes={},
138 ttl=None, hide=None, delete=False):138 delete=False):
139 account, queue = self.accounts.get_queue(account, queue)
140 if queue is None:
141 return
139 index = 0142 index = 0
140 notify = False143 notify = False
141 if marker is not None:144 if 'marker' in filters and filters['marker'] is not None:
142 found = False145 found = False
143 for index in range(0, len(self.accounts[account][queue])):146 for index in xrange(0, len(queue[3])):
144 message = self.accounts[account][queue][index]147 message = queue[3][index]
145 if message['id'] == marker:148 if message['id'] == filters['marker']:
146 index += 1149 index += 1
147 found = True150 found = True
148 break151 break
149 if not found:152 if not found:
150 index = 0153 index = 0
151 messages = []154 messages = []
152 total = len(self.accounts[account][queue])155 total = len(queue[3])
156 limit = filters.get('limit', None)
157 match_hidden = filters.get('match_hidden', False)
158 ttl = attributes.get('ttl', None)
159 hide = attributes.get('hide', None)
153 while index < total:160 while index < total:
154 message = self.accounts[account][queue][index]161 message = queue[3][index]
155 if not match_hidden and message['hide'] != 0:162 if not match_hidden and message['hide'] != 0:
156 index += 1163 index += 1
157 continue164 continue
@@ -162,15 +169,126 @@
162 if hide == 0:169 if hide == 0:
163 notify = True170 notify = True
164 if delete:171 if delete:
165 del self.accounts[account][queue][index]172 del queue[3][index]
166 total -= 1173 total -= 1
167 else:174 else:
168 index += 1175 index += 1
169 messages.append(message)176 yield message
170 if limit:177 if limit:
171 limit -= 1178 limit -= 1
172 if limit == 0:179 if limit == 0:
173 break180 break
174 if notify:181 if notify:
175 self.notify(account, queue)182 self.notify(account[0], queue[0])
176 return messages183 if len(queue[3]) == 0:
184 self.accounts.delete_queue(account[0], queue[0])
185
186
187class IndexedTupleList(object):
188 '''Class for managing an indexed tuple list. The tuple must be at
189 least three elements and must reserve the first three for (name,
190 next, previous).'''
191
192 def __init__(self):
193 self.first = None
194 self.last = None
195 self.index = {}
196
197 def add(self, item):
198 item = (item[0], None, self.last) + item[3:]
199 if self.first is None:
200 self.first = item
201 self.last = item
202 self.index[item[0]] = item
203 return item
204
205 def count(self):
206 return len(self.index)
207
208 def delete(self, filters):
209 if len(filters) == 0:
210 self.first = None
211 self.last = None
212 self.index.clear()
213 return
214 for item in self.iter(filters):
215 self.delete_item(item[0])
216
217 def delete_item(self, name):
218 if name not in self.index:
219 return
220 item = self.index[name][1]
221 if item is not None:
222 prev_item = self.index[name][2]
223 self.index[item[0]] = (item[0], item[1], prev_item) + item[3:]
224 item = self.index[name][2]
225 if item is not None:
226 next_item = self.index[name][1]
227 self.index[item[0]] = (item[0], next_item, item[2]) + item[3:]
228 if self.first == self.index[name]:
229 self.first = self.index[name][1]
230 if self.last == self.index[name]:
231 self.last = self.index[name][2]
232 del self.index[name]
233
234 def get(self, name):
235 if name in self.index:
236 return self.index[name]
237 return None
238
239 def iter(self, filters={}):
240 marker = filters.get('marker', None)
241 if marker is not None and marker in self.index:
242 item = self.index[marker]
243 else:
244 item = self.first
245 limit = filters.get('limit', None)
246 while item is not None:
247 yield item
248 if limit:
249 limit -= 1
250 if limit == 0:
251 break
252 item = item[1]
253
254
255class Accounts(IndexedTupleList):
256
257 def delete_queue(self, account, queue):
258 account = self.get(account)
259 if account is not None:
260 account[3].delete_item(queue)
261 if account[3].count() == 0:
262 self.delete_item(account[0])
263
264 def delete_queues(self, account, filters):
265 account = self.get(account)
266 if account is not None:
267 account[3].delete(filters)
268 if account[3].count() == 0:
269 self.delete_item(account[0])
270
271 def get_queue(self, account, queue, create=False):
272 if account in self.index:
273 account = self.index[account]
274 elif create:
275 account = self.add((account, None, None, Queues()))
276 else:
277 return None, None
278 return account, account[3].get(queue, create)
279
280 def iter_queues(self, account, filters={}):
281 account = self.get(account)
282 if account is not None:
283 for queue in account[3].iter(filters):
284 yield queue
285
286
287class Queues(IndexedTupleList):
288
289 def get(self, queue, create=False):
290 if queue in self.index:
291 return self.index[queue]
292 elif create:
293 return self.add((queue, None, None, []))
294 return None
177295
=== modified file 'burrow/backend/sqlite.py'
--- burrowd/backend/sqlite.py 2011-03-17 23:42:41 +0000
+++ burrow/backend/sqlite.py 2011-04-06 05:49:23 +0000
@@ -12,23 +12,24 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Memory backend for the burrow server.'''15'''SQLite backend for burrow.'''
1616
17import sqlite317import sqlite3
18import time18import time
1919
20import burrowd.backend20import burrow.backend
2121
22# Default configuration values for this module.22# Default configuration values for this module.
23DEFAULT_DATABASE = ':memory:'23DEFAULT_DATABASE = ':memory:'
2424
2525
26class Backend(burrowd.backend.Backend):26class Backend(burrow.backend.Backend):
2727
28 def __init__(self, config):28 def __init__(self, config):
29 super(Backend, self).__init__(config)29 super(Backend, self).__init__(config)
30 database = self.config.get('database', DEFAULT_DATABASE)30 database = self.config.get('database', DEFAULT_DATABASE)
31 self.db = sqlite3.connect(database)31 self.db = sqlite3.connect(database)
32 self.db.isolation_level = None
32 queries = [33 queries = [
33 'CREATE TABLE queues ('34 'CREATE TABLE queues ('
34 'account VARCHAR(255) NOT NULL,'35 'account VARCHAR(255) NOT NULL,'
@@ -44,129 +45,97 @@
44 for query in queries:45 for query in queries:
45 self.db.execute(query)46 self.db.execute(query)
4647
47 def delete_accounts(self):48 def delete_accounts(self, filters={}):
48 self.db.execute("DELETE FROM queues")49 if len(filters) == 0:
49 self.db.execute("DELETE FROM messages")50 self.db.execute('DELETE FROM queues')
5051 self.db.execute('DELETE FROM messages')
51 def get_accounts(self):
52 result = self.db.execute("SELECT account FROM queues").fetchall()
53 return [row[0] for row in result]
54
55 def delete_account(self, account):
56 query = "SELECT rowid FROM queues WHERE account='%s'" % account
57 result = self.db.execute(query).fetchall()
58 if len(result) == 0:
59 return52 return
60 queues = [str(queue[0]) for queue in result]53
61 query = "DELETE FROM messages WHERE queue IN (%s)" % (','.join(queues))54 def get_accounts(self, filters={}):
62 self.db.execute(query)55 query = 'SELECT DISTINCT account FROM queues'
63 self.db.execute("DELETE FROM queues WHERE account='%s'" % account)56 values = tuple()
6457 marker = filters.get('marker', None)
65 def get_queues(self, account):58 if marker is not None:
66 query = "SELECT queue FROM queues WHERE account='%s'" % account59 query += ' WHERE account > ?'
67 result = self.db.execute(query).fetchall()60 values += (marker,)
68 return [row[0] for row in result]61 limit = filters.get('limit', None)
69
70 def queue_exists(self, account, queue):
71 query = "SELECT COUNT(*) FROM queues " \
72 "WHERE account='%s' AND queue='%s'" % \
73 (account, queue)
74 result = self.db.execute(query).fetchall()
75 if len(result) == 0:
76 return False
77 self.rowid = result[0][0]
78 return True
79
80 def delete_messages(self, account, queue, limit, marker, match_hidden):
81 messages = self.get_messages(account, queue, limit, marker,
82 match_hidden)
83 ids = [message['id'] for message in messages]
84 query = "DELETE FROM messages WHERE queue=%d AND name IN (%s)" % \
85 (self.rowid, ','.join(ids))
86 self.db.execute(query)
87 query = "SELECT rowid FROM messages WHERE queue=%d LIMIT 1" % \
88 self.rowid
89 if len(self.db.execute(query).fetchall()) == 0:
90 query = "DELETE FROM queues WHERE rowid=%d" % self.rowid
91 self.db.execute(query)
92 return messages
93
94 def get_messages(self, account, queue, limit, marker, match_hidden):
95 if marker is not None:
96 query = "SELECT rowid FROM messages " \
97 "WHERE queue=%d AND name='%s'" % \
98 (self.rowid, marker)
99 result = self.db.execute(query).fetchall()
100 if len(result) == 0:
101 marker = None
102 else:
103 marker = result[0][0]
104 query = "SELECT name,ttl,hide,body FROM messages WHERE queue=%d" % \
105 self.rowid
106 if match_hidden is False:
107 query += " AND hide == 0"
108 if marker is not None:
109 query += " AND rowid > %d" % marker
110 if limit is not None:62 if limit is not None:
111 query += " LIMIT %d" % limit63 query += ' LIMIT ?'
112 result = self.db.execute(query).fetchall()64 values += (limit,)
113 messages = []65 for row in self.db.execute(query, values):
114 for row in result:66 yield row[0]
115 messages.append(dict(id=row[0], ttl=row[1], hide=row[2],67
116 body=row[3]))68 def delete_queues(self, account, filters={}):
117 return messages69 query = 'SELECT rowid FROM queues WHERE account=?'
11870 ids = []
119 def update_messages(self, account, queue, limit, marker, match_hidden, ttl,71 for row in self.db.execute(query, (account,)):
120 hide):72 ids.append(str(row[0]))
121 messages = self.get_messages(account, queue, limit, marker,73 if len(ids) == 0:
122 match_hidden)74 return
123 query = "UPDATE messages SET"75 query = 'DELETE FROM messages WHERE queue IN (%s)'
124 comma = ''76 self.db.execute(query % ','.join(ids))
125 if ttl is not None:77 self.db.execute('DELETE FROM queues WHERE account=?', (account,))
126 query += "%s ttl=%d" % (comma, ttl)78
127 comma = ','79 def get_queues(self, account, filters={}):
128 if hide is not None:80 query = 'SELECT queue FROM queues WHERE account=?'
129 query += "%s hide=%d" % (comma, hide)81 for row in self.db.execute(query, (account,)):
130 comma = ','82 yield row[0]
131 if comma == '':83
132 return (False, message)84 def delete_messages(self, account, queue, filters={}):
133 ids = []85 result = self._get_messages(account, queue, filters)
134 for message in messages:86 rowid = result.next()
87 ids = []
88 for message in result:
89 ids.append(message['id'])
90 yield message
91 if len(ids) == 0:
92 return
93 query = 'DELETE FROM messages WHERE queue=%d AND name IN (%s)'
94 self.db.execute(query % (rowid, ','.join(ids)))
95 query = 'SELECT rowid FROM messages WHERE queue=? LIMIT 1'
96 if len(self.db.execute(query, (rowid,)).fetchall()) == 0:
97 query = 'DELETE FROM queues WHERE rowid=?'
98 self.db.execute(query, (rowid,))
99
100 def get_messages(self, account, queue, filters={}):
101 result = self._get_messages(account, queue, filters)
102 rowid = result.next()
103 return result
104
105 def update_messages(self, account, queue, attributes={}, filters={}):
106 result = self._get_messages(account, queue, filters)
107 rowid = result.next()
108 ids = []
109 ttl = attributes.get('ttl', None)
110 hide = attributes.get('hide', None)
111 for message in result:
135 ids.append(message['id'])112 ids.append(message['id'])
136 if ttl is not None:113 if ttl is not None:
137 message['ttl'] = ttl114 message['ttl'] = ttl
138 if hide is not None:115 if hide is not None:
139 message['hide'] = hide116 message['hide'] = hide
140 query += " WHERE queue=%d AND name IN (%s)" % \117 yield message
141 (self.rowid, ','.join(ids))118 if len(ids) == 0:
142 self.db.execute(query)119 return
120 query = 'UPDATE messages SET'
121 comma = ''
122 values = tuple()
123 if ttl is not None:
124 query += '%s ttl=?' % comma
125 values += (ttl,)
126 comma = ','
127 if hide is not None:
128 query += '%s hide=?' % comma
129 values += (hide,)
130 comma = ','
131 if comma == '':
132 return
133 values += (rowid,)
134 query += ' WHERE queue=? AND name IN (%s)'
135 self.db.execute(query % ','.join(ids), values)
143 self.notify(account, queue)136 self.notify(account, queue)
144 return messages137
145138 def create_message(self, account, queue, message, body, attributes):
146 def delete_message(self, account, queue, message_id):
147 message = self.get_message(account, queue, message_id)
148 if message is None:
149 return None
150 query = "DELETE FROM messages WHERE queue=%d AND name='%s'" % \
151 (self.rowid, message_id)
152 self.db.execute(query)
153 query = "SELECT rowid FROM messages WHERE queue=%d LIMIT 1" % \
154 self.rowid
155 if len(self.db.execute(query).fetchall()) == 0:
156 query = "DELETE FROM queues WHERE rowid=%d" % self.rowid
157 self.db.execute(query)
158 return message
159
160 def get_message(self, account, queue, message_id):
161 query = "SELECT name,ttl,hide,body FROM messages " \
162 "WHERE queue=%d AND name='%s'" % (self.rowid, message_id)
163 result = self.db.execute(query).fetchall()
164 if len(result) == 0:
165 return None
166 row = result[0]
167 return dict(id=row[0], ttl=row[1], hide=row[2], body=row[3])
168
169 def put_message(self, account, queue, message_id, ttl, hide, body):
170 query = "SELECT rowid FROM queues " \139 query = "SELECT rowid FROM queues " \
171 "WHERE account='%s' AND queue='%s'" % (account, queue)140 "WHERE account='%s' AND queue='%s'" % (account, queue)
172 result = self.db.execute(query).fetchall()141 result = self.db.execute(query).fetchall()
@@ -176,11 +145,13 @@
176 else:145 else:
177 rowid = result[0][0]146 rowid = result[0][0]
178 query = "SELECT rowid FROM messages WHERE queue=%d AND name='%s'" % \147 query = "SELECT rowid FROM messages WHERE queue=%d AND name='%s'" % \
179 (rowid, message_id)148 (rowid, message)
180 result = self.db.execute(query).fetchall()149 result = self.db.execute(query).fetchall()
150 ttl = attributes.get('ttl', 0)
151 hide = attributes.get('hide', 0)
181 if len(result) == 0:152 if len(result) == 0:
182 query = "INSERT INTO messages VALUES (%d, '%s', %d, %d, '%s')" % \153 query = "INSERT INTO messages VALUES (%d, '%s', %d, %d, '%s')" % \
183 (rowid, message_id, ttl, hide, body)154 (rowid, message, ttl, hide, body)
184 self.db.execute(query)155 self.db.execute(query)
185 self.notify(account, queue)156 self.notify(account, queue)
186 return True157 return True
@@ -191,12 +162,45 @@
191 self.notify(account, queue)162 self.notify(account, queue)
192 return False163 return False
193164
194 def update_message(self, account, queue, message_id, ttl, hide):165 def delete_message(self, account, queue, message):
195 message = self.get_message(account, queue, message_id)166 rowid = self._get_queue(account, queue)
167 if rowid is None:
168 return None
169 message = self.get_message(account, queue, message)
170 if message is None:
171 return None
172 query = "DELETE FROM messages WHERE queue=%d AND name='%s'" % \
173 (rowid, message['id'])
174 self.db.execute(query)
175 query = "SELECT rowid FROM messages WHERE queue=%d LIMIT 1" % rowid
176 if len(self.db.execute(query).fetchall()) == 0:
177 query = "DELETE FROM queues WHERE rowid=%d" % rowid
178 self.db.execute(query)
179 return message
180
181 def get_message(self, account, queue, message):
182 rowid = self._get_queue(account, queue)
183 if rowid is None:
184 return None
185 query = "SELECT name,ttl,hide,body FROM messages " \
186 "WHERE queue=%d AND name='%s'" % (rowid, message)
187 result = self.db.execute(query).fetchall()
188 if len(result) == 0:
189 return None
190 row = result[0]
191 return dict(id=row[0], ttl=row[1], hide=row[2], body=row[3])
192
193 def update_message(self, account, queue, message, attributes):
194 rowid = self._get_queue(account, queue)
195 if rowid is None:
196 return None
197 message = self.get_message(account, queue, message)
196 if message is None:198 if message is None:
197 return None199 return None
198 query = "UPDATE messages SET"200 query = "UPDATE messages SET"
199 comma = ''201 comma = ''
202 ttl = attributes.get('ttl', None)
203 hide = attributes.get('hide', None)
200 if ttl is not None:204 if ttl is not None:
201 query += "%s ttl=%d" % (comma, ttl)205 query += "%s ttl=%d" % (comma, ttl)
202 comma = ','206 comma = ','
@@ -205,7 +209,7 @@
205 comma = ','209 comma = ','
206 if comma == '':210 if comma == '':
207 return message211 return message
208 query += " WHERE queue=%d AND name='%s'" % (self.rowid, message_id)212 query += " WHERE queue=%d AND name='%s'" % (rowid, message['id'])
209 self.db.execute(query)213 self.db.execute(query)
210 if hide == 0:214 if hide == 0:
211 self.notify(account, queue)215 self.notify(account, queue)
@@ -248,3 +252,36 @@
248 queue252 queue
249 result = self.db.execute(query).fetchall()[0]253 result = self.db.execute(query).fetchall()[0]
250 self.notify(result[0], result[1])254 self.notify(result[0], result[1])
255
256 def _get_queue(self, account, queue):
257 query = "SELECT COUNT(*) FROM queues " \
258 "WHERE account='%s' AND queue='%s'" % \
259 (account, queue)
260 result = self.db.execute(query).fetchall()
261 if len(result) == 0:
262 return None
263 return result[0][0]
264
265 def _get_messages(self, account, queue, filters):
266 rowid = self._get_queue(account, queue)
267 yield rowid
268 if rowid is None:
269 return
270 marker = None
271 if 'marker' in filters and filters['marker'] is not None:
272 query = "SELECT rowid FROM messages " \
273 "WHERE queue=%d AND name='%s'" % (rowid, filters['marker'])
274 result = self.db.execute(query).fetchall()
275 if len(result) > 0:
276 marker = result[0][0]
277 query = "SELECT name,ttl,hide,body FROM messages WHERE queue=%d" % \
278 rowid
279 if marker is not None:
280 query += " AND rowid > %d" % marker
281 if 'match_hidden' not in filters or filters['match_hidden'] is False:
282 query += " AND hide == 0"
283 if 'limit' in filters and filters['limit'] is not None:
284 query += " LIMIT %d" % filters['limit']
285 result = self.db.execute(query).fetchall()
286 for row in result:
287 yield dict(id=row[0], ttl=row[1], hide=row[2], body=row[3])
251288
=== added file 'burrow/client.py'
--- burrow/client.py 1970-01-01 00:00:00 +0000
+++ burrow/client.py 2011-04-06 05:49:23 +0000
@@ -0,0 +1,63 @@
1# Copyright (C) 2011 OpenStack LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15'''Client module for burrow.'''
16
17import ConfigParser
18import logging
19import logging.config
20
21import burrow
22import burrow.config
23
24# Default configuration values for this module.
25DEFAULT_BACKEND = 'burrow.backend.http'
26
27
28class Client(object):
29 '''Client class for burrow.'''
30
31 def __init__(self, url=None, config_files=[],
32 add_default_log_handler=True):
33 '''Initialize a client using the URL and config files from the
34 given list. This is passed directly to ConfigParser.read(),
35 so files should be in ConfigParser format. This will load
36 all the backend class from the configuration.'''
37 if len(config_files) > 0:
38 logging.config.fileConfig(config_files)
39 self._config = ConfigParser.ConfigParser()
40 self._config.read(config_files)
41 # TODO: Parse URL if given and overwrite any values in self._config.
42 self.config = burrow.config.Config(self._config, 'burrow.client')
43 self.log = burrow.get_logger(self.config)
44 if add_default_log_handler:
45 self._add_default_log_handler()
46 self._import_backend()
47
48 def _add_default_log_handler(self):
49 '''Add a default log handler it one has not been set.'''
50 root_log = logging.getLogger()
51 if len(root_log.handlers) > 0 or len(self.log.handlers) > 0:
52 return
53 handler = logging.StreamHandler()
54 handler.setLevel(logging.ERROR)
55 log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
56 handler.setFormatter(logging.Formatter(log_format))
57 root_log.addHandler(handler)
58
59 def _import_backend(self):
60 '''Load backend given in the 'backend' option.'''
61 backend = self.config.get('backend', DEFAULT_BACKEND)
62 config = (self._config, backend)
63 self.backend = burrow.import_class(backend, 'Backend')(config)
064
=== modified file 'burrow/config.py'
--- burrowd/config.py 2011-03-17 23:42:41 +0000
+++ burrow/config.py 2011-04-06 05:49:23 +0000
@@ -12,7 +12,7 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Configuration module for the burrow server.'''15'''Configuration module for burrow.'''
1616
17import ConfigParser17import ConfigParser
1818
1919
=== modified file 'burrow/frontend/__init__.py'
--- burrowd/frontend/__init__.py 2011-03-17 23:42:41 +0000
+++ burrow/frontend/__init__.py 2011-04-06 05:49:23 +0000
@@ -12,12 +12,12 @@
12# See the License for the specific language governing permissions and12# See the License for the specific language governing permissions and
13# limitations under the License.13# limitations under the License.
1414
15'''Frontends for the burrow server.'''15'''Frontends for burrow.'''
1616
17import burrowd17import burrow
1818
1919
20class Frontend(burrowd.Module):20class Frontend(burrow.Module):
21 '''Interface that frontend implementations must provide.'''21 '''Interface that frontend implementations must provide.'''
2222
23 def __init__(self, config, backend):23 def __init__(self, config, backend):
2424
=== modified file 'burrow/frontend/wsgi.py'
--- burrowd/frontend/wsgi.py 2011-03-17 23:42:41 +0000
+++ burrow/frontend/wsgi.py 2011-04-06 05:49:23 +0000
@@ -24,7 +24,7 @@
24import webob.dec24import webob.dec
25import webob.exc25import webob.exc
2626
27import burrowd.frontend27import burrow.frontend
2828
29# Default configuration values for this module.29# Default configuration values for this module.
30DEFAULT_HOST = '0.0.0.0'30DEFAULT_HOST = '0.0.0.0'
@@ -38,20 +38,18 @@
38DEFAULT_HIDE = 038DEFAULT_HIDE = 0
3939
4040
41def queue_exists(method):41def wait_on_queue(method):
42 '''Decorator to ensure an account and queue exists. If the wait42 '''Decorator to wait on an account/queue if the wait option is
43 option is given, this will block until a message in the queue is43 given. This will block until a message in the queue is ready or
44 ready or the timeout expires.'''44 the timeout expires.'''
45 def wrapper(self, req, account, queue, *args, **kwargs):45 def wrapper(self, req, account, queue, *args, **kwargs):
46 wait = 046 wait = 0
47 if 'wait' in req.params:47 if 'wait' in req.params:
48 wait = int(req.params['wait'])48 wait = int(req.params['wait'])
49 if wait > 0:49 if wait > 0:
50 wait += time.time()50 wait += time.time()
51 res = webob.exc.HTTPNotFound()
52 while True:51 while True:
53 if self.backend.queue_exists(account, queue):52 res = method(self, req, account, queue, *args, **kwargs)
54 res = method(self, req, account, queue, *args, **kwargs)
55 if wait == 0 or res.status_int != 404:53 if wait == 0 or res.status_int != 404:
56 break54 break
57 now = time.time()55 now = time.time()
@@ -63,7 +61,7 @@
63 return wrapper61 return wrapper
6462
6563
66class Frontend(burrowd.frontend.Frontend):64class Frontend(burrow.frontend.Frontend):
6765
68 def __init__(self, config, backend):66 def __init__(self, config, backend):
69 super(Frontend, self).__init__(config, backend)67 super(Frontend, self).__init__(config, backend)
@@ -73,7 +71,7 @@
73 mapper.connect('/', action='root')71 mapper.connect('/', action='root')
74 mapper.connect('/{account}', action='account')72 mapper.connect('/{account}', action='account')
75 mapper.connect('/{account}/{queue}', action='queue')73 mapper.connect('/{account}/{queue}', action='queue')
76 mapper.connect('/{account}/{queue}/{message_id}', action='message')74 mapper.connect('/{account}/{queue}/{message}', action='message')
77 self._routes = routes.middleware.RoutesMiddleware(self._route, mapper)75 self._routes = routes.middleware.RoutesMiddleware(self._route, mapper)
7876
79 def run(self, thread_pool):77 def run(self, thread_pool):
@@ -121,85 +119,86 @@
121119
122 @webob.dec.wsgify120 @webob.dec.wsgify
123 def _delete_root(self, req):121 def _delete_root(self, req):
124 self.backend.delete_accounts()122 filters = self._parse_filters(req)
123 self.backend.delete_accounts(filters)
125 return webob.exc.HTTPNoContent()124 return webob.exc.HTTPNoContent()
126125
127 @webob.dec.wsgify126 @webob.dec.wsgify
128 def _get_root(self, req):127 def _get_root(self, req):
129 accounts = self.backend.get_accounts()128 filters = self._parse_filters(req)
129 accounts = [account for account in self.backend.get_accounts(filters)]
130 if len(accounts) == 0:130 if len(accounts) == 0:
131 return webob.exc.HTTPNotFound()131 return webob.exc.HTTPNotFound()
132 return webob.exc.HTTPOk(body=json.dumps(accounts, indent=2))132 return webob.exc.HTTPOk(body=json.dumps(accounts, indent=2))
133133
134 @webob.dec.wsgify134 @webob.dec.wsgify
135 def _delete_account(self, req, account):135 def _delete_account(self, req, account):
136 self.backend.delete_account(account)136 filters = self._parse_filters(req)
137 self.backend.delete_queues(account, filters)
137 return webob.exc.HTTPNoContent()138 return webob.exc.HTTPNoContent()
138139
139 @webob.dec.wsgify140 @webob.dec.wsgify
140 def _get_account(self, req, account):141 def _get_account(self, req, account):
141 queues = self.backend.get_queues(account)142 filters = self._parse_filters(req)
143 queues = [queue for queue in self.backend.get_queues(account, filters)]
142 if len(queues) == 0:144 if len(queues) == 0:
143 return webob.exc.HTTPNotFound()145 return webob.exc.HTTPNotFound()
144 return webob.exc.HTTPOk(body=json.dumps(queues, indent=2))146 return webob.exc.HTTPOk(body=json.dumps(queues, indent=2))
145147
146 @webob.dec.wsgify148 @webob.dec.wsgify
147 @queue_exists149 @wait_on_queue
148 def _delete_queue(self, req, account, queue):150 def _delete_queue(self, req, account, queue):
149 limit, marker, match_hidden = self._parse_filters(req)151 filters = self._parse_filters(req)
150 messages = self.backend.delete_messages(account, queue, limit, marker,152 messages = [message for message in
151 match_hidden)153 self.backend.delete_messages(account, queue, filters)]
152 return self._return_messages(req, account, queue, messages, 'none')154 return self._return_messages(req, account, queue, messages, 'none')
153155
154 @webob.dec.wsgify156 @webob.dec.wsgify
155 @queue_exists157 @wait_on_queue
156 def _get_queue(self, req, account, queue):158 def _get_queue(self, req, account, queue):
157 limit, marker, match_hidden = self._parse_filters(req)159 filters = self._parse_filters(req)
158 messages = self.backend.get_messages(account, queue, limit, marker,160 messages = [message for message in
159 match_hidden)161 self.backend.get_messages(account, queue, filters)]
160 return self._return_messages(req, account, queue, messages, 'all')162 return self._return_messages(req, account, queue, messages, 'all')
161163
162 @webob.dec.wsgify164 @webob.dec.wsgify
163 @queue_exists165 @wait_on_queue
164 def _post_queue(self, req, account, queue):166 def _post_queue(self, req, account, queue):
165 limit, marker, match_hidden = self._parse_filters(req)167 attributes = self._parse_attributes(req)
166 ttl, hide = self._parse_metadata(req)168 filters = self._parse_filters(req)
167 messages = self.backend.update_messages(account, queue, limit, marker,169 messages = [message for message in
168 match_hidden, ttl, hide)170 self.backend.update_messages(account, queue, attributes, filters)]
169 return self._return_messages(req, account, queue, messages, 'all')171 return self._return_messages(req, account, queue, messages, 'all')
170172
171 @webob.dec.wsgify173 @webob.dec.wsgify
172 @queue_exists174 def _delete_message(self, req, account, queue, message):
173 def _delete_message(self, req, account, queue, message_id):175 message = self.backend.delete_message(account, queue, message)
174 message = self.backend.delete_message(account, queue, message_id)
175 if message is None:176 if message is None:
176 return webob.exc.HTTPNotFound()177 return webob.exc.HTTPNotFound()
177 return self._return_message(req, account, queue, message, 'none')178 return self._return_message(req, account, queue, message, 'none')
178179
179 @webob.dec.wsgify180 @webob.dec.wsgify
180 @queue_exists181 def _get_message(self, req, account, queue, message):
181 def _get_message(self, req, account, queue, message_id):182 message = self.backend.get_message(account, queue, message)
182 message = self.backend.get_message(account, queue, message_id)
183 if message is None:183 if message is None:
184 return webob.exc.HTTPNotFound()184 return webob.exc.HTTPNotFound()
185 return self._return_message(req, account, queue, message, 'all')185 return self._return_message(req, account, queue, message, 'all')
186186
187 @webob.dec.wsgify187 @webob.dec.wsgify
188 @queue_exists188 def _post_message(self, req, account, queue, message):
189 def _post_message(self, req, account, queue, message_id):189 attributes = self._parse_attributes(req)
190 ttl, hide = self._parse_metadata(req)190 message = self.backend.update_message(account, queue, message,
191 message = self.backend.update_message(account, queue, message_id, ttl,191 attributes)
192 hide)
193 if message is None:192 if message is None:
194 return webob.exc.HTTPNotFound()193 return webob.exc.HTTPNotFound()
195 return self._return_message(req, account, queue, message, 'id')194 return self._return_message(req, account, queue, message, 'id')
196195
197 @webob.dec.wsgify196 @webob.dec.wsgify
198 def _put_message(self, req, account, queue, message_id):197 def _put_message(self, req, account, queue, message):
199 (ttl, hide) = self._parse_metadata(req, self.default_ttl,198 attributes = self._parse_attributes(req, self.default_ttl,
200 self.default_hide)199 self.default_hide)
201 if self.backend.put_message(account, queue, message_id, ttl, hide, \200 if self.backend.create_message(account, queue, message, req.body,
202 req.body):201 attributes):
203 return webob.exc.HTTPCreated()202 return webob.exc.HTTPCreated()
204 return webob.exc.HTTPNoContent()203 return webob.exc.HTTPNoContent()
205204
@@ -239,31 +238,32 @@
239 return webob.exc.HTTPOk(body=json.dumps(body, indent=2))238 return webob.exc.HTTPOk(body=json.dumps(body, indent=2))
240239
241 def _parse_filters(self, req):240 def _parse_filters(self, req):
242 limit = None241 filters = {}
243 if 'limit' in req.params:242 if 'limit' in req.params:
244 limit = int(req.params['limit'])243 filters['limit'] = int(req.params['limit'])
245 marker = None
246 if 'marker' in req.params:244 if 'marker' in req.params:
247 marker = req.params['marker']245 filters['marker'] = req.params['marker']
248 match_hidden = False
249 if 'hidden' in req.params and req.params['hidden'].lower() == 'true':246 if 'hidden' in req.params and req.params['hidden'].lower() == 'true':
250 match_hidden = True247 filters['match_hidden'] = True
251 return limit, marker, match_hidden248 return filters
252249
253 def _parse_metadata(self, req, default_ttl=None, default_hide=None):250 def _parse_attributes(self, req, default_ttl=None, default_hide=None):
251 attributes = {}
254 if 'ttl' in req.params:252 if 'ttl' in req.params:
255 ttl = int(req.params['ttl'])253 ttl = int(req.params['ttl'])
256 else:254 else:
257 ttl = default_ttl255 ttl = default_ttl
258 if ttl is not None and ttl > 0:256 if ttl is not None and ttl > 0:
259 ttl += int(time.time())257 ttl += int(time.time())
258 attributes['ttl'] = ttl
260 if 'hide' in req.params:259 if 'hide' in req.params:
261 hide = int(req.params['hide'])260 hide = int(req.params['hide'])
262 else:261 else:
263 hide = default_hide262 hide = default_hide
264 if hide is not None and hide > 0:263 if hide is not None and hide > 0:
265 hide += int(time.time())264 hide += int(time.time())
266 return ttl, hide265 attributes['hide'] = hide
266 return attributes
267267
268268
269class WSGILog(object):269class WSGILog(object):
270270
=== added file 'burrow/server.py'
--- burrow/server.py 1970-01-01 00:00:00 +0000
+++ burrow/server.py 2011-04-06 05:49:23 +0000
@@ -0,0 +1,95 @@
1# Copyright (C) 2011 OpenStack LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15'''Server module for burrow.'''
16
17import ConfigParser
18import logging
19import logging.config
20
21import eventlet
22
23import burrow
24import burrow.config
25
26# Default configuration values for this module.
27DEFAULT_BACKEND = 'burrow.backend.sqlite'
28DEFAULT_FRONTENDS = 'burrow.frontend.wsgi'
29DEFAULT_THREAD_POOL_SIZE = 1000
30
31
32class Server(object):
33 '''Server class for burrow.'''
34
35 def __init__(self, config_files=[], add_default_log_handler=True):
36 '''Initialize a server using the config files from the given
37 list. This is passed directly to ConfigParser.read(), so
38 files should be in ConfigParser format. This will load all
39 frontend and backend classes from the configuration.'''
40 if len(config_files) > 0:
41 logging.config.fileConfig(config_files)
42 self._config = ConfigParser.ConfigParser()
43 self._config.read(config_files)
44 self.config = burrow.config.Config(self._config, 'burrow.server')
45 self.log = burrow.get_logger(self.config)
46 if add_default_log_handler:
47 self._add_default_log_handler()
48 self._import_backend()
49 self._import_frontends()
50
51 def _add_default_log_handler(self):
52 '''Add a default log handler it one has not been set.'''
53 root_log = logging.getLogger()
54 if len(root_log.handlers) > 0 or len(self.log.handlers) > 0:
55 return
56 handler = logging.StreamHandler()
57 handler.setLevel(logging.DEBUG)
58 log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
59 handler.setFormatter(logging.Formatter(log_format))
60 root_log.addHandler(handler)
61
62 def _import_backend(self):
63 '''Load backend given in the 'backend' option.'''
64 backend = self.config.get('backend', DEFAULT_BACKEND)
65 config = (self._config, backend)
66 self.backend = burrow.import_class(backend, 'Backend')(config)
67
68 def _import_frontends(self):
69 '''Load frontends given in the 'frontends' option.'''
70 self.frontends = []
71 frontends = self.config.get('frontends', DEFAULT_FRONTENDS)
72 for frontend in frontends.split(','):
73 frontend = frontend.split(':')
74 if len(frontend) == 1:
75 frontend.append(None)
76 config = (self._config, frontend[0], frontend[1])
77 frontend = burrow.import_class(frontend[0], 'Frontend')
78 frontend = frontend(config, self.backend)
79 self.frontends.append(frontend)
80
81 def run(self):
82 '''Create the thread pool and start the main server loop. Wait
83 for the pool to complete, but possibly run forever if the
84 frontends and backend never remove threads.'''
85 thread_pool_size = self.config.getint('thread_pool_size',
86 DEFAULT_THREAD_POOL_SIZE)
87 thread_pool = eventlet.GreenPool(size=int(thread_pool_size))
88 self.backend.run(thread_pool)
89 for frontend in self.frontends:
90 frontend.run(thread_pool)
91 self.log.info(_('Waiting for all threads to exit'))
92 try:
93 thread_pool.waitall()
94 except KeyboardInterrupt:
95 pass
096
=== modified file 'etc/burrowd.conf'
--- etc/burrowd.conf 2011-03-17 23:42:41 +0000
+++ etc/burrowd.conf 2011-04-06 05:49:23 +0000
@@ -1,6 +1,6 @@
1[DEFAULT]1[DEFAULT]
22
3# Log level to use. All sections below prefixed with 'burrowd' can define3# Log level to use. All sections below prefixed with 'burrow' can define
4# this to override this default.4# this to override this default.
5log_level = DEBUG5log_level = DEBUG
66
@@ -11,26 +11,26 @@
11default_hide = 011default_hide = 0
1212
1313
14[burrowd]14[burrow.server]
1515
16# Backend to use for storing messages.16# Backend to use for storing messages.
17backend = burrowd.backend.sqlite17backend = burrow.backend.sqlite
1818
19# Comma separated list of frontends to run.19# Comma separated list of frontends to run.
20# frontends = burrowd.frontend.wsgi,burrowd.frontend.wsgi:ssl20# frontends = burrow.frontend.wsgi,burrow.frontend.wsgi:ssl
21frontends = burrowd.frontend.wsgi21frontends = burrow.frontend.wsgi
2222
23# Size of the thread pool to use for the server.23# Size of the thread pool to use for the server.
24thread_pool_size = 100024thread_pool_size = 1000
2525
2626
27[burrowd.backend.sqlite]27[burrow.backend.sqlite]
2828
29# Database file to use, passed to sqlite3.connect.29# Database file to use, passed to sqlite3.connect.
30database = :memory:30database = :memory:
3131
3232
33[burrowd.frontend.wsgi]33[burrow.frontend.wsgi]
3434
35# Host to listen on.35# Host to listen on.
36host = 0.0.0.036host = 0.0.0.0
@@ -51,7 +51,7 @@
51ssl_keyfile = example.key51ssl_keyfile = example.key
5252
53# Size of thread pool for the WSGI server. If the size is 0, use the main53# Size of thread pool for the WSGI server. If the size is 0, use the main
54# burrowd thread pool.54# burrow thread pool.
55thread_pool_size = 055thread_pool_size = 0
5656
57# Default expiration time in seconds to set for messages. This overrides57# Default expiration time in seconds to set for messages. This overrides
@@ -63,7 +63,7 @@
63# default_hide = 063# default_hide = 0
6464
6565
66[burrowd.frontend.wsgi:ssl]66[burrow.frontend.wsgi:ssl]
6767
68# Port to listen on.68# Port to listen on.
69port = 844369port = 8443
7070
=== modified file 'locale/burrow.pot'
--- locale/burrow.pot 2011-03-18 00:47:26 +0000
+++ locale/burrow.pot 2011-04-06 05:49:23 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: burrow 0.1\n"9"Project-Id-Version: burrow 0.1\n"
10"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"10"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
11"POT-Creation-Date: 2011-03-17 17:43-0700\n"11"POT-Creation-Date: 2011-04-05 19:00-0700\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,20 +17,20 @@
17"Content-Transfer-Encoding: 8bit\n"17"Content-Transfer-Encoding: 8bit\n"
18"Generated-By: Babel 0.9.4\n"18"Generated-By: Babel 0.9.4\n"
1919
20#: burrowd/__init__.py:9620#: burrow/__init__.py:38
21msgid "Waiting for all threads to exit"
22msgstr ""
23
24#: burrowd/__init__.py:109
25msgid "Module created"21msgid "Module created"
26msgstr ""22msgstr ""
2723
28#: burrowd/__init__.py:13024#: burrow/__init__.py:59
29#, python-format25#, python-format
30msgid "Class %s.%s cannot be found (%s)"26msgid "Class %s.%s cannot be found (%s)"
31msgstr ""27msgstr ""
3228
33#: burrowd/frontend/wsgi.py:8729#: burrow/server.py:91
30msgid "Waiting for all threads to exit"
31msgstr ""
32
33#: burrow/frontend/wsgi.py:85
34#, python-format34#, python-format
35msgid "Listening on %s:%d"35msgid "Listening on %s:%d"
36msgstr ""36msgstr ""
3737
=== modified file 'setup.py'
--- setup.py 2011-03-17 23:42:41 +0000
+++ setup.py 2011-04-06 05:49:23 +0000
@@ -17,11 +17,14 @@
17from setuptools.command.sdist import sdist17from setuptools.command.sdist import sdist
18import os18import os
19import subprocess19import subprocess
20
20try:21try:
21 from babel.messages import frontend22 from babel.messages import frontend
22except ImportError:23except ImportError:
23 frontend = None24 frontend = None
2425
26import burrow
27
2528
26class local_sdist(sdist):29class local_sdist(sdist):
27 """Customized sdist hook - builds the ChangeLog file from VC first"""30 """Customized sdist hook - builds the ChangeLog file from VC first"""
@@ -54,7 +57,7 @@
5457
55setup(58setup(
56 name=name,59 name=name,
57 version='0.1',60 version=burrow.__version__,
58 description='Burrow',61 description='Burrow',
59 license='Apache License (2.0)',62 license='Apache License (2.0)',
60 author='OpenStack, LLC.',63 author='OpenStack, LLC.',
6164
=== modified file 'test/frontend/test_wsgi.py'
--- test/frontend/test_wsgi.py 2011-03-17 23:42:41 +0000
+++ test/frontend/test_wsgi.py 2011-04-06 05:49:23 +0000
@@ -20,19 +20,19 @@
20import eventlet20import eventlet
21import webob21import webob
2222
23import burrowd.backend.memory23import burrow.backend.memory
24import burrowd.backend.sqlite24import burrow.backend.sqlite
25import burrowd.frontend.wsgi25import burrow.frontend.wsgi
2626
2727
28class TestWSGIMemory(unittest.TestCase):28class TestWSGIMemory(unittest.TestCase):
29 '''Unittests for the WSGI frontend to SQLite backend.'''29 '''Unittests for the WSGI frontend to SQLite backend.'''
30 backend_class = burrowd.backend.memory.Backend30 backend_class = burrow.backend.memory.Backend
3131
32 def setUp(self):32 def setUp(self):
33 config = (ConfigParser.ConfigParser(), 'test')33 config = (ConfigParser.ConfigParser(), 'test')
34 self.backend = self.backend_class(config)34 self.backend = self.backend_class(config)
35 self.frontend = burrowd.frontend.wsgi.Frontend(config, self.backend)35 self.frontend = burrow.frontend.wsgi.Frontend(config, self.backend)
36 self.frontend.default_ttl = 036 self.frontend.default_ttl = 0
37 self._get_url('/', status=404)37 self._get_url('/', status=404)
38 self._get_url('/a', status=404)38 self._get_url('/a', status=404)
@@ -310,4 +310,4 @@
310310
311class TestWSGISQLite(TestWSGIMemory):311class TestWSGISQLite(TestWSGIMemory):
312 '''Unittests for the WSGI frontend to SQLite backend.'''312 '''Unittests for the WSGI frontend to SQLite backend.'''
313 backend_class = burrowd.backend.sqlite.Backend313 backend_class = burrow.backend.sqlite.Backend

Subscribers

People subscribed via source and target branches