Welcome to mirror list, hosted at ThFree Co, Russian Federation.

event.rb « container_registry « models « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
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')