1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# frozen_string_literal: true
module Ci
class AppendBuildTraceService
Result = Struct.new(:status, :stream_size, keyword_init: true)
TraceRangeError = Class.new(StandardError)
attr_reader :build, :params
def initialize(build, params)
@build = build
@params = params
end
def execute(body_data)
# TODO:
# it seems that `Content-Range` as formatted by runner is wrong,
# the `byte_end` should point to final byte, but it points byte+1
# that means that we have to calculate end of body,
# as we cannot use `content_length[1]`
# Issue: https://gitlab.com/gitlab-org/gitlab-runner/issues/3275
# Update the build metadata prior to appending trace content
update_build_metadata if debug_trace
content_range = stream_range.split('-')
body_start = content_range[0].to_i
body_end = body_start + body_data.bytesize
if trace_size_exceeded?(body_end)
build.drop(:trace_size_exceeded)
return Result.new(status: 403)
end
stream_size = build.trace.append(body_data, body_start)
unless stream_size == body_end
log_range_error(stream_size, body_end)
return Result.new(status: 416, stream_size: stream_size)
end
Result.new(status: 202, stream_size: stream_size)
end
private
delegate :project, to: :build
def stream_range
params.fetch(:content_range)
end
def debug_trace
params.fetch(:debug_trace, false)
end
# rubocop: disable CodeReuse/ActiveRecord
def update_build_metadata
metadata = Ci::BuildMetadata.find_by(build_id: build)
metadata.update!(debug_trace_enabled: debug_trace)
end
# rubocop: enable CodeReuse/ActiveRecord
def log_range_error(stream_size, body_end)
extra = {
build_id: build.id,
body_end: body_end,
stream_size: stream_size,
stream_class: stream_size.class,
stream_range: stream_range
}
build.trace_chunks.last.try do |chunk|
extra.merge!(
chunk_index: chunk.chunk_index,
chunk_store: chunk.data_store,
chunks_count: build.trace_chunks.count
)
end
::Gitlab::ErrorTracking
.log_exception(TraceRangeError.new, extra)
end
def trace_size_exceeded?(size)
project.actual_limits.exceeded?(:ci_jobs_trace_size_limit, size / 1.megabyte)
end
end
end
|