blob: c4d06be8841d3e38a67aefe7df43ebc1bafc079f (
plain)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# frozen_string_literal: true
module ContainerRegistry
class Event
include Gitlab::Utils::StrongMemoize
ALLOWED_ACTIONS = %w(push delete).freeze
PUSH_ACTION = 'push'
DELETE_ACTION = 'delete'
EVENT_TRACKING_CATEGORY = 'container_registry:notification'
EVENT_PREFIX = "i_container_registry"
ALLOWED_ACTOR_TYPES = %w(
personal_access_token
build
gitlab_or_ldap
).freeze
TRACKABLE_ACTOR_EVENTS = %w(
push_tag
delete_tag
push_repository
delete_repository
create_repository
).freeze
attr_reader :event
def initialize(event)
@event = event
end
def supported?
action.in?(ALLOWED_ACTIONS)
end
def handle!
update_project_statistics
end
def track!
tracked_target = target_tag? ? :tag : :repository
tracking_action = "#{action}_#{tracked_target}"
if target_repository? && action_push? && !container_repository_exists?
tracking_action = "create_repository"
end
::Gitlab::Tracking.event(EVENT_TRACKING_CATEGORY, tracking_action)
event = usage_data_event_for(tracking_action)
::Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event, values: originator.id) if event
end
private
def target_tag?
# There is no clear indication in the event structure when we delete a top-level manifest
# except existance of "tag" key
event['target'].has_key?('tag')
end
def target_digest?
event['target'].has_key?('digest')
end
def target_repository?
!target_tag? && event['target'].has_key?('repository')
end
def action
event['action']
end
def action_push?
PUSH_ACTION == action
end
def action_delete?
DELETE_ACTION == action
end
def container_repository_exists?
return unless container_registry_path
ContainerRepository.exists_by_path?(container_registry_path)
end
def container_registry_path
strong_memoize(:container_registry_path) do
path = event.dig('target', 'repository')
next unless path
ContainerRegistry::Path.new(path)
end
end
def project
container_registry_path&.repository_project
end
# counter name for unique user tracking (for MAU)
def usage_data_event_for(tracking_action)
return unless originator
return unless TRACKABLE_ACTOR_EVENTS.include?(tracking_action)
"#{EVENT_PREFIX}_#{tracking_action}_user"
end
def originator_type
event.dig('actor', 'user_type')
end
def originator
return unless ALLOWED_ACTOR_TYPES.include?(originator_type)
username = event.dig('actor', 'name')
return unless username
strong_memoize(:originator) do
User.find_by_username(username)
end
end
def update_project_statistics
return unless supported?
return unless target_tag? || (action_delete? && target_digest?)
return unless project
Rails.cache.delete(project.root_ancestor.container_repositories_size_cache_key)
ProjectCacheWorker.perform_async(project.id, [], [:container_registry_size])
end
end
end
::ContainerRegistry::Event.prepend_mod_with('ContainerRegistry::Event')
|