def regenerate_bundle_batch(): """ Submit a batch of requests to regenerate operator bundle images. :rtype: flask.Response :raise ValidationError: if required parameters are not supplied """ payload = flask.request.get_json() Batch.validate_batch_request_params(payload) batch = Batch(annotations=payload.get('annotations')) db.session.add(batch) requests = [] # Iterate through all the build requests and verify that the requests are valid before # committing them and scheduling the tasks for build_request in payload['build_requests']: try: request = RequestRegenerateBundle.from_json(build_request, batch) except ValidationError as e: # Rollback the transaction if any of the build requests are invalid db.session.rollback() raise ValidationError( f'{str(e).rstrip(".")}. This occurred on the build request in ' f'index {payload["build_requests"].index(build_request)}.') db.session.add(request) requests.append(request) db.session.commit() messaging.send_messages_for_new_batch_of_requests(requests) request_jsons = [] # This list will be used for the log message below and avoids the need of having to iterate # through the list of requests another time request_id_strs = [] for build_request, request in zip(payload['build_requests'], requests): request_jsons.append(request.to_json()) request_id_strs.append(str(request.id)) error_callback = failed_request_callback.s(request.id) handle_regenerate_bundle_request.apply_async( args=[ build_request['from_bundle_image'], build_request.get('organization'), request.id, ], link_error=error_callback, queue=_get_user_queue(), ) flask.current_app.logger.debug( 'Successfully scheduled the batch %d with requests: %s', batch.id, ', '.join(request_id_strs), ) return flask.jsonify(request_jsons), 201
def get_builds(): """ Retrieve the paginated build requests. :rtype: flask.Response """ batch_id = flask.request.args.get('batch') state = flask.request.args.get('state') verbose = str_to_bool(flask.request.args.get('verbose')) max_per_page = flask.current_app.config['IIB_MAX_PER_PAGE'] # Create an alias class to load the polymorphic classes poly_request = with_polymorphic(Request, '*') query = poly_request.query.options(*get_request_query_options( verbose=verbose)) if state: RequestStateMapping.validate_state(state) state_int = RequestStateMapping.__members__[state].value query = query.join(Request.state) query = query.filter(RequestState.state == state_int) if batch_id is not None: batch_id = Batch.validate_batch(batch_id) query = query.filter_by(batch_id=batch_id) pagination_query = query.order_by( Request.id.desc()).paginate(max_per_page=max_per_page) requests = pagination_query.items query_params = {} if state: query_params['state'] = state if verbose: query_params['verbose'] = verbose if batch_id: query_params['batch'] = batch_id response = { 'items': [request.to_json(verbose=verbose) for request in requests], 'meta': pagination_metadata(pagination_query, **query_params), } return flask.jsonify(response)
def add_rm_batch(): """ Submit a batch of requests to add or remove operators from an index image. Note: Any duplicate bundle will be removed from payload when adding operators. :rtype: flask.Response :raise ValidationError: if required parameters are not supplied """ payload = flask.request.get_json() Batch.validate_batch_request_params(payload) batch = Batch(annotations=payload.get('annotations')) db.session.add(batch) requests = [] # Iterate through all the build requests and verify that the requests are valid before # committing them and scheduling the tasks for build_request in payload['build_requests']: try: if build_request.get('operators'): # Check for the validity of a RM request request = RequestRm.from_json(build_request, batch) elif build_request.get('bundles'): build_request_uniq = copy.deepcopy(build_request) build_request_uniq['bundles'] = _get_unique_bundles(build_request_uniq['bundles']) # Check for the validity of an Add request request = RequestAdd.from_json(build_request_uniq, batch) else: raise ValidationError('Build request is not a valid Add/Rm request.') except ValidationError as e: raise ValidationError( f'{str(e).rstrip(".")}. This occurred on the build request in ' f'index {payload["build_requests"].index(build_request)}.' ) db.session.add(request) requests.append(request) db.session.commit() messaging.send_messages_for_new_batch_of_requests(requests) request_jsons = [] # This list will be used for the log message below and avoids the need of having to iterate # through the list of requests another time processed_request_ids = [] for build_request, request in zip(payload['build_requests'], requests): request_jsons.append(request.to_json()) overwrite_from_index = build_request.get('overwrite_from_index') celery_queue = _get_user_queue(serial=overwrite_from_index) if isinstance(request, RequestAdd): args = _get_add_args(build_request, request, overwrite_from_index, celery_queue) elif isinstance(request, RequestRm): args = _get_rm_args(build_request, request, overwrite_from_index) safe_args = _get_safe_args(args, build_request) error_callback = failed_request_callback.s(request.id) try: if isinstance(request, RequestAdd): handle_add_request.apply_async( args=args, link_error=error_callback, argsrepr=repr(safe_args), queue=celery_queue, ) else: handle_rm_request.apply_async( args=args, link_error=error_callback, argsrepr=repr(safe_args), queue=celery_queue, ) except kombu.exceptions.OperationalError: unprocessed_requests = [r for r in requests if str(r.id) not in processed_request_ids] handle_broker_batch_error(unprocessed_requests) processed_request_ids.append(str(request.id)) flask.current_app.logger.debug( 'Successfully scheduled the batch %d with requests: %s', batch.id, ', '.join(processed_request_ids), ) return flask.jsonify(request_jsons), 201
def get_builds(): """ Retrieve the paginated build requests. :rtype: flask.Response """ batch_id = flask.request.args.get('batch') state = flask.request.args.get('state') verbose = str_to_bool(flask.request.args.get('verbose')) max_per_page = flask.current_app.config['IIB_MAX_PER_PAGE'] request_type = flask.request.args.get('request_type') user = flask.request.args.get('user') index_image = flask.request.args.get('index_image') query_params = {} # Create an alias class to load the polymorphic classes poly_request = with_polymorphic(Request, '*') query = poly_request.query.options(*get_request_query_options( verbose=verbose)) if state: query_params['state'] = state RequestStateMapping.validate_state(state) state_int = RequestStateMapping.__members__[state].value query = query.join(Request.state) query = query.filter(RequestState.state == state_int) if batch_id is not None: query_params['batch'] = batch_id batch_id = Batch.validate_batch(batch_id) query = query.filter_by(batch_id=batch_id) if request_type: query_params['request_type'] = request_type RequestTypeMapping.validate_type(request_type) request_type = request_type.replace('-', '_') request_type_int = RequestTypeMapping.__members__[request_type].value query = query.filter(Request.type == request_type_int) if user: # join with the user table and then filter on username # request table only has the user_id query_params['user'] = user query = query.join(Request.user).filter(User.username == user) if index_image: query_params['index_image'] = index_image # Get the image id of the image to be searched image_result = Image.query.filter_by( pull_specification=index_image).first() if image_result: # join with the Request* tables to get the response as image_ids are stored there query = (query.outerjoin( RequestCreateEmptyIndex, Request.id == RequestCreateEmptyIndex.id).outerjoin( RequestAdd, Request.id == RequestAdd.id).outerjoin( RequestMergeIndexImage, Request.id == RequestMergeIndexImage.id).outerjoin( RequestRm, Request.id == RequestRm.id)) query = query.filter( or_( RequestCreateEmptyIndex.index_image_id == image_result.id, RequestAdd.index_image_id == image_result.id, RequestMergeIndexImage.index_image_id == image_result.id, RequestRm.index_image_id == image_result.id, )) # if index_image is not found in image table, then raise an error else: raise ValidationError(f'{index_image} is not a valid index image') pagination_query = query.order_by( Request.id.desc()).paginate(max_per_page=max_per_page) requests = pagination_query.items response = { 'items': [request.to_json(verbose=verbose) for request in requests], 'meta': pagination_metadata(pagination_query, **query_params), } return flask.jsonify(response)