OLD | NEW |
1 # This file is part of the Juju GUI, which lets users view and manage Juju | 1 # This file is part of the Juju GUI, which lets users view and manage Juju |
2 # environments within a graphical interface (https://launchpad.net/juju-gui). | 2 # environments within a graphical interface (https://launchpad.net/juju-gui). |
3 # Copyright (C) 2013 Canonical Ltd. | 3 # Copyright (C) 2013 Canonical Ltd. |
4 # | 4 # |
5 # This program is free software: you can redistribute it and/or modify it under | 5 # This program is free software: you can redistribute it and/or modify it under |
6 # the terms of the GNU Affero General Public License version 3, as published by | 6 # the terms of the GNU Affero General Public License version 3, as published by |
7 # the Free Software Foundation. | 7 # the Free Software Foundation. |
8 # | 8 # |
9 # This program is distributed in the hope that it will be useful, but WITHOUT | 9 # This program is distributed in the hope that it will be useful, but WITHOUT |
10 # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | 10 # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
11 # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 11 # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 # Affero General Public License for more details. | 12 # Affero General Public License for more details. |
13 # | 13 # |
14 # You should have received a copy of the GNU Affero General Public License | 14 # You should have received a copy of the GNU Affero General Public License |
15 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 |
17 """Bundle deployment utility functions and objects.""" | 17 """Bundle deployment utility functions and objects.""" |
18 | 18 |
19 import collections | 19 import collections |
20 from functools import wraps | 20 from functools import wraps |
21 import itertools | 21 import itertools |
22 import logging | 22 import logging |
23 import time | 23 import time |
| 24 import urllib |
24 | 25 |
25 from tornado import ( | 26 from tornado import ( |
26 gen, | 27 gen, |
27 escape, | 28 escape, |
28 ) | 29 ) |
| 30 from tornado.httpclient import AsyncHTTPClient |
29 | 31 |
30 from guiserver.watchers import AsyncWatcher | 32 from guiserver.watchers import AsyncWatcher |
31 | 33 |
32 | 34 |
33 # Change statuses. | 35 # Change statuses. |
34 SCHEDULED = 'scheduled' | 36 SCHEDULED = 'scheduled' |
35 STARTED = 'started' | 37 STARTED = 'started' |
36 CANCELLED = 'cancelled' | 38 CANCELLED = 'cancelled' |
37 COMPLETED = 'completed' | 39 COMPLETED = 'completed' |
38 # Define a sequence of allowed constraints to be used in the process of | 40 # Define a sequence of allowed constraints to be used in the process of |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 Return a gen.Return instance, so that the result of this method can easily | 199 Return a gen.Return instance, so that the result of this method can easily |
198 be raised from coroutines. | 200 be raised from coroutines. |
199 """ | 201 """ |
200 if info is None: | 202 if info is None: |
201 info = {} | 203 info = {} |
202 data = {'Response': info} | 204 data = {'Response': info} |
203 if error is not None: | 205 if error is not None: |
204 logging.error('deployer: {}'.format(escape.utf8(error))) | 206 logging.error('deployer: {}'.format(escape.utf8(error))) |
205 data['Error'] = error | 207 data['Error'] = error |
206 return gen.Return(data) | 208 return gen.Return(data) |
| 209 |
| 210 |
| 211 @gen.coroutine |
| 212 def increment_deployment_counter(bundle_id, charmworld_url): |
| 213 """Increment the deployment count in Charmworld. |
| 214 |
| 215 If the call to Charmworld fails we log the error but don't report it. |
| 216 This counter is a 'best effort' attempt but it will not impede our |
| 217 deployment of the bundle. |
| 218 |
| 219 Arguments are: |
| 220 - bundle_id: the ID for the bundle in Charmworld. |
| 221 - charmworld_url: the URL for charmworld, including the protocol. |
| 222 If None, do nothing. |
| 223 |
| 224 Returns True if the counter is successfully incremented else False. |
| 225 """ |
| 226 if charmworld_url is None: |
| 227 raise gen.Return(False) |
| 228 |
| 229 if not all((isinstance(bundle_id, basestring), |
| 230 isinstance(charmworld_url, basestring))): |
| 231 raise gen.Return(False) |
| 232 |
| 233 path = 'metric/deployments/increment' |
| 234 url = u'{}api/3/bundle/{}/{}'.format( |
| 235 charmworld_url, |
| 236 urllib.quote(bundle_id), path) |
| 237 logging.info('Incrementing bundle deployment count using\n{}.'.format( |
| 238 url.encode('utf-8'))) |
| 239 client = AsyncHTTPClient() |
| 240 # We use a GET instead of a POST since there is not request body. |
| 241 try: |
| 242 resp = yield client.fetch(url, callback=None) |
| 243 except Exception as exc: |
| 244 logging.error('Attempt to increment deployment counter failed.') |
| 245 logging.error('URL: {}'.format(url)) |
| 246 logging.exception(exc) |
| 247 raise gen.Return(False) |
| 248 success = bool(resp.code == 200) |
| 249 raise gen.Return(success) |
OLD | NEW |