Allow resuming from a failure during the "init" phase

This also shifts build failure transitions from individual functions
in utils.py to the init module handler.
This commit is contained in:
mprahl
2017-11-06 13:03:10 -05:00
parent 80df4be363
commit d8f126e978
9 changed files with 158 additions and 37 deletions

View File

@@ -265,6 +265,9 @@ class ModuleBuild(MBSBase):
# If the rebuild_strategy isn't specified, use the default
rebuild_strategy=rebuild_strategy or conf.rebuild_strategy
)
# Add a state transition to "init"
mbt = ModuleBuildTrace(state_time=now, state=module.state)
module.module_builds_trace.append(mbt)
session.add(module)
session.commit()
module_build_service.messaging.publish(

View File

@@ -132,7 +132,7 @@ def get_variant_dict(data):
result['active'] = data['active']
if not result:
raise ValueError("Couldn't get variant_dict from %s" % data)
raise RuntimeError("Couldn't get variant_dict from %s" % data)
return result

View File

@@ -32,7 +32,7 @@ from module_build_service.utils import (
attempt_to_reuse_all_components,
record_component_builds,
get_rpm_release_from_mmd)
from module_build_service.errors import UnprocessableEntity
from module_build_service.errors import UnprocessableEntity, Forbidden, ValidationError
from module_build_service.builder.KojiContentGenerator import KojiContentGenerator
from requests.exceptions import ConnectionError
@@ -139,8 +139,17 @@ def init(config, session, msg):
record_component_builds(mmd, build, session=session)
build.modulemd = mmd.dumps()
build.transition(conf, models.BUILD_STATES["wait"])
except UnprocessableEntity:
build.transition(conf, models.BUILD_STATES["failed"])
# Catch custom exceptions that we can expose to the user
except (UnprocessableEntity, Forbidden, ValidationError, RuntimeError) as e:
# Rollback changes underway
session.rollback()
build.transition(conf, models.BUILD_STATES["failed"], state_reason=str(e))
except Exception as e:
log.exception(str(e))
# Rollback changes underway
session.rollback()
msg = "An unknown error occurred while validating the modulemd"
build.transition(conf, models.BUILD_STATES["failed"], state_reason=msg)
finally:
session.add(build)
session.commit()

View File

@@ -843,14 +843,7 @@ def record_component_builds(mmd, module, initial_batch=1,
# Format the modulemd by putting in defaults and replacing streams that
# are branches with commit hashes
try:
format_mmd(mmd, module.scmurl, session=session)
except Exception as e:
module.transition(conf, models.BUILD_STATES["failed"],
"Failed to validate modulemd file: %s" % str(e))
session.add(module)
session.commit()
raise
format_mmd(mmd, module.scmurl, session=session)
# When main_mmd is set, merge the metadata from this mmd to main_mmd,
# otherwise our current mmd is main_mmd.
@@ -865,10 +858,7 @@ def record_component_builds(mmd, module, initial_batch=1,
'conflicting components: {2}'
.format(mmd.name, main_mmd.name,
', '.join(duplicate_components)))
module.transition(conf, models.BUILD_STATES["failed"], error_msg)
session.add(module)
session.commit()
raise RuntimeError(error_msg)
raise UnprocessableEntity(error_msg)
merge_included_mmd(main_mmd, mmd)
else:
main_mmd = mmd
@@ -979,9 +969,15 @@ def submit_module_build(username, url, mmd, scm, optional_params=None):
component.state = None
db.session.add(component)
module.username = username
module.transition(conf, models.BUILD_STATES["wait"],
"Resubmitted by %s" % username)
module.batch = 0
# The last transition in the trace will be "failed", but we want to determine what the
# state was previous to the failure.
prev_state = module.module_builds_trace[-2].state
if prev_state == models.BUILD_STATES['init']:
transition_to = models.BUILD_STATES['init']
else:
transition_to = models.BUILD_STATES['wait']
module.batch = 0
module.transition(conf, transition_to, "Resubmitted by %s" % username)
log.info("Resumed existing module build in previous state %s"
% module.state)
else:

View File

@@ -181,6 +181,9 @@ class ModuleBuildAPI(AbstractQueryableBuildAPI):
log.error('Invalid JSON submitted')
raise ValidationError('Invalid JSON submitted')
if module.state == models.BUILD_STATES['failed']:
raise Forbidden('You can\'t cancel a failed module')
if r['state'] == 'failed' \
or r['state'] == str(models.BUILD_STATES['failed']):
module.transition(conf, models.BUILD_STATES["failed"],