diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-03 00:08:11 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-03 00:08:11 +0000 |
commit | bd8fb5668ae739a83d55ec5ca4a04344eef2167e (patch) | |
tree | baf085c6cd58b3b5e5a192d4d3db360d623bb056 /lib | |
parent | 561e1b470f0a99fe6304c8f197348c47a637d594 (diff) | |
download | gitlab-ce-bd8fb5668ae739a83d55ec5ca4a04344eef2167e.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
-rw-r--r-- | lib/banzai/filter/inline_grafana_metrics_filter.rb | 33 | ||||
-rw-r--r-- | lib/gitlab/import_export/project/tree_restorer.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/import_export/project/tree_saver.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/import_export/relation_rename_service.rb | 48 | ||||
-rw-r--r-- | lib/grafana/time_window.rb | 130 |
5 files changed, 151 insertions, 64 deletions
diff --git a/lib/banzai/filter/inline_grafana_metrics_filter.rb b/lib/banzai/filter/inline_grafana_metrics_filter.rb index 69ae747333f..60a16b164af 100644 --- a/lib/banzai/filter/inline_grafana_metrics_filter.rb +++ b/lib/banzai/filter/inline_grafana_metrics_filter.rb @@ -13,13 +13,16 @@ module Banzai super end + # @return [Hash<Symbol, String>] with keys :grafana_url, :start, and :end def embed_params(node) query_params = Gitlab::Metrics::Dashboard::Url.parse_query(node['href']) - return unless [:panelId, :from, :to].all? do |param| - query_params.include?(param) - end - { url: node['href'], start: query_params[:from], end: query_params[:to] } + return unless query_params.include?(:panelId) + + time_window = Grafana::TimeWindow.new(query_params[:from], query_params[:to]) + url = url_with_window(node['href'], query_params, time_window.in_milliseconds) + + { grafana_url: url }.merge(time_window.formatted) end # Selects any links with an href contains the configured @@ -44,18 +47,24 @@ module Banzai Gitlab::Routing.url_helpers.project_grafana_api_metrics_dashboard_url( project, embedded: true, - grafana_url: params[:url], - start: format_time(params[:start]), - end: format_time(params[:end]) + **params ) end - # Formats a timestamp from Grafana for compatibility with - # parsing in JS via `new Date(timestamp)` + # If the provided url is missing time window parameters, + # this inserts the default window into the url, allowing + # the embed service to correctly format prometheus + # queries during embed processing. # - # @param time [String] Represents miliseconds since epoch - def format_time(time) - Time.at(time.to_i / 1000).utc.strftime('%FT%TZ') + # @param url [String] + # @param query_params [Hash<Symbol, String>] + # @param time_window_params [Hash<Symbol, Integer>] + # @return [String] + def url_with_window(url, query_params, time_window_params) + uri = URI(url) + uri.query = time_window_params.merge(query_params).to_query + + uri.to_s end # Fetches a dashboard and caches the result for the diff --git a/lib/gitlab/import_export/project/tree_restorer.rb b/lib/gitlab/import_export/project/tree_restorer.rb index a5123f16dbc..904cb461ac3 100644 --- a/lib/gitlab/import_export/project/tree_restorer.rb +++ b/lib/gitlab/import_export/project/tree_restorer.rb @@ -21,8 +21,6 @@ module Gitlab @tree_hash = read_tree_hash @project_members = @tree_hash.delete('project_members') - RelationRenameService.rename(@tree_hash) - if relation_tree_restorer.restore import_failure_service.with_retry(action: 'set_latest_merge_request_diff_ids!') do @project.merge_requests.set_latest_merge_request_diff_ids! diff --git a/lib/gitlab/import_export/project/tree_saver.rb b/lib/gitlab/import_export/project/tree_saver.rb index 58f33a04851..32b3b518ece 100644 --- a/lib/gitlab/import_export/project/tree_saver.rb +++ b/lib/gitlab/import_export/project/tree_saver.rb @@ -35,8 +35,6 @@ module Gitlab end project_tree['project_members'] += group_members_array - - RelationRenameService.add_new_associations(project_tree) end def reader diff --git a/lib/gitlab/import_export/relation_rename_service.rb b/lib/gitlab/import_export/relation_rename_service.rb deleted file mode 100644 index 03aaa6aefc3..00000000000 --- a/lib/gitlab/import_export/relation_rename_service.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -# This class is intended to help with relation renames within Gitlab versions -# and allow compatibility between versions. -# If you have to change one relationship name that is imported/exported, -# you should add it to the RENAMES constant indicating the old name and the -# new one. -# The behavior of these renamed relationships should be transient and it should -# only last one release until you completely remove the renaming from the list. -# -# When importing, this class will check the hash and: -# - if only the old relationship name is found, it will rename it with the new one -# - if only the new relationship name is found, it will do nothing -# - if it finds both, it will use the new relationship data -# -# When exporting, this class will duplicate the keys in the resulting file. -# This way, if we open the file in an old version of the exporter it will work -# and also it will with the newer versions. -module Gitlab - module ImportExport - class RelationRenameService - RENAMES = { - 'pipelines' => 'ci_pipelines' # Added in 11.6, remove in 11.7 - }.freeze - - def self.rename(tree_hash) - return unless tree_hash&.present? - - RENAMES.each do |old_name, new_name| - old_entry = tree_hash.delete(old_name) - - next if tree_hash[new_name] - next unless old_entry - - tree_hash[new_name] = old_entry - end - end - - def self.add_new_associations(tree_hash) - RENAMES.each do |old_name, new_name| - next if tree_hash.key?(old_name) - - tree_hash[old_name] = tree_hash[new_name] - end - end - end - end -end diff --git a/lib/grafana/time_window.rb b/lib/grafana/time_window.rb new file mode 100644 index 00000000000..111e3ab7de2 --- /dev/null +++ b/lib/grafana/time_window.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +module Grafana + # Allows for easy formatting and manipulations of timestamps + # coming from a Grafana url + class TimeWindow + include ::Gitlab::Utils::StrongMemoize + + def initialize(from, to) + @from = from + @to = to + end + + def formatted + { + start: window[:from].formatted, + end: window[:to].formatted + } + end + + def in_milliseconds + window.transform_values(&:to_ms) + end + + private + + def window + strong_memoize(:window) do + specified_window + rescue Timestamp::Error + default_window + end + end + + def specified_window + RangeWithDefaults.new( + from: Timestamp.from_ms_since_epoch(@from), + to: Timestamp.from_ms_since_epoch(@to) + ).to_hash + end + + def default_window + RangeWithDefaults.new.to_hash + end + end + + # For incomplete time ranges, adds default parameters to + # achieve a complete range. If both full range is provided, + # range will be returned. + class RangeWithDefaults + DEFAULT_RANGE = 8.hours + + # @param from [Grafana::Timestamp, nil] Start of the expected range + # @param to [Grafana::Timestamp, nil] End of the expected range + def initialize(from: nil, to: nil) + @from = from + @to = to + + apply_defaults! + end + + def to_hash + { from: @from, to: @to }.compact + end + + private + + def apply_defaults! + @to ||= @from ? relative_end : Timestamp.new(Time.now) + @from ||= relative_start + end + + def relative_start + Timestamp.new(DEFAULT_RANGE.before(@to.time)) + end + + def relative_end + Timestamp.new(DEFAULT_RANGE.since(@from.time)) + end + end + + # Offers a consistent API for timestamps originating from + # Grafana or other sources, allowing for formatting of timestamps + # as consumed by Grafana-related utilities + class Timestamp + Error = Class.new(StandardError) + + attr_accessor :time + + # @param timestamp [Time] + def initialize(time) + @time = time + end + + # Formats a timestamp from Grafana for compatibility with + # parsing in JS via `new Date(timestamp)` + def formatted + time.utc.strftime('%FT%TZ') + end + + # Converts to milliseconds since epoch + def to_ms + time.to_i * 1000 + end + + class << self + # @param time [String] Representing milliseconds since epoch. + # This is what JS "decided" unix is. + def from_ms_since_epoch(time) + return if time.nil? + + raise Error.new('Expected milliseconds since epoch') unless ms_since_epoch?(time) + + new(cast_ms_to_time(time)) + end + + private + + def cast_ms_to_time(time) + Time.at(time.to_i / 1000.0) + end + + def ms_since_epoch?(time) + ms = time.to_i + + ms.to_s == time && ms.bit_length < 64 + end + end + end +end |