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')
|