lib/gooddata/lcm/actions/update_metric_formats.rb
# encoding: UTF-8
# frozen_string_literal: true
# Copyright (c) 2010-2021 GoodData Corporation. All rights reserved.
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
require_relative 'base_action'
module GoodData
module LCM2
class UpdateMetricFormats < BaseAction
DESCRIPTION = 'Localize Metric Formats'
PARAMS = define_params(self) do
description 'Synchronization Info'
param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
description 'Client Used for Connecting to GD'
param :gdc_gd_client, instance_of(Type::GdClientType), required: true
description 'Organization Name'
param :organization, instance_of(Type::StringType), required: false
description 'DataProduct to manage'
param :data_product, instance_of(Type::GDDataProductType), required: false
description 'Logger'
param :gdc_logger, instance_of(Type::GdLogger), required: true
description 'ADS Client'
param :ads_client, instance_of(Type::AdsClientType), required: false
description 'Input Source'
param :input_source, instance_of(Type::HashType), required: false
description 'Localization query'
param :localization_query, instance_of(Type::StringType), required: false
description 'Abort on error'
param :abort_on_error, instance_of(Type::StringType), required: false
description 'Collect synced status'
param :collect_synced_status, instance_of(Type::BooleanType), required: false
description 'Sync failed list'
param :sync_failed_list, instance_of(Type::HashType), required: false
end
RESULT_HEADER = %i[action ok_clients error_clients]
class << self
def load_metric_data(params)
collect_synced_status = collect_synced_status(params)
if params&.dig(:input_source, :metric_format) && params[:input_source][:metric_format].present?
metric_input_source = validate_input_source(params[:input_source], collect_synced_status)
return nil unless metric_input_source
else
return nil
end
metric_data_source = GoodData::Helpers::DataSource.new(metric_input_source)
begin
temp_csv = without_check(PARAMS, params) do
File.open(metric_data_source.realize(params), 'r:UTF-8')
end
rescue StandardError => e
GoodData.logger.warn("Unable to get metric input source, skip updating metric formats. Error: #{e.message} - #{e}")
return nil
end
metrics_hash = GoodData::Helpers::Csv.read_as_hash temp_csv
return nil if metrics_hash.empty?
expected_keys = %w[tag client_id format]
unless expected_keys.map(&:to_sym).all? { |s| metrics_hash.first.key? s }
GoodData.logger.warn("The input metric data is incorrect, expecting the following fields: #{expected_keys}")
return nil
end
metrics_hash
end
def validate_input_source(input_source, continue_on_error)
type = input_source[:type] if input_source&.dig(:type)
metric_format = input_source[:metric_format]
if type.blank?
raise "Incorrect configuration: 'type' of 'input_source' is required" unless continue_on_error
return nil
end
modified_input_source = input_source
case type
when 'ads', 'redshift', 'snowflake', 'bigquery', 'postgresql', 'mssql', 'mysql'
if metric_format[:query].blank?
GoodData.logger.warn("The metric input_source '#{type}' is missing property 'query'")
return nil
end
modified_input_source[:query] = metric_format[:query]
return modified_input_source
when 's3'
if metric_format[:file].blank?
GoodData.logger.warn("The metric input_source '#{type}' is missing property 'file'")
return nil
end
if modified_input_source.key?(:key)
modified_input_source[:key] = metric_format[:file]
else
modified_input_source[:file] = metric_format[:file]
end
return modified_input_source
when 'blobStorage'
if metric_format[:file].blank?
GoodData.logger.warn("The metric input_source '#{type}' is missing property 'file'")
return nil
end
modified_input_source[:file] = metric_format[:file]
return modified_input_source
when 'staging'
if metric_format[:file].blank?
GoodData.logger.warn("The metric input_source '#{type}' is missing property 'file'")
return nil
end
modified_input_source[:path] = metric_format[:file]
return modified_input_source
when 'web'
if metric_format[:url].blank?
GoodData.logger.warn("The metric input_source '#{type}' is missing property 'url'")
return nil
end
modified_input_source[:url] = metric_format[:url]
return modified_input_source
else
return nil
end
end
def get_clients_metrics(metric_data)
return {} if metric_data.nil?
metric_groups = {}
clients = metric_data.map { |row| row[:client_id] }.uniq
clients.each do |client|
next if client.blank?
formats = {}
metric_data.select { |row| row[:client_id] == client && row[:tag].present? && row[:format].present? }.each { |row| formats[row[:tag]] = row[:format] }
metric_groups[client.to_s] ||= formats
end
metric_groups
end
def call(params)
data = load_metric_data(params)
result = []
return result if data.nil?
metric_group = get_clients_metrics(data)
return result if metric_group.empty?
GoodData.logger.debug("Clients have metrics which will be modified: #{metric_group.keys}")
updated_clients = params.synchronize.map { |segment| segment.to.map { |client| client[:client_id] } }.flatten.uniq
GoodData.logger.debug("Updating clients: #{updated_clients}")
data_product = params.data_product
data_product_clients = data_product.clients
number_client_ok = 0
number_client_error = 0
collect_synced_status = collect_synced_status(params)
metric_group.each do |client_id, formats|
next if !updated_clients.include?(client_id) || (collect_synced_status && sync_failed_client(client_id, params))
client = data_product_clients.find { |c| c.id == client_id }
begin
GoodData.logger.info("Start updating metric format for client: '#{client_id}'")
metrics = client.project.metrics.to_a
formats.each do |tag, format|
next if tag.blank? || format.blank?
metrics_to_be_updated = metrics.select { |metric| metric.tags.include?(tag) }
metrics_to_be_updated.each do |metric|
metric.format = format
metric.save
end
end
number_client_ok += 1
GoodData.logger.info("Finished updating metric format for client: '#{client_id}'")
rescue StandardError => e
number_client_error += 1
GoodData.logger.warn("Failed to update metric format for client: '#{client_id}'. Error: #{e.message} - #{e}")
end
end
[{ :action => 'Update metric format', :ok_clients => number_client_ok, :error_clients => number_client_error }]
end
end
end
end
end