applications: report deployment errors (#69655)
gitea-wip/hobo/pipeline/head There was a failure building this commit Details
gitea/hobo/pipeline/head Something is wrong with the build of this commit Details

This commit is contained in:
Lauréline Guérin 2022-11-02 17:00:17 +01:00
parent 736e3e3df6
commit 8986dd9592
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
4 changed files with 77 additions and 13 deletions

View File

@ -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()

View File

@ -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);

View File

@ -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>

View File

@ -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)'