diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
commit | b39512ed755239198a9c294b6a45e65c05900235 (patch) | |
tree | d234a3efade1de67c46b9e5a38ce813627726aa7 /app/services/ci | |
parent | d31474cf3b17ece37939d20082b07f6657cc79a9 (diff) |
Add latest changes from gitlab-org/gitlab@15-3-stable-eev15.3.0-rc42
Diffstat (limited to 'app/services/ci')
20 files changed, 203 insertions, 38 deletions
diff --git a/app/services/ci/archive_trace_service.rb b/app/services/ci/archive_trace_service.rb index 7b1d2207460..9705a236d98 100644 --- a/app/services/ci/archive_trace_service.rb +++ b/app/services/ci/archive_trace_service.rb @@ -62,8 +62,8 @@ module Ci failed_archive_counter.increment Sidekiq.logger.warn(class: worker_name, - message: "Failed to archive trace. message: #{error.message}.", - job_id: job.id) + message: "Failed to archive trace. message: #{error.message}.", + job_id: job.id) Gitlab::ErrorTracking .track_and_raise_for_dev_exception(error, diff --git a/app/services/ci/deployments/destroy_service.rb b/app/services/ci/deployments/destroy_service.rb new file mode 100644 index 00000000000..ac51fa55537 --- /dev/null +++ b/app/services/ci/deployments/destroy_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Ci + module Deployments + class DestroyService < BaseService + def execute(deployment) + raise Gitlab::Access::AccessDeniedError unless can?(current_user, :destroy_deployment, deployment) + + return ServiceResponse.error(message: 'Cannot destroy running deployment') if deployment&.running? + return ServiceResponse.error(message: 'Deployment currently deployed to environment') if deployment&.last? + + project.destroy_deployment_by_id(deployment) + + ServiceResponse.success(message: 'Deployment destroyed') + end + end + end +end diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index d85e52e1312..1c563396162 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -7,7 +7,7 @@ module Ci Ci::ExpirePipelineCacheService.new.execute(pipeline, delete: true) - pipeline.cancel_running if pipeline.cancelable? + pipeline.cancel_running(cascade_to_children: true, execute_async: false) if pipeline.cancelable? # The pipeline, the builds, job and pipeline artifacts all get destroyed here. # Ci::Pipeline#destroy triggers fast destroy on job_artifacts and diff --git a/app/services/ci/job_artifacts/create_service.rb b/app/services/ci/job_artifacts/create_service.rb index 05f8e804c67..af56eb221d5 100644 --- a/app/services/ci/job_artifacts/create_service.rb +++ b/app/services/ci/job_artifacts/create_service.rb @@ -126,6 +126,8 @@ module Ci job.update_column(:artifacts_expire_at, artifact.expire_at) end + Gitlab::Ci::Artifacts::Logger.log_created(artifact) + success(artifact: artifact) rescue ActiveRecord::RecordNotUnique => error track_exception(error, params) diff --git a/app/services/ci/job_artifacts/destroy_batch_service.rb b/app/services/ci/job_artifacts/destroy_batch_service.rb index 9d6b413ce59..54ec2c671c6 100644 --- a/app/services/ci/job_artifacts/destroy_batch_service.rb +++ b/app/services/ci/job_artifacts/destroy_batch_service.rb @@ -53,8 +53,10 @@ module Ci update_project_statistics! if update_stats increment_monitoring_statistics(artifacts_count, artifacts_bytes) + Gitlab::Ci::Artifacts::Logger.log_deleted(@job_artifacts, 'Ci::JobArtifacts::DestroyBatchService#execute') + success(destroyed_artifacts_count: artifacts_count, - statistics_updates: affected_project_statistics) + statistics_updates: affected_project_statistics) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/ci/list_config_variables_service.rb b/app/services/ci/list_config_variables_service.rb index 88dac514bb9..c791a89b804 100644 --- a/app/services/ci/list_config_variables_service.rb +++ b/app/services/ci/list_config_variables_service.rb @@ -26,8 +26,8 @@ module Ci return {} unless config result = Gitlab::Ci::YamlProcessor.new(config, project: project, - user: current_user, - sha: sha).execute + user: current_user, + sha: sha).execute result.valid? ? result.variables_with_data : {} end diff --git a/app/services/ci/parse_dotenv_artifact_service.rb b/app/services/ci/parse_dotenv_artifact_service.rb index 40e2cd82b4f..fd13ed245cf 100644 --- a/app/services/ci/parse_dotenv_artifact_service.rb +++ b/app/services/ci/parse_dotenv_artifact_service.rb @@ -40,7 +40,7 @@ module Ci key, value = scan_line!(line) variables[key] = Ci::JobVariable.new(job_id: artifact.job_id, - source: :dotenv, key: key, value: value) + source: :dotenv, key: key, value: value) end end diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 8969b95b81f..b357855db12 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -4,6 +4,8 @@ module Ci # This class responsible for assigning # proper pending build to runner on runner API request class RegisterJobService + include ::Gitlab::Ci::Artifacts::Logger + attr_reader :runner, :metrics TEMPORARY_LOCK_TIMEOUT = 3.seconds @@ -220,10 +222,26 @@ module Ci # We need to use the presenter here because Gitaly calls in the presenter # may fail, and we need to ensure the response has been generated. presented_build = ::Ci::BuildRunnerPresenter.new(build) # rubocop:disable CodeReuse/Presenter + + log_artifacts_context(build) + log_build_dependencies_size(presented_build) + build_json = ::API::Entities::Ci::JobRequest::Response.new(presented_build).to_json Result.new(build, build_json, true) end + def log_build_dependencies_size(presented_build) + return unless ::Feature.enabled?(:ci_build_dependencies_artifacts_logger, type: :ops) + + presented_build.all_dependencies.then do |dependencies| + size = dependencies.sum do |build| + build.available_artifacts? ? build.artifacts_file.size : 0 + end + + log_build_dependencies(size: size, count: dependencies.size) if size > 0 + end + end + def assign_runner!(build, params) build.runner_id = runner.id build.runner_session_attributes = params[:session] if params[:session].present? diff --git a/app/services/ci/retry_job_service.rb b/app/services/ci/retry_job_service.rb index e0ced3d0197..25bda8a6380 100644 --- a/app/services/ci/retry_job_service.rb +++ b/app/services/ci/retry_job_service.rb @@ -4,10 +4,10 @@ module Ci class RetryJobService < ::BaseService include Gitlab::Utils::StrongMemoize - def execute(job) + def execute(job, variables: []) if job.retryable? job.ensure_scheduling_type! - new_job = retry_job(job) + new_job = retry_job(job, variables: variables) ServiceResponse.success(payload: { job: new_job }) else @@ -19,7 +19,7 @@ module Ci end # rubocop: disable CodeReuse/ActiveRecord - def clone!(job) + def clone!(job, variables: []) # Cloning a job requires a strict type check to ensure # the attributes being used for the clone are taken straight # from the model and not overridden by other abstractions. @@ -27,7 +27,7 @@ module Ci check_access!(job) - new_job = job.clone(current_user: current_user) + new_job = job.clone(current_user: current_user, new_job_variables_attributes: variables) new_job.run_after_commit do ::Ci::CopyCrossDatabaseAssociationsService.new.execute(job, new_job) @@ -55,8 +55,8 @@ module Ci def check_assignable_runners!(job); end - def retry_job(job) - clone!(job).tap do |new_job| + def retry_job(job, variables: []) + clone!(job, variables: variables).tap do |new_job| check_assignable_runners!(new_job) if new_job.is_a?(Ci::Build) next if new_job.failed? diff --git a/app/services/ci/runners/assign_runner_service.rb b/app/services/ci/runners/assign_runner_service.rb index 886cd3a4e44..290f945cc72 100644 --- a/app/services/ci/runners/assign_runner_service.rb +++ b/app/services/ci/runners/assign_runner_service.rb @@ -13,9 +13,15 @@ module Ci end def execute - return false unless @user.present? && @user.can?(:assign_runner, @runner) + unless @user.present? && @user.can?(:assign_runner, @runner) + return ServiceResponse.error(message: 'user not allowed to assign runner', http_status: :forbidden) + end - @runner.assign_to(@project, @user) + if @runner.assign_to(@project, @user) + ServiceResponse.success + else + ServiceResponse.error(message: 'failed to assign runner') + end end private diff --git a/app/services/ci/runners/bulk_delete_runners_service.rb b/app/services/ci/runners/bulk_delete_runners_service.rb new file mode 100644 index 00000000000..ce07aa541c2 --- /dev/null +++ b/app/services/ci/runners/bulk_delete_runners_service.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Ci + module Runners + class BulkDeleteRunnersService + attr_reader :runners + + RUNNER_LIMIT = 50 + + # @param runners [Array<Ci::Runner, Integer>] the runners to unregister/destroy + def initialize(runners:) + @runners = runners + end + + def execute + if @runners + # Delete a few runners immediately + return ServiceResponse.success(payload: delete_runners) + end + + ServiceResponse.success(payload: { deleted_count: 0, deleted_ids: [] }) + end + + private + + def delete_runners + # rubocop:disable CodeReuse/ActiveRecord + runners_to_be_deleted = Ci::Runner.where(id: @runners).limit(RUNNER_LIMIT) + # rubocop:enable CodeReuse/ActiveRecord + deleted_ids = runners_to_be_deleted.destroy_all.map(&:id) # rubocop: disable Cop/DestroyAll + + { deleted_count: deleted_ids.count, deleted_ids: deleted_ids } + end + end + end +end diff --git a/app/services/ci/runners/process_runner_version_update_service.rb b/app/services/ci/runners/process_runner_version_update_service.rb new file mode 100644 index 00000000000..c8a5e42ccab --- /dev/null +++ b/app/services/ci/runners/process_runner_version_update_service.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Ci + module Runners + class ProcessRunnerVersionUpdateService + def initialize(version) + @version = version + end + + def execute + return ServiceResponse.error(message: 'version not present') unless @version + + _, status = upgrade_check_service.check_runner_upgrade_suggestion(@version) + return ServiceResponse.error(message: 'upgrade version check failed') if status == :error + + Ci::RunnerVersion.upsert({ version: @version, status: status }) + ServiceResponse.success(payload: { upgrade_status: status.to_s }) + end + + private + + def upgrade_check_service + @runner_upgrade_check ||= Gitlab::Ci::RunnerUpgradeCheck.new(::Gitlab::VERSION) + end + end + end +end diff --git a/app/services/ci/runners/reconcile_existing_runner_versions_service.rb b/app/services/ci/runners/reconcile_existing_runner_versions_service.rb index e04079bfe27..1950d82845b 100644 --- a/app/services/ci/runners/reconcile_existing_runner_versions_service.rb +++ b/app/services/ci/runners/reconcile_existing_runner_versions_service.rb @@ -3,8 +3,6 @@ module Ci module Runners class ReconcileExistingRunnerVersionsService - include BaseServiceUtility - VERSION_BATCH_SIZE = 100 def execute @@ -12,7 +10,7 @@ module Ci total_deleted = cleanup_runner_versions(insert_result[:versions_from_runners]) total_updated = update_status_on_outdated_runner_versions(insert_result[:versions_from_runners]) - success({ + ServiceResponse.success(payload: { total_inserted: insert_result[:new_record_count], total_updated: total_updated, total_deleted: total_deleted @@ -22,7 +20,7 @@ module Ci private def upgrade_check - Gitlab::Ci::RunnerUpgradeCheck.instance + @runner_upgrade_check ||= Gitlab::Ci::RunnerUpgradeCheck.new(::Gitlab::VERSION) end # rubocop: disable CodeReuse/ActiveRecord @@ -74,13 +72,11 @@ module Ci end def runner_version_with_updated_status(runner_version) - version = runner_version['version'] - suggestion = upgrade_check.check_runner_upgrade_status(version) - new_status = suggestion.each_key.first + _, new_status = upgrade_check.check_runner_upgrade_suggestion(runner_version.version) - if new_status != :error && new_status != runner_version['status'].to_sym + if new_status != :error && new_status != runner_version.status.to_sym { - version: version, + version: runner_version.version, status: Ci::RunnerVersion.statuses[new_status] } end diff --git a/app/services/ci/runners/register_runner_service.rb b/app/services/ci/runners/register_runner_service.rb index 6588cd7e248..ae9b8bc8a16 100644 --- a/app/services/ci/runners/register_runner_service.rb +++ b/app/services/ci/runners/register_runner_service.rb @@ -6,7 +6,7 @@ module Ci def execute(registration_token, attributes) runner_type_attrs = extract_runner_type_attrs(registration_token) - return unless runner_type_attrs + return ServiceResponse.error(message: 'invalid token supplied', http_status: :forbidden) unless runner_type_attrs runner = ::Ci::Runner.new(attributes.merge(runner_type_attrs)) @@ -20,7 +20,7 @@ module Ci end end - runner + ServiceResponse.success(payload: { runner: runner }) end private diff --git a/app/services/ci/runners/reset_registration_token_service.rb b/app/services/ci/runners/reset_registration_token_service.rb index 81a70a771cf..dddbfb78d44 100644 --- a/app/services/ci/runners/reset_registration_token_service.rb +++ b/app/services/ci/runners/reset_registration_token_service.rb @@ -11,15 +11,19 @@ module Ci end def execute - return unless @user.present? && @user.can?(:update_runners_registration_token, scope) + unless @user.present? && @user.can?(:update_runners_registration_token, scope) + return ServiceResponse.error(message: 'user not allowed to update runners registration token') + end if scope.respond_to?(:runners_registration_token) scope.reset_runners_registration_token! - scope.runners_registration_token + runners_token = scope.runners_registration_token else scope.reset_runners_token! - scope.runners_token + runners_token = scope.runners_token end + + ServiceResponse.success(payload: { new_registration_token: runners_token }) end private diff --git a/app/services/ci/runners/unassign_runner_service.rb b/app/services/ci/runners/unassign_runner_service.rb index 1e46cf6add8..c40e5e0d44e 100644 --- a/app/services/ci/runners/unassign_runner_service.rb +++ b/app/services/ci/runners/unassign_runner_service.rb @@ -13,9 +13,15 @@ module Ci end def execute - return false unless @user.present? && @user.can?(:assign_runner, @runner) + unless @user.present? && @user.can?(:assign_runner, @runner) + return ServiceResponse.error(message: 'user not allowed to assign runner') + end - @runner_project.destroy + if @runner_project.destroy + ServiceResponse.success + else + ServiceResponse.error(message: 'failed to destroy runner project') + end end private diff --git a/app/services/ci/runners/unregister_runner_service.rb b/app/services/ci/runners/unregister_runner_service.rb index 4ee1e73c458..742b21f77df 100644 --- a/app/services/ci/runners/unregister_runner_service.rb +++ b/app/services/ci/runners/unregister_runner_service.rb @@ -14,6 +14,7 @@ module Ci def execute @runner&.destroy + ServiceResponse.success end end end diff --git a/app/services/ci/stuck_builds/drop_helpers.rb b/app/services/ci/stuck_builds/drop_helpers.rb index 048b52c6e13..dca50963883 100644 --- a/app/services/ci/stuck_builds/drop_helpers.rb +++ b/app/services/ci/stuck_builds/drop_helpers.rb @@ -56,12 +56,12 @@ module Ci def log_dropping_message(type, build, reason) Gitlab::AppLogger.info(class: self.class.name, - message: "Dropping #{type} build", - build_stuck_type: type, - build_id: build.id, - runner_id: build.runner_id, - build_status: build.status, - build_failure_reason: reason) + message: "Dropping #{type} build", + build_stuck_type: type, + build_id: build.id, + runner_id: build.runner_id, + build_status: build.status, + build_failure_reason: reason) end end end diff --git a/app/services/ci/track_failed_build_service.rb b/app/services/ci/track_failed_build_service.rb new file mode 100644 index 00000000000..caf7034234c --- /dev/null +++ b/app/services/ci/track_failed_build_service.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +# This service tracks failed CI builds using Snowplow. +# +# @param build [Ci::Build] the build that failed. +# @param exit_code [Int] the resulting exit code. +module Ci + class TrackFailedBuildService + SCHEMA_URL = 'iglu:com.gitlab/ci_build_failed/jsonschema/1-0-0' + + def initialize(build:, exit_code:, failure_reason:) + @build = build + @exit_code = exit_code + @failure_reason = failure_reason + end + + def execute + # rubocop:disable Style/IfUnlessModifier + unless @build.failed? + return ServiceResponse.error(message: 'Attempted to track a non-failed CI build') + end + + # rubocop:enable Style/IfUnlessModifier + + context = SnowplowTracker::SelfDescribingJson.new(SCHEMA_URL, payload) + + ::Gitlab::Tracking.event( + 'ci::build', + 'failed', + context: [context], + user: @build.user, + project: @build.project_id) + + ServiceResponse.success + end + + private + + def payload + { + build_id: @build.id, + build_name: @build.name, + build_artifact_types: @build.job_artifact_types, + exit_code: @exit_code, + failure_reason: @failure_reason + } + end + end +end diff --git a/app/services/ci/update_build_state_service.rb b/app/services/ci/update_build_state_service.rb index a74ddcfaf06..835d5f9a16c 100644 --- a/app/services/ci/update_build_state_service.rb +++ b/app/services/ci/update_build_state_service.rb @@ -105,7 +105,7 @@ module Ci Result.new(status: 200) when 'failed' - build.drop_with_exit_code!(params[:failure_reason] || :unknown_failure, params[:exit_code]) + build.drop_with_exit_code!(params[:failure_reason], params[:exit_code]) Result.new(status: 200) else |