File: update_environment_service.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (136 lines) | stat: -rw-r--r-- 3,745 bytes parent folder | download
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 Deployments
  class UpdateEnvironmentService
    attr_reader :deployment
    attr_reader :deployable

    delegate :environment, to: :deployment
    delegate :variables, to: :deployable
    delegate :options, to: :deployable, allow_nil: true

    EnvironmentUpdateFailure = Class.new(StandardError)

    def initialize(deployment)
      @deployment = deployment
      @deployable = deployment.deployable
    end

    def execute
      deployment.create_ref
      deployment.invalidate_cache

      update_environment(deployment)

      deployment
    end

    def update_environment(deployment)
      ApplicationRecord.transaction do
        # Renew attributes at update
        renew_external_url
        renew_auto_stop_in
        renew_deployment_tier
        renew_cluster_agent
        environment.fire_state_event(action)

        if environment.save
          deployment.update_merge_request_metrics! unless environment.stopped?
        else
          # If there is a validation error on environment update, such as
          # the external URL is malformed, the error message is recorded for debugging purpose.
          # We should surface the error message to users for letting them to take an action.
          # See https://gitlab.com/gitlab-org/gitlab/-/issues/21182.
          Gitlab::ErrorTracking.track_exception(
            EnvironmentUpdateFailure.new,
            project_id: deployment.project_id,
            environment_id: environment.id,
            reason: environment.errors.full_messages.to_sentence)
        end
      end
    end

    private

    def environment_options
      options&.dig(:environment) || {}
    end

    def expanded_environment_url
      return unless environment_url

      ExpandVariables.expand(environment_url, -> { variables.sort_and_expand_all })
    end

    def expanded_auto_stop_in
      return unless auto_stop_in

      ExpandVariables.expand(auto_stop_in, -> { variables.sort_and_expand_all })
    end

    def expanded_cluster_agent_path
      return unless cluster_agent_path

      ExpandVariables.expand(cluster_agent_path, -> { variables.sort_and_expand_all })
    end

    def environment_url
      environment_options[:url]
    end

    def action
      environment_options[:action] || 'start'
    end

    def auto_stop_in
      deployable&.environment_auto_stop_in
    end

    def cluster_agent_path
      environment_options.dig(:kubernetes, :agent)
    end

    def renew_external_url
      if (url = expanded_environment_url)
        environment.external_url = url
      end
    end

    def renew_auto_stop_in
      return unless deployable

      if (value = expanded_auto_stop_in)
        environment.auto_stop_in = value
      end
    end

    def renew_deployment_tier
      return unless deployable

      if (tier = deployable.environment_tier_from_options)
        environment.tier = tier
      end
    end

    def renew_cluster_agent
      return unless cluster_agent_path && deployable.user

      requested_project_path, requested_agent_name = expanded_cluster_agent_path.split(':')

      matching_authorization = user_access_authorizations_for_project.find do |authorization|
        requested_project_path == authorization.config_project.full_path &&
          requested_agent_name == authorization.agent.name
      end

      return unless matching_authorization

      environment.cluster_agent = matching_authorization.agent
    end

    def user_access_authorizations_for_project
      Clusters::Agents::Authorizations::UserAccess::Finder.new(deployable.user, project: deployable.project).execute
    end
  end
end

Deployments::UpdateEnvironmentService.prepend_mod_with('Deployments::UpdateEnvironmentService')