applications: report deployment errors (#69655)
This commit is contained in:
parent
736e3e3df6
commit
8986dd9592
|
@ -37,6 +37,11 @@ from .utils import Requests
|
|||
requests = Requests()
|
||||
|
||||
|
||||
class DeploymentError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
|
||||
class Application(models.Model):
|
||||
SUPPORTED_MODULES = ('wcs',)
|
||||
|
||||
|
@ -204,8 +209,9 @@ class Version(models.Model):
|
|||
url = urllib.parse.urljoin(service['url'], 'api/export-import/bundle-import/')
|
||||
response = requests.put(url, data=bundle_content)
|
||||
if not response.ok:
|
||||
# TODO: report failures
|
||||
continue
|
||||
raise DeploymentError(
|
||||
_('Failed to deploy module %s (%s)') % (service_id, response.status_code)
|
||||
)
|
||||
# TODO: look at response content for afterjob URLs to display a progress bar
|
||||
pass
|
||||
|
||||
|
@ -232,13 +238,15 @@ class Version(models.Model):
|
|||
# create or update
|
||||
response = requests.post(roles_api_url, json=role_info)
|
||||
if not response.ok:
|
||||
# TODO: report failures
|
||||
continue
|
||||
raise DeploymentError(
|
||||
_('Failed to create role %s (%s)') % (element['slug'], response.status_code)
|
||||
)
|
||||
# then force provisionning
|
||||
response = requests.post(provision_api_url, json={'role_uuid': response.json()['uuid']})
|
||||
if not response.ok:
|
||||
# TODO: report failures
|
||||
continue
|
||||
raise DeploymentError(
|
||||
_('Failed to provision role %s (%s)') % (element['slug'], response.status_code)
|
||||
)
|
||||
|
||||
|
||||
class AsyncJob(models.Model):
|
||||
|
@ -281,12 +289,18 @@ class AsyncJob(models.Model):
|
|||
self.version.create_bundle()
|
||||
elif self.action == 'deploy':
|
||||
self.version.deploy()
|
||||
except Exception:
|
||||
except DeploymentError as e:
|
||||
self.status = 'failed'
|
||||
self.exception = e.msg
|
||||
if self.raise_exception:
|
||||
raise
|
||||
except Exception:
|
||||
self.status = 'failed'
|
||||
self.exception = traceback.format_exc()
|
||||
if self.raise_exception:
|
||||
raise
|
||||
finally:
|
||||
self.status = 'completed'
|
||||
self.completion_timestamp = now()
|
||||
self.save()
|
||||
if self.status == 'running':
|
||||
self.status = 'completed'
|
||||
self.completion_timestamp = now()
|
||||
self.save()
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
$(function () {
|
||||
if ("{{ object.status }}" == "completed") {
|
||||
window.location = "{{ view.get_redirect_url }}";
|
||||
} else {
|
||||
} else if ("{{ object.status }}" != "failed") {
|
||||
setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
|
|
|
@ -24,8 +24,13 @@
|
|||
{% for job in version.asyncjob_set.all %}
|
||||
<li>
|
||||
{{ job.label }}
|
||||
({% blocktrans with sdate=job.creation_timestamp|date:"DATETIME_FORMAT" edate=job.completion_timestamp|date:"DATETIME_FORMAT" %}started at {{ sdate }}, ended at {{ edate }}{% endblocktrans %})
|
||||
{% if job.completion_timestamp %}
|
||||
({% blocktrans with sdate=job.creation_timestamp|date:"DATETIME_FORMAT" edate=job.completion_timestamp|date:"DATETIME_FORMAT" %}started at {{ sdate }}, ended at {{ edate }}{% endblocktrans %})
|
||||
{% else %}
|
||||
({% blocktrans with sdate=job.creation_timestamp|date:"DATETIME_FORMAT" %}started at {{ sdate }}{% endblocktrans %})
|
||||
{% endif %}
|
||||
- {% trans "status:" %} {{ job.get_status_display }}
|
||||
{% if job.status == 'failed' %}[{{ job.exception|truncatechars:50 }}]{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -10,7 +10,7 @@ from httmock import HTTMock
|
|||
from test_manager import login
|
||||
from webtest import Upload
|
||||
|
||||
from hobo.applications.models import Application, Element, Relation, Version
|
||||
from hobo.applications.models import Application, AsyncJob, DeploymentError, Element, Relation, Version
|
||||
from hobo.environment.models import Authentic, Wcs
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -534,6 +534,21 @@ def test_deploy_application(app, admin_user, settings, app_bundle, app_bundle_wi
|
|||
assert resp.text.count('43.0') == 1
|
||||
assert resp.text.count('Deploying application bundle') == 4
|
||||
|
||||
def response_content(url, request):
|
||||
if url.path == '/api/export-import/bundle-import/':
|
||||
return {'status_code': 500}
|
||||
return mocked_http(url, request)
|
||||
|
||||
resp = app.get('/applications/install/')
|
||||
resp.form['bundle'] = Upload('app.tar', app_bundle, 'application/x-tar')
|
||||
with HTTMock(response_content):
|
||||
with pytest.raises(DeploymentError) as e:
|
||||
resp.form.submit()
|
||||
assert str(e.value) == 'Failed to deploy module wcs (500)'
|
||||
job = AsyncJob.objects.latest('pk')
|
||||
assert job.status == 'failed'
|
||||
assert job.exception == 'Failed to deploy module wcs (500)'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app_bundle_roles():
|
||||
|
@ -617,3 +632,33 @@ def test_deploy_application_roles(app, admin_user, settings, app_bundle_roles):
|
|||
# then form
|
||||
assert 'wcs.example.invalid' in mocked_http.call['requests'][4].url
|
||||
assert mocked_http.call['count'] == 5
|
||||
|
||||
def response_content(url, request):
|
||||
if url.path == '/api/roles/':
|
||||
return {'status_code': 500}
|
||||
return mocked_http(url, request)
|
||||
|
||||
resp = app.get('/applications/install/')
|
||||
resp.form['bundle'] = Upload('app.tar', app_bundle_roles, 'application/x-tar')
|
||||
with HTTMock(response_content):
|
||||
with pytest.raises(DeploymentError) as e:
|
||||
resp.form.submit()
|
||||
assert str(e.value) == 'Failed to create role test-role (500)'
|
||||
job = AsyncJob.objects.latest('pk')
|
||||
assert job.status == 'failed'
|
||||
assert job.exception == 'Failed to create role test-role (500)'
|
||||
|
||||
def response_content(url, request):
|
||||
if url.path == '/api/provision/':
|
||||
return {'status_code': 500}
|
||||
return mocked_http(url, request)
|
||||
|
||||
resp = app.get('/applications/install/')
|
||||
resp.form['bundle'] = Upload('app.tar', app_bundle_roles, 'application/x-tar')
|
||||
with HTTMock(response_content):
|
||||
with pytest.raises(DeploymentError) as e:
|
||||
resp.form.submit()
|
||||
assert str(e.value) == 'Failed to provision role test-role (500)'
|
||||
job = AsyncJob.objects.latest('pk')
|
||||
assert job.status == 'failed'
|
||||
assert job.exception == 'Failed to provision role test-role (500)'
|
||||
|
|
Loading…
Reference in New Issue