gooddata 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gdc-ii-config.yaml +42 -1
- data/.github/workflows/build.yml +14 -13
- data/.github/workflows/pre-merge.yml +13 -13
- data/.pronto.yml +1 -0
- data/.rubocop.yml +2 -14
- data/CHANGELOG.md +9 -0
- data/Dockerfile +13 -7
- data/Dockerfile.jruby +5 -5
- data/Dockerfile.ruby +5 -7
- data/Gemfile +4 -2
- data/README.md +5 -4
- data/Rakefile +1 -1
- data/SDK_VERSION +1 -1
- data/VERSION +1 -1
- data/bin/run_brick.rb +7 -0
- data/ci/mysql/pom.xml +6 -1
- data/ci/redshift/pom.xml +3 -4
- data/docker-compose.lcm.yml +42 -1
- data/docker-compose.yml +42 -0
- data/gooddata.gemspec +21 -22
- data/lcm.rake +9 -0
- data/lib/gooddata/bricks/base_pipeline.rb +26 -0
- data/lib/gooddata/bricks/brick.rb +0 -1
- data/lib/gooddata/bricks/middleware/execution_result_middleware.rb +3 -3
- data/lib/gooddata/bricks/pipeline.rb +2 -14
- data/lib/gooddata/cloud_resources/mysql/mysql_client.rb +18 -8
- data/lib/gooddata/cloud_resources/redshift/drivers/.gitkeepme +0 -0
- data/lib/gooddata/cloud_resources/redshift/redshift_client.rb +0 -2
- data/lib/gooddata/cloud_resources/snowflake/snowflake_client.rb +1 -1
- data/lib/gooddata/lcm/actions/base_action.rb +157 -0
- data/lib/gooddata/lcm/actions/collect_data_product.rb +2 -1
- data/lib/gooddata/lcm/actions/collect_projects_warning_status.rb +53 -0
- data/lib/gooddata/lcm/actions/collect_segment_clients.rb +14 -0
- data/lib/gooddata/lcm/actions/initialize_continue_on_error_option.rb +87 -0
- data/lib/gooddata/lcm/actions/migrate_gdc_date_dimension.rb +28 -2
- data/lib/gooddata/lcm/actions/provision_clients.rb +34 -5
- data/lib/gooddata/lcm/actions/synchronize_cas.rb +24 -4
- data/lib/gooddata/lcm/actions/synchronize_clients.rb +56 -4
- data/lib/gooddata/lcm/actions/synchronize_dataset_mappings.rb +28 -3
- data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +48 -11
- data/lib/gooddata/lcm/actions/synchronize_kd_dashboard_permission.rb +103 -0
- data/lib/gooddata/lcm/actions/synchronize_ldm.rb +60 -15
- data/lib/gooddata/lcm/actions/synchronize_ldm_layout.rb +98 -0
- data/lib/gooddata/lcm/actions/synchronize_pp_dashboard_permission.rb +108 -0
- data/lib/gooddata/lcm/actions/synchronize_schedules.rb +31 -1
- data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +14 -9
- data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +30 -4
- data/lib/gooddata/lcm/actions/synchronize_users.rb +11 -10
- data/lib/gooddata/lcm/actions/update_metric_formats.rb +21 -4
- data/lib/gooddata/lcm/exceptions/lcm_execution_warning.rb +15 -0
- data/lib/gooddata/lcm/helpers/check_helper.rb +19 -0
- data/lib/gooddata/lcm/lcm2.rb +45 -4
- data/lib/gooddata/lcm/user_bricks_helper.rb +9 -0
- data/lib/gooddata/mixins/inspector.rb +1 -1
- data/lib/gooddata/models/ldm_layout.rb +38 -0
- data/lib/gooddata/models/project.rb +197 -22
- data/lib/gooddata/models/project_creator.rb +83 -6
- data/lib/gooddata/models/segment.rb +2 -1
- data/lib/gooddata/models/user_filters/user_filter_builder.rb +104 -15
- data/lib/gooddata/rest/connection.rb +5 -3
- data/lib/gooddata/rest/phmap.rb +1 -0
- data/lib/gooddata.rb +1 -0
- data/lib/gooddata_brick_base.rb +35 -0
- data/sonar-project.properties +6 -0
- metadata +64 -59
- data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +0 -15
@@ -39,6 +39,9 @@ module GoodData
|
|
39
39
|
opts = { client: GoodData.connection }.merge(opts)
|
40
40
|
dry_run = opts[:dry_run]
|
41
41
|
replacements = opts['maql_replacements'] || opts[:maql_replacements] || {}
|
42
|
+
update_preference = opts[:update_preference]
|
43
|
+
exist_fallback_to_hard_sync_config = !update_preference.nil? && !update_preference[:fallback_to_hard_sync].nil?
|
44
|
+
include_maql_fallback_hard_sync = exist_fallback_to_hard_sync_config && GoodData::Helpers.to_boolean(update_preference[:fallback_to_hard_sync])
|
42
45
|
|
43
46
|
_, project = GoodData.get_client_and_project(opts)
|
44
47
|
|
@@ -48,6 +51,7 @@ module GoodData
|
|
48
51
|
maql_diff_params = [:includeGrain]
|
49
52
|
maql_diff_params << :excludeFactRule if opts[:exclude_fact_rule]
|
50
53
|
maql_diff_params << :includeDeprecated if opts[:include_deprecated]
|
54
|
+
maql_diff_params << :includeMaqlFallbackHardSync if include_maql_fallback_hard_sync
|
51
55
|
|
52
56
|
maql_diff_time = Benchmark.realtime do
|
53
57
|
response = project.maql_diff(blueprint: bp, params: maql_diff_params)
|
@@ -62,7 +66,7 @@ module GoodData
|
|
62
66
|
ca_maql = response['projectModelDiff']['computedAttributesScript'] if response['projectModelDiff']['computedAttributesScript']
|
63
67
|
ca_chunks = ca_maql && ca_maql['maqlDdlChunks']
|
64
68
|
|
65
|
-
maqls = pick_correct_chunks(chunks, opts)
|
69
|
+
maqls = include_maql_fallback_hard_sync ? pick_correct_chunks_hard_sync(chunks, opts) : pick_correct_chunks(chunks, opts)
|
66
70
|
replaced_maqls = apply_replacements_on_maql(maqls, replacements)
|
67
71
|
apply_maqls(ca_chunks, project, replaced_maqls, opts) unless dry_run
|
68
72
|
[replaced_maqls, ca_maql]
|
@@ -72,9 +76,11 @@ module GoodData
|
|
72
76
|
errors = []
|
73
77
|
replaced_maqls.each do |replaced_maql_chunks|
|
74
78
|
begin
|
79
|
+
fallback_hard_sync = replaced_maql_chunks['updateScript']['fallbackHardSync'].nil? ? false : replaced_maql_chunks['updateScript']['fallbackHardSync']
|
75
80
|
replaced_maql_chunks['updateScript']['maqlDdlChunks'].each do |chunk|
|
76
81
|
GoodData.logger.debug(chunk)
|
77
|
-
project.execute_maql(chunk)
|
82
|
+
execute_maql_result = project.execute_maql(chunk)
|
83
|
+
process_fallback_hard_sync_result(execute_maql_result, project) if fallback_hard_sync
|
78
84
|
end
|
79
85
|
rescue => e
|
80
86
|
GoodData.logger.error("Error occured when executing MAQL, project: \"#{project.title}\" reason: \"#{e.message}\", chunks: #{replaced_maql_chunks.inspect}")
|
@@ -140,8 +146,8 @@ module GoodData
|
|
140
146
|
preference = Hash[preference.map { |k, v| [k, GoodData::Helpers.to_boolean(v)] }]
|
141
147
|
|
142
148
|
# will use new parameters instead of the old ones
|
143
|
-
if preference.empty? || [
|
144
|
-
if [
|
149
|
+
if preference.empty? || %i[allow_cascade_drops keep_data].any? { |k| preference.key?(k) }
|
150
|
+
if %i[cascade_drops preserve_data].any? { |k| preference.key?(k) }
|
145
151
|
fail "Please do not mix old parameters (:cascade_drops, :preserve_data) with the new ones (:allow_cascade_drops, :keep_data)."
|
146
152
|
end
|
147
153
|
preference = { allow_cascade_drops: false, keep_data: true }.merge(preference)
|
@@ -174,8 +180,8 @@ module GoodData
|
|
174
180
|
results_from_api = GoodData::Helpers.join(
|
175
181
|
rules,
|
176
182
|
stuff,
|
177
|
-
[
|
178
|
-
[
|
183
|
+
%i[cascade_drops preserve_data],
|
184
|
+
%i[cascade_drops preserve_data],
|
179
185
|
inner: true
|
180
186
|
).sort_by { |l| l[:priority] } || []
|
181
187
|
|
@@ -204,6 +210,53 @@ module GoodData
|
|
204
210
|
end
|
205
211
|
end
|
206
212
|
|
213
|
+
def pick_correct_chunks_hard_sync(chunks, opts = {})
|
214
|
+
preference = GoodData::Helpers.symbolize_keys(opts[:update_preference] || {})
|
215
|
+
preference = Hash[preference.map { |k, v| [k, GoodData::Helpers.to_boolean(v)] }]
|
216
|
+
|
217
|
+
# Old configure using cascade_drops and preserve_data parameters. New configure using allow_cascade_drops and
|
218
|
+
# keep_data parameters. Need translate from new configure to old configure before processing
|
219
|
+
if preference.empty? || %i[allow_cascade_drops keep_data].any? { |k| preference.key?(k) }
|
220
|
+
if %i[cascade_drops preserve_data].any? { |k| preference.key?(k) }
|
221
|
+
fail "Please do not mix old parameters (:cascade_drops, :preserve_data) with the new ones (:allow_cascade_drops, :keep_data)."
|
222
|
+
end
|
223
|
+
|
224
|
+
# Default allow_cascade_drops=false and keep_data=true
|
225
|
+
preference = { allow_cascade_drops: false, keep_data: true }.merge(preference)
|
226
|
+
|
227
|
+
new_preference = {}
|
228
|
+
new_preference[:cascade_drops] = preference[:allow_cascade_drops]
|
229
|
+
new_preference[:preserve_data] = preference[:keep_data]
|
230
|
+
preference = new_preference
|
231
|
+
end
|
232
|
+
preference[:fallback_to_hard_sync] = true
|
233
|
+
|
234
|
+
# Filter chunk with fallbackHardSync = true
|
235
|
+
result = chunks.select do |chunk|
|
236
|
+
chunk['updateScript']['maqlDdlChunks'] && !chunk['updateScript']['fallbackHardSync'].nil? && chunk['updateScript']['fallbackHardSync']
|
237
|
+
end
|
238
|
+
|
239
|
+
# The API model/diff only returns one result for MAQL fallback hard synchronize
|
240
|
+
result = pick_chunks_hard_sync(result[0], preference) if !result.nil? && !result.empty?
|
241
|
+
|
242
|
+
if result.nil? || result.empty?
|
243
|
+
available_chunks = chunks
|
244
|
+
.map do |chunk|
|
245
|
+
{
|
246
|
+
cascade_drops: chunk['updateScript']['cascadeDrops'],
|
247
|
+
preserve_data: chunk['updateScript']['preserveData'],
|
248
|
+
fallback_hard_sync: chunk['updateScript']['fallbackHardSync'].nil? ? false : chunk['updateScript']['fallbackHardSync']
|
249
|
+
}
|
250
|
+
end
|
251
|
+
.map(&:to_s)
|
252
|
+
.join(', ')
|
253
|
+
|
254
|
+
fail "Synchronize LDM cannot proceed. Adjust your update_preferences and try again. Available chunks with preference: #{available_chunks}"
|
255
|
+
end
|
256
|
+
|
257
|
+
result
|
258
|
+
end
|
259
|
+
|
207
260
|
private
|
208
261
|
|
209
262
|
def apply_replacements_on_maql(maqls, replacements = {})
|
@@ -215,6 +268,30 @@ module GoodData
|
|
215
268
|
end
|
216
269
|
end
|
217
270
|
end
|
271
|
+
|
272
|
+
# Fallback hard synchronize although execute result success but some cases there are errors during executing.
|
273
|
+
# In this cases, then export the errors to execution log as warning
|
274
|
+
def process_fallback_hard_sync_result(result, project)
|
275
|
+
messages = result['wTaskStatus']['messages']
|
276
|
+
if !messages.nil? && messages.size.positive?
|
277
|
+
warning_message = GoodData::Helpers.interpolate_error_messages(messages)
|
278
|
+
log_message = "Project #{project.pid} failed to preserve data, truncated data of some datasets. MAQL diff execution messages: \"#{warning_message}\""
|
279
|
+
GoodData.logger.warn(log_message)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# In case fallback hard synchronize, then the API model/diff only returns one result with preserve_data is always false and
|
284
|
+
# cascade_drops is true or false. So pick chunk for fallback hard synchronize, we will ignore the preserve_data parameter
|
285
|
+
# and only check the cascade_drops parameter in preference.
|
286
|
+
def pick_chunks_hard_sync(chunk, preference)
|
287
|
+
# Make sure default values for cascade_drops
|
288
|
+
working_preference = { cascade_drops: false }.merge(preference)
|
289
|
+
if working_preference[:cascade_drops] || chunk['updateScript']['cascadeDrops'] == working_preference[:cascade_drops]
|
290
|
+
[chunk]
|
291
|
+
else
|
292
|
+
[]
|
293
|
+
end
|
294
|
+
end
|
218
295
|
end
|
219
296
|
end
|
220
297
|
end
|
@@ -257,7 +257,8 @@ module GoodData
|
|
257
257
|
res = client.poll_on_code(res['asyncTask']['links']['poll'])
|
258
258
|
failed_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult failed count), 0)
|
259
259
|
created_count = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult created count), 0)
|
260
|
-
return
|
260
|
+
return [].to_enum if (failed_count + created_count).zero?
|
261
|
+
|
261
262
|
Enumerator.new do |y|
|
262
263
|
uri = GoodData::Helpers.get_path(res, %w(clientProjectProvisioningResult links details))
|
263
264
|
loop do
|
@@ -19,6 +19,9 @@ using NilExtensions
|
|
19
19
|
|
20
20
|
module GoodData
|
21
21
|
module UserFilterBuilder
|
22
|
+
@all_domain_users = {}
|
23
|
+
@mutex = Mutex.new
|
24
|
+
|
22
25
|
# Main Entry function. Gets values and processes them to get filters
|
23
26
|
# that are suitable for other function to process.
|
24
27
|
# Values can be read from file or provided inline as an array.
|
@@ -48,11 +51,26 @@ module GoodData
|
|
48
51
|
end
|
49
52
|
|
50
53
|
def self.read_file(file, options = {})
|
51
|
-
memo =
|
52
|
-
|
54
|
+
memo = Hash[]
|
55
|
+
if row_based?(options)
|
56
|
+
read_data_without_header(file, memo, options)
|
57
|
+
else
|
58
|
+
read_data_with_header(file, memo, options)
|
59
|
+
end
|
60
|
+
memo
|
61
|
+
end
|
53
62
|
|
54
|
-
|
55
|
-
|
63
|
+
def self.read_data_without_header(file, memo, options)
|
64
|
+
CSV.foreach(file, headers: false, return_headers: false) do |row|
|
65
|
+
key, data = process_line(row, options)
|
66
|
+
memo[key] = [] unless memo.key?(key)
|
67
|
+
memo[key].concat(data)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.read_data_with_header(file, memo, options)
|
72
|
+
CSV.foreach(file, headers: true, return_headers: false) do |row|
|
73
|
+
key, data = process_line(row, options)
|
56
74
|
memo[key] = [] unless memo.key?(key)
|
57
75
|
memo[key].concat(data)
|
58
76
|
end
|
@@ -210,13 +228,23 @@ module GoodData
|
|
210
228
|
# Takes the filter definition looks up any necessary values and provides API executable MAQL
|
211
229
|
# @param labels_cache e.g. { 'label_uri': label_object }
|
212
230
|
# @param lookups_cache e.g. { 'label_uri': { "jirka@gooddata.com": 'value_uri' }}
|
213
|
-
|
231
|
+
# rubocop:disable Metrics/ParameterLists
|
232
|
+
def self.create_expression(filter, labels_cache, lookups_cache, attr_cache, options = {}, login)
|
214
233
|
values = filter[:values]
|
215
234
|
# Do not create MUF for label when all its values is NULL (https://jira.intgdc.com/browse/TMA-1361)
|
216
235
|
non_null_values = values.select { |value| !value.nil? && value.downcase != 'null' }
|
217
236
|
return ['TRUE', []] if non_null_values.empty?
|
218
237
|
|
219
238
|
label = labels_cache[filter[:label]]
|
239
|
+
if label.nil?
|
240
|
+
err_message = "Unable to apply filter values: #{values} since the project: #{options[:project].pid} doesn't have label: #{filter[:label]} for login: #{login}"
|
241
|
+
if options[:ignore_missing_values]
|
242
|
+
GoodData.logger.warn(err_message)
|
243
|
+
return ['TRUE', []]
|
244
|
+
else
|
245
|
+
fail err_message
|
246
|
+
end
|
247
|
+
end
|
220
248
|
errors = []
|
221
249
|
|
222
250
|
element_uris_by_values = Hash[values.map do |v|
|
@@ -262,6 +290,7 @@ module GoodData
|
|
262
290
|
end
|
263
291
|
[expression, errors]
|
264
292
|
end
|
293
|
+
# rubocop:enable Metrics/ParameterLists
|
265
294
|
|
266
295
|
# Encapuslates the creation of filter
|
267
296
|
def self.create_user_filter(expression, related)
|
@@ -273,6 +302,66 @@ module GoodData
|
|
273
302
|
}
|
274
303
|
end
|
275
304
|
|
305
|
+
def self.create_user_profile_mapping(filters, project_users, options = {})
|
306
|
+
domain = options[:domain]
|
307
|
+
found_list = {}
|
308
|
+
missing_list = []
|
309
|
+
|
310
|
+
# Get the list of user login from filters
|
311
|
+
login_list = filters.flat_map do |filter|
|
312
|
+
filter[:login]
|
313
|
+
end
|
314
|
+
|
315
|
+
# Then find user login in the users_brick_input
|
316
|
+
users_brick_input = options[:users_brick_input]
|
317
|
+
if users_brick_input&.any?
|
318
|
+
users_brick_input.map do |user|
|
319
|
+
login_list << user.with_indifferent_access['login']
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
login_list.uniq.flat_map do |login|
|
324
|
+
user = project_users.find { |u| u.login == login }
|
325
|
+
if user
|
326
|
+
found_list[login] = user.profile_url
|
327
|
+
else
|
328
|
+
missing_list << login
|
329
|
+
end
|
330
|
+
end
|
331
|
+
# rubocop:disable Metrics/BlockNesting
|
332
|
+
unless missing_list.empty? || domain.nil?
|
333
|
+
if missing_list.size < 100
|
334
|
+
missing_list.each do |login|
|
335
|
+
user = domain.find_user_by_login(login)
|
336
|
+
found_list[login] = user.links['self'] if user
|
337
|
+
end
|
338
|
+
else
|
339
|
+
if @all_domain_users[domain.name].nil?
|
340
|
+
@mutex.lock
|
341
|
+
if @all_domain_users[domain.name].nil?
|
342
|
+
domain_users = domain.users
|
343
|
+
@all_domain_users[domain.name] = domain_users
|
344
|
+
GoodData.logger.info("action=lcm_get_domain_users domain=#{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=false")
|
345
|
+
else
|
346
|
+
domain_users = @all_domain_users[domain.name]
|
347
|
+
GoodData.logger.info("action=lcm_get_domain_users domain=##{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=true")
|
348
|
+
end
|
349
|
+
@mutex.unlock
|
350
|
+
else
|
351
|
+
domain_users = @all_domain_users[domain.name]
|
352
|
+
GoodData.logger.info("action=lcm_get_domain_users domain=##{domain.name} number_users=#{domain_users.size} number_missing_users=#{missing_list.size} use_cache=true")
|
353
|
+
end
|
354
|
+
|
355
|
+
missing_list.each do |login|
|
356
|
+
user = domain_users.find { |u| u.login == login }
|
357
|
+
found_list[login] = user.links['self'] if user
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
# rubocop:enable Metrics/BlockNesting
|
362
|
+
found_list
|
363
|
+
end
|
364
|
+
|
276
365
|
# Resolves and creates maql statements from filter definitions.
|
277
366
|
# This method does not perform any modifications on API but
|
278
367
|
# collects all the information that is needed to do so.
|
@@ -283,7 +372,7 @@ module GoodData
|
|
283
372
|
#
|
284
373
|
# @param filters [Array<Hash>] Filters definition
|
285
374
|
# @return [Array] first is list of MAQL statements
|
286
|
-
def self.maqlify_filters(filters,
|
375
|
+
def self.maqlify_filters(filters, user_profile_mapping, options = {})
|
287
376
|
fail_early = options[:fail_early] == false ? false : true
|
288
377
|
users_cache = options[:users_cache]
|
289
378
|
labels_cache = create_label_cache(filters, options)
|
@@ -291,11 +380,10 @@ module GoodData
|
|
291
380
|
lookups_cache = create_lookups_cache(small_labels)
|
292
381
|
attrs_cache = create_attrs_cache(filters, options)
|
293
382
|
create_filter_proc = proc do |login, f|
|
294
|
-
expression, errors = create_expression(f, labels_cache, lookups_cache, attrs_cache, options)
|
383
|
+
expression, errors = create_expression(f, labels_cache, lookups_cache, attrs_cache, options, login)
|
295
384
|
safe_login = login.downcase
|
296
385
|
profiles_uri = if options[:type] == :muf
|
297
|
-
|
298
|
-
project_user.nil? ? ('/gdc/account/profile/' + safe_login) : project_user.profile_url
|
386
|
+
user_profile_mapping[safe_login].nil? ? ('/gdc/account/profile/' + safe_login) : user_profile_mapping[safe_login]
|
299
387
|
elsif options[:type] == :variable
|
300
388
|
(users_cache[login] && users_cache[login].uri)
|
301
389
|
else
|
@@ -393,7 +481,8 @@ module GoodData
|
|
393
481
|
|
394
482
|
project_users = project.users
|
395
483
|
filters = normalize_filters(user_filters)
|
396
|
-
|
484
|
+
user_profile_mapping = create_user_profile_mapping(filters, project_users, options)
|
485
|
+
user_filters, errors = maqlify_filters(filters, user_profile_mapping, options.merge(users_must_exist: users_must_exist, type: :muf))
|
397
486
|
if !ignore_missing_values && !errors.empty?
|
398
487
|
errors = errors.map do |e|
|
399
488
|
e.merge(pid: project.pid)
|
@@ -404,7 +493,7 @@ module GoodData
|
|
404
493
|
filters = user_filters.map { |data| client.create(MandatoryUserFilter, data, project: project) }
|
405
494
|
to_create, to_delete = resolve_user_filters(filters, project.data_permissions)
|
406
495
|
|
407
|
-
to_delete = sanitize_filters_to_delete(to_delete, options[:users_brick_input],
|
496
|
+
to_delete = sanitize_filters_to_delete(to_delete, options[:users_brick_input], user_profile_mapping) unless options[:no_sanitize]
|
408
497
|
|
409
498
|
if options[:do_not_touch_filters_that_are_not_mentioned]
|
410
499
|
GoodData.logger.warn("Data permissions computed: #{to_create.count} to create")
|
@@ -499,7 +588,7 @@ module GoodData
|
|
499
588
|
# @param file [String | Array] File or array of values to be parsed for filters
|
500
589
|
# @param options [Hash] Filter definitions
|
501
590
|
# @return [Array<Hash>]
|
502
|
-
def self.get_values(file, options)
|
591
|
+
def self.get_values(file, options = {})
|
503
592
|
file.is_a?(Array) ? read_array(file, options) : read_file(file, options)
|
504
593
|
end
|
505
594
|
|
@@ -584,12 +673,12 @@ module GoodData
|
|
584
673
|
# Removes MUFs from to_delete unless in user is in users_brick_input
|
585
674
|
# if this does not happen, users that are about to be deleted by users_brick
|
586
675
|
# would have all their filters removed now, which is not desirable
|
587
|
-
def self.sanitize_filters_to_delete(to_delete, users_brick_input,
|
676
|
+
def self.sanitize_filters_to_delete(to_delete, users_brick_input, user_profile_mapping)
|
588
677
|
return [] unless users_brick_input && users_brick_input.any?
|
589
678
|
user_profiles = users_brick_input.map do |user|
|
590
|
-
result =
|
679
|
+
result = user_profile_mapping[user.with_indifferent_access['login']]
|
591
680
|
next unless result
|
592
|
-
result
|
681
|
+
result
|
593
682
|
end.compact
|
594
683
|
return [] unless user_profiles.any?
|
595
684
|
to_delete.reject do |_, value|
|
@@ -68,6 +68,8 @@ module GoodData
|
|
68
68
|
RETRY_TIME_COEFFICIENT = 1.5
|
69
69
|
RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
|
70
70
|
|
71
|
+
RETRYABLE_ERRORS << OpenSSL::SSL::SSLErrorWaitReadable if OpenSSL::SSL.const_defined?(:SSLErrorWaitReadable)
|
72
|
+
|
71
73
|
class << self
|
72
74
|
def construct_login_payload(username, password)
|
73
75
|
res = {
|
@@ -304,12 +306,12 @@ module GoodData
|
|
304
306
|
end
|
305
307
|
|
306
308
|
def refresh_token(_options = {})
|
307
|
-
begin # rubocop:disable RedundantBegin
|
309
|
+
begin # rubocop:disable Style/RedundantBegin
|
308
310
|
# avoid infinite loop GET fails with 401
|
309
311
|
response = get(TOKEN_PATH, :x_gdc_authsst => sst_token, :dont_reauth => true)
|
310
312
|
# Remove when TT sent in headers. Currently we need to parse from body
|
311
313
|
merge_headers!(:x_gdc_authtt => GoodData::Helpers.get_path(response, %w(userToken token)))
|
312
|
-
rescue Exception => e # rubocop:disable RescueException
|
314
|
+
rescue Exception => e # rubocop:disable Style/RescueException
|
313
315
|
raise e
|
314
316
|
end
|
315
317
|
end
|
@@ -688,7 +690,7 @@ ERR
|
|
688
690
|
execution_id = request_id
|
689
691
|
|
690
692
|
GoodData.gd_logger.update_store(domain, method, duration, endpoint)
|
691
|
-
GoodData.gd_logger.add Logger::
|
693
|
+
GoodData.gd_logger.add Logger::DEBUG, { endpoint: endpoint, duration: duration, domain: domain,
|
692
694
|
execution_id: execution_id, time_stamp: time_stamp }, "rest_call"
|
693
695
|
end
|
694
696
|
end
|
data/lib/gooddata/rest/phmap.rb
CHANGED
@@ -83,6 +83,7 @@ module GoodData
|
|
83
83
|
['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[^\/]+/objects/setPermissions}],
|
84
84
|
['/gdc/internal/projects/{id}/roles', %r{/gdc/internal/projects/[^\/]+/roles}],
|
85
85
|
['/gdc/dataload/projects/{id}/modelMapping/datasets/bulk/upsert', %r{/gdc/dataload/projects/[^\/]+/modelMapping/datasets/bulk/upsert}],
|
86
|
+
['/gdc/dataload/internal/projects/{id}/ldmLayout', %r{/gdc/dataload/internal/projects/[^\/]+/ldmLayout}],
|
86
87
|
['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[^\/]+/variables/item/[\d]+}],
|
87
88
|
['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[^\/]+/validate/task/[^\/]+}],
|
88
89
|
['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[^\/]+/using2/[\d]+/[\d]+}],
|
data/lib/gooddata.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010-2022 GoodData Corporation. All rights reserved.
|
5
|
+
# This source code is licensed under the BSD-style license found in the
|
6
|
+
# LICENSE file in the root directory of this source tree.
|
7
|
+
|
8
|
+
require 'pmap'
|
9
|
+
$pmap_default_thread_count = 20 # rubocop:disable GlobalVars
|
10
|
+
|
11
|
+
# GoodData Module
|
12
|
+
module GoodData
|
13
|
+
end
|
14
|
+
|
15
|
+
# Modules
|
16
|
+
require_relative 'gooddata/core/core'
|
17
|
+
require_relative 'gooddata/models/models'
|
18
|
+
require_relative 'gooddata/exceptions/exceptions'
|
19
|
+
require_relative 'gooddata/helpers/helpers'
|
20
|
+
|
21
|
+
# Files
|
22
|
+
require_relative 'gooddata/bricks/utils'
|
23
|
+
require_relative 'gooddata/bricks/brick'
|
24
|
+
require_relative 'gooddata/bricks/base_pipeline'
|
25
|
+
require_relative 'gooddata/bricks/middleware/base_middleware'
|
26
|
+
require_relative 'gooddata/bricks/middleware/bench_middleware'
|
27
|
+
require_relative 'gooddata/bricks/middleware/logger_middleware'
|
28
|
+
require_relative 'gooddata/bricks/middleware/decode_params_middleware'
|
29
|
+
require_relative 'gooddata/bricks/middleware/aws_middleware'
|
30
|
+
require_relative 'gooddata/bricks/middleware/dwh_middleware'
|
31
|
+
require_relative 'gooddata/bricks/middleware/bench_middleware'
|
32
|
+
|
33
|
+
# CSV Downloader
|
34
|
+
require_relative 'gooddata/core/logging'
|
35
|
+
require_relative 'gooddata/connection'
|