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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-21 15:06:14 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-21 15:06:14 +0300
commit664c4c7b49c6056136299817eb79e9f1de83e567 (patch)
treeff9e4f53481d42284f82664722278e05f5bbbcbd /app/services
parent6791eefead979110cc773720daee6e58c56483d9 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/services')
-rw-r--r--app/services/create_branch_service.rb2
-rw-r--r--app/services/metrics/dashboard/grafana_metric_embed_service.rb157
2 files changed, 158 insertions, 1 deletions
diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb
index 110e589e30d..d58cb0f9e2b 100644
--- a/app/services/create_branch_service.rb
+++ b/app/services/create_branch_service.rb
@@ -14,7 +14,7 @@ class CreateBranchService < BaseService
if new_branch
success(new_branch)
else
- error('Invalid reference name')
+ error("Invalid reference name: #{branch_name}")
end
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
diff --git a/app/services/metrics/dashboard/grafana_metric_embed_service.rb b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
new file mode 100644
index 00000000000..f302a786ba8
--- /dev/null
+++ b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+# Responsible for returning a gitlab-compatible dashboard
+# containing info based on a grafana dashboard and datasource.
+#
+# Use Gitlab::Metrics::Dashboard::Finder to retrive dashboards.
+module Metrics
+ module Dashboard
+ class GrafanaMetricEmbedService < ::Metrics::Dashboard::BaseService
+ include ReactiveCaching
+
+ SEQUENCE = [
+ ::Gitlab::Metrics::Dashboard::Stages::GrafanaFormatter
+ ].freeze
+
+ self.reactive_cache_key = ->(service) { service.cache_key }
+ self.reactive_cache_lease_timeout = 30.seconds
+ self.reactive_cache_refresh_interval = 30.minutes
+ self.reactive_cache_lifetime = 30.minutes
+ self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
+
+ class << self
+ # Determines whether the provided params are sufficient
+ # to uniquely identify a grafana dashboard.
+ def valid_params?(params)
+ [
+ params[:embedded],
+ params[:grafana_url]
+ ].all?
+ end
+
+ def from_cache(project_id, user_id, grafana_url)
+ project = Project.find(project_id)
+ user = User.find(user_id)
+
+ new(project, user, grafana_url: grafana_url)
+ end
+ end
+
+ def get_dashboard
+ with_reactive_cache(*cache_key) { |result| result }
+ end
+
+ # Inherits the primary logic from the parent class and
+ # maintains the service's API while including ReactiveCache
+ def calculate_reactive_cache(*)
+ ::Metrics::Dashboard::BaseService
+ .instance_method(:get_dashboard)
+ .bind(self)
+ .call() # rubocop:disable Style/MethodCallWithoutArgsParentheses
+ end
+
+ def cache_key(*args)
+ [project.id, current_user.id, grafana_url]
+ end
+
+ # Required for ReactiveCaching; Usage overridden by
+ # self.reactive_cache_worker_finder
+ def id
+ nil
+ end
+
+ private
+
+ def get_raw_dashboard
+ raise MissingIntegrationError unless client
+
+ grafana_dashboard = fetch_dashboard
+ datasource = fetch_datasource(grafana_dashboard)
+
+ params.merge!(grafana_dashboard: grafana_dashboard, datasource: datasource)
+
+ {}
+ end
+
+ def fetch_dashboard
+ uid = GrafanaUidParser.new(grafana_url, project).parse
+ raise DashboardProcessingError.new('Dashboard uid not found') unless uid
+
+ response = client.get_dashboard(uid: uid)
+
+ parse_json(response.body)
+ end
+
+ def fetch_datasource(dashboard)
+ name = DatasourceNameParser.new(grafana_url, dashboard).parse
+ raise DashboardProcessingError.new('Datasource name not found') unless name
+
+ response = client.get_datasource(name: name)
+
+ parse_json(response.body)
+ end
+
+ def grafana_url
+ params[:grafana_url]
+ end
+
+ def client
+ project.grafana_integration&.client
+ end
+
+ def allowed?
+ Ability.allowed?(current_user, :read_project, project)
+ end
+
+ def sequence
+ SEQUENCE
+ end
+
+ def parse_json(json)
+ JSON.parse(json, symbolize_names: true)
+ rescue JSON::ParserError
+ raise DashboardProcessingError.new('Grafana response contains invalid json')
+ end
+ end
+
+ # Identifies the uid of the dashboard based on url format
+ class GrafanaUidParser
+ def initialize(grafana_url, project)
+ @grafana_url, @project = grafana_url, project
+ end
+
+ def parse
+ @grafana_url.match(uid_regex) { |m| m.named_captures['uid'] }
+ end
+
+ private
+
+ # URLs are expected to look like https://domain.com/d/:uid/other/stuff
+ def uid_regex
+ base_url = @project.grafana_integration.grafana_url.chomp('/')
+
+ %r{(#{Regexp.escape(base_url)}\/d\/(?<uid>\w+)\/)}x
+ end
+ end
+
+ # Identifies the name of the datasource for a dashboard
+ # based on the panelId query parameter found in the url
+ class DatasourceNameParser
+ def initialize(grafana_url, grafana_dashboard)
+ @grafana_url, @grafana_dashboard = grafana_url, grafana_dashboard
+ end
+
+ def parse
+ @grafana_dashboard[:dashboard][:panels]
+ .find { |panel| panel[:id].to_s == query_params[:panelId] }
+ .try(:[], :datasource)
+ end
+
+ private
+
+ def query_params
+ Gitlab::Metrics::Dashboard::Url.parse_query(@grafana_url)
+ end
+ end
+ end
+end