summaryrefslogtreecommitdiff
path: root/app/services/clusters/parse_cluster_applications_artifact_service.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/clusters/parse_cluster_applications_artifact_service.rb')
-rw-r--r--app/services/clusters/parse_cluster_applications_artifact_service.rb95
1 files changed, 95 insertions, 0 deletions
diff --git a/app/services/clusters/parse_cluster_applications_artifact_service.rb b/app/services/clusters/parse_cluster_applications_artifact_service.rb
new file mode 100644
index 00000000000..b8e1c80cfe7
--- /dev/null
+++ b/app/services/clusters/parse_cluster_applications_artifact_service.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+module Clusters
+ class ParseClusterApplicationsArtifactService < ::BaseService
+ include Gitlab::Utils::StrongMemoize
+
+ MAX_ACCEPTABLE_ARTIFACT_SIZE = 5.kilobytes
+ RELEASE_NAMES = %w[prometheus].freeze
+
+ def initialize(job, current_user)
+ @job = job
+
+ super(job.project, current_user)
+ end
+
+ def execute(artifact)
+ return success unless Feature.enabled?(:cluster_applications_artifact, project)
+
+ raise ArgumentError, 'Artifact is not cluster_applications file type' unless artifact&.cluster_applications?
+
+ unless artifact.file.size < MAX_ACCEPTABLE_ARTIFACT_SIZE
+ return error(too_big_error_message, :bad_request)
+ end
+
+ unless cluster
+ return error(s_('ClusterIntegration|No deployment cluster found for this job'))
+ end
+
+ parse!(artifact)
+
+ success
+ rescue Gitlab::Kubernetes::Helm::Parsers::ListV2::ParserError, ActiveRecord::RecordInvalid => error
+ Gitlab::ErrorTracking.track_exception(error, job_id: artifact.job_id)
+ error(error.message, :bad_request)
+ end
+
+ private
+
+ attr_reader :job
+
+ def cluster
+ strong_memoize(:cluster) do
+ deployment_cluster = job.deployment&.cluster
+
+ deployment_cluster if Ability.allowed?(current_user, :admin_cluster, deployment_cluster)
+ end
+ end
+
+ def parse!(artifact)
+ releases = []
+
+ artifact.each_blob do |blob|
+ releases.concat(Gitlab::Kubernetes::Helm::Parsers::ListV2.new(blob).releases)
+ end
+
+ update_cluster_application_statuses!(releases)
+ end
+
+ def update_cluster_application_statuses!(releases)
+ release_by_name = releases.index_by { |release| release['Name'] }
+
+ Clusters::Cluster.transaction do
+ RELEASE_NAMES.each do |release_name|
+ application = find_or_build_application(release_name)
+
+ release = release_by_name[release_name]
+
+ if release
+ case release['Status']
+ when 'DEPLOYED'
+ application.make_externally_installed!
+ when 'FAILED'
+ application.make_errored!(s_('ClusterIntegration|Helm release failed to install'))
+ end
+ else
+ # missing, so by definition, we consider this uninstalled
+ application.make_externally_uninstalled! if application.persisted?
+ end
+ end
+ end
+ end
+
+ def find_or_build_application(application_name)
+ application_class = Clusters::Cluster::APPLICATIONS[application_name]
+
+ cluster.find_or_build_application(application_class)
+ end
+
+ def too_big_error_message
+ human_size = ActiveSupport::NumberHelper.number_to_human_size(MAX_ACCEPTABLE_ARTIFACT_SIZE)
+
+ s_('ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}') % { human_size: human_size }
+ end
+ end
+end