gooddata 2.1.8-java → 2.1.9-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/.travis.yml +1 -1
- data/Dockerfile +9 -4
- data/Dockerfile.jruby +4 -4
- data/Dockerfile.ruby +5 -4
- data/SDK_VERSION +1 -1
- data/VERSION +1 -1
- data/bin/provision.sh +2 -0
- data/bin/release.sh +2 -0
- data/bin/rollout.sh +2 -0
- data/bin/run_brick.rb +28 -7
- data/bin/test_projects_cleanup.rb +4 -0
- data/bin/user_filters.sh +2 -0
- data/ci.rake +1 -1
- data/dev-gooddata-sso.pub.encrypted +40 -40
- data/gooddata.gemspec +5 -1
- data/lcm.rake +10 -0
- data/lib/gooddata/bricks/middleware/execution_result_middleware.rb +68 -0
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +2 -1
- data/lib/gooddata/bricks/middleware/mask_logger_decorator.rb +5 -1
- data/lib/gooddata/bricks/pipeline.rb +7 -0
- data/lib/gooddata/cloud_resources/cloud_resouce_factory.rb +28 -0
- data/lib/gooddata/cloud_resources/cloud_resource_client.rb +24 -0
- data/lib/gooddata/cloud_resources/cloud_resources.rb +12 -0
- data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +15 -0
- data/lib/gooddata/cloud_resources/redshift/redshift_client.rb +100 -0
- data/lib/gooddata/exceptions/invalid_env_error.rb +15 -0
- data/lib/gooddata/helpers/data_helper.rb +10 -0
- data/lib/gooddata/helpers/global_helpers.rb +4 -0
- data/lib/gooddata/helpers/global_helpers_params.rb +4 -7
- data/lib/gooddata/lcm/actions/collect_segment_clients.rb +4 -1
- data/lib/gooddata/lcm/actions/collect_segments.rb +1 -2
- data/lib/gooddata/lcm/actions/create_segment_masters.rb +5 -3
- data/lib/gooddata/lcm/actions/synchronize_clients.rb +1 -1
- data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +1 -2
- data/lib/gooddata/lcm/actions/synchronize_ldm.rb +10 -2
- data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +22 -2
- data/lib/gooddata/lcm/actions/synchronize_users.rb +19 -0
- data/lib/gooddata/lcm/actions/update_release_table.rb +7 -1
- data/lib/gooddata/lcm/exceptions/lcm_execution_error.rb +16 -0
- data/lib/gooddata/lcm/helpers/release_table_helper.rb +16 -8
- data/lib/gooddata/lcm/lcm2.rb +6 -4
- data/lib/gooddata/models/execution.rb +0 -1
- data/lib/gooddata/models/execution_detail.rb +0 -1
- data/lib/gooddata/models/profile.rb +33 -11
- data/lib/gooddata/models/project.rb +2 -2
- data/lib/gooddata/models/project_creator.rb +2 -0
- data/lib/gooddata/models/schedule.rb +0 -1
- data/lib/gooddata/rest/client.rb +2 -2
- data/lib/gooddata/rest/connection.rb +5 -3
- data/rubydev_public.gpg.encrypted +51 -51
- data/rubydev_secret_keys.gpg.encrypted +109 -109
- metadata +12 -5
- data/lib/gooddata/extensions/hash.rb +0 -18
@@ -190,6 +190,9 @@ module GoodData
|
|
190
190
|
create_non_existing_user_groups: create_non_existing_user_groups,
|
191
191
|
user_groups_cache: nil
|
192
192
|
}
|
193
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, data_rows=#{new_users.size}")
|
194
|
+
|
195
|
+
GoodData.logger.info("Synchronizing in mode \"#{mode}\"")
|
193
196
|
results = case mode
|
194
197
|
when 'add_to_organization'
|
195
198
|
domain.create_users(new_users.uniq { |u| u[:login] || u[:email] })
|
@@ -197,6 +200,8 @@ module GoodData
|
|
197
200
|
user_ids = new_users.uniq { |u| u[:login] || u[:email] }.map { |u| u[:login] || u[:email] }
|
198
201
|
users = user_ids.map { |u| domain.users(u, client: client) }
|
199
202
|
params.gdc_logger.warn "Deleting #{users.count} users from domain #{domain_name}"
|
203
|
+
|
204
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, domain=#{domain_name}, data_rows=#{users.count}")
|
200
205
|
users.map(&:delete)
|
201
206
|
when 'sync_project'
|
202
207
|
project.import_users(new_users, common_params)
|
@@ -204,6 +209,8 @@ module GoodData
|
|
204
209
|
new_users.group_by { |u| u[:pid] }.flat_map do |project_id, users|
|
205
210
|
begin
|
206
211
|
project = client.projects(project_id)
|
212
|
+
|
213
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project_id}, data_rows=#{users.count}")
|
207
214
|
project.import_users(users, common_params)
|
208
215
|
rescue RestClient::ResourceNotFound
|
209
216
|
fail "Project \"#{project_id}\" was not found. Please check your project ids in the source file"
|
@@ -215,6 +222,8 @@ module GoodData
|
|
215
222
|
end
|
216
223
|
when 'sync_one_project_based_on_pid'
|
217
224
|
filtered_users = new_users.select { |u| u[:pid] == project.pid }
|
225
|
+
|
226
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, data_rows=#{filtered_users.count}")
|
218
227
|
project.import_users(filtered_users, common_params)
|
219
228
|
when 'sync_one_project_based_on_custom_id'
|
220
229
|
filter_value = UserBricksHelper.resolve_client_id(domain, project, data_product)
|
@@ -235,6 +244,7 @@ module GoodData
|
|
235
244
|
end
|
236
245
|
|
237
246
|
GoodData.logger.info("Project #{project.pid} will receive #{filtered_users.count} from #{new_users.count} users")
|
247
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, filtered_users=#{filtered_users.count}, data_rows=#{new_users.count}")
|
238
248
|
project.import_users(filtered_users, common_params)
|
239
249
|
when 'sync_multiple_projects_based_on_custom_id'
|
240
250
|
all_clients = domain.clients(:all, data_product).to_a
|
@@ -248,6 +258,8 @@ module GoodData
|
|
248
258
|
fail "Client #{client_id} does not have project." unless project
|
249
259
|
|
250
260
|
GoodData.logger.info("Project #{project.pid} of client #{client_id} will receive #{users.count} users")
|
261
|
+
|
262
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, data_rows=#{users.count}")
|
251
263
|
project.import_users(users, common_params)
|
252
264
|
end
|
253
265
|
when 'sync_domain_client_workspaces'
|
@@ -280,6 +292,8 @@ module GoodData
|
|
280
292
|
|
281
293
|
working_client_ids << client_id.to_s
|
282
294
|
GoodData.logger.info("Project #{project.pid} of client #{client_id} will receive #{users.count} users")
|
295
|
+
|
296
|
+
GoodData.gd_logger.info("Synchronizing in mode=#{mode}, project_id=#{project.pid}, data_rows=#{users.count}")
|
283
297
|
project.import_users(users, common_params)
|
284
298
|
end
|
285
299
|
|
@@ -303,13 +317,18 @@ module GoodData
|
|
303
317
|
next
|
304
318
|
end
|
305
319
|
GoodData.logger.info("Synchronizing all users in project #{project.pid} of client #{c.client_id}")
|
320
|
+
|
321
|
+
GoodData.gd_logger.info("Synchronizing all users in project_id=#{project.pid}, client_id=#{c.client_id}")
|
306
322
|
res += project.import_users([], common_params)
|
307
323
|
end
|
308
324
|
end
|
309
325
|
|
310
326
|
res
|
311
327
|
when 'sync_domain_and_project'
|
328
|
+
GoodData.gd_logger.info("Create users in mode=#{mode}, data_rows=#{new_users.count}")
|
312
329
|
domain.create_users(new_users, ignore_failures: ignore_failures)
|
330
|
+
|
331
|
+
GoodData.gd_logger.info("Import users in mode=#{mode}, data_rows=#{new_users.count}")
|
313
332
|
project.import_users(new_users, common_params)
|
314
333
|
end
|
315
334
|
|
@@ -39,6 +39,7 @@ module GoodData
|
|
39
39
|
class << self
|
40
40
|
def call(params)
|
41
41
|
client = params.gdc_gd_client
|
42
|
+
GoodData.gd_logger.info("Update release table: use_nfs=#{params.ads_client.nil?}")
|
42
43
|
|
43
44
|
domain_name = params.organization || params.domain
|
44
45
|
fail "Either organisation or domain has to be specified in params" unless domain_name
|
@@ -48,6 +49,7 @@ module GoodData
|
|
48
49
|
segment_id = segment_in.segment_id
|
49
50
|
|
50
51
|
placeholders = {
|
52
|
+
data_product_id: segment_in[:data_product_id],
|
51
53
|
segment_id: segment_in[:segment_id],
|
52
54
|
master_project_id: segment_in[:master_pid],
|
53
55
|
version: segment_in[:version],
|
@@ -83,7 +85,11 @@ module GoodData
|
|
83
85
|
|
84
86
|
params.ads_client.execute(query)
|
85
87
|
else
|
86
|
-
|
88
|
+
data_product_id = placeholders[:data_product_id]
|
89
|
+
segment_id = placeholders[:segment_id]
|
90
|
+
master_pid = placeholders[:master_project_id]
|
91
|
+
version = placeholders[:version]
|
92
|
+
GoodData::LCM2::Helpers.update_latest_master_to_nfs(domain_id, data_product_id, segment_id, master_pid, version)
|
87
93
|
end
|
88
94
|
end
|
89
95
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright (c) 2010-2019 GoodData Corporation. All rights reserved.
|
2
|
+
# This source code is licensed under the BSD-style license found in the
|
3
|
+
# LICENSE file in the root directory of this source tree.
|
4
|
+
|
5
|
+
module GoodData
|
6
|
+
class LcmExecutionError < RuntimeError
|
7
|
+
DEFAULT_MSG = 'Error during lcm execution'
|
8
|
+
|
9
|
+
attr_reader :summary_error
|
10
|
+
|
11
|
+
def initialize(summary_error, message = DEFAULT_MSG)
|
12
|
+
super(message)
|
13
|
+
@summary_error = summary_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -8,7 +8,7 @@ module GoodData
|
|
8
8
|
module LCM2
|
9
9
|
class Helpers
|
10
10
|
DEFAULT_TABLE_NAME = 'LCM_RELEASE'
|
11
|
-
DEFAULT_NFS_DIRECTORY = 'release-tables'
|
11
|
+
DEFAULT_NFS_DIRECTORY = '/release-tables'
|
12
12
|
|
13
13
|
class << self
|
14
14
|
def latest_master_project_from_ads(release_table_name, ads_client, segment_id)
|
@@ -25,22 +25,30 @@ module GoodData
|
|
25
25
|
sorted.last
|
26
26
|
end
|
27
27
|
|
28
|
-
def latest_master_project_from_nfs(domain_id, segment_id)
|
29
|
-
|
30
|
-
data
|
28
|
+
def latest_master_project_from_nfs(domain_id, data_product_id, segment_id)
|
29
|
+
file_path = path_to_release_table_file(domain_id, data_product_id, segment_id)
|
30
|
+
data = GoodData::Helpers::Csv.read_as_hash(file_path)
|
31
|
+
latest_master_project = data.sort_by { |master| master[:version] }
|
31
32
|
.reverse.first
|
33
|
+
|
34
|
+
version_info = latest_master_project ? "master_pid=#{latest_master_project[:master_project_id]} version=#{latest_master_project[:version]}" : ""
|
35
|
+
GoodData.gd_logger.info "Getting latest master project: file=#{file_path} domain=#{domain_id} data_product=#{data_product_id} segment=#{segment_id} #{version_info}"
|
36
|
+
latest_master_project
|
32
37
|
end
|
33
38
|
|
34
|
-
def update_latest_master_to_nfs(domain_id, segment_id, master_pid, version)
|
39
|
+
def update_latest_master_to_nfs(domain_id, data_product_id, segment_id, master_pid, version)
|
40
|
+
file_path = path_to_release_table_file(domain_id, data_product_id, segment_id)
|
41
|
+
GoodData.gd_logger.info "Updating release table: file=#{file_path} domain=#{domain_id} data_product=#{data_product_id} segment=#{segment_id} master_pid=#{master_pid} version=#{version}" # rubocop:disable Metrics/LineLength
|
35
42
|
GoodData::Helpers::Csv.ammend_line(
|
36
|
-
|
43
|
+
file_path,
|
37
44
|
master_project_id: master_pid,
|
38
45
|
version: version
|
39
46
|
)
|
40
47
|
end
|
41
48
|
|
42
|
-
def path_to_release_table_file(domain_id, segment_id)
|
43
|
-
|
49
|
+
def path_to_release_table_file(domain_id, data_prod_id, segment_id)
|
50
|
+
nsf_directory = ENV['RELEASE_TABLE_NFS_DIRECTORY'] || DEFAULT_NFS_DIRECTORY
|
51
|
+
[nsf_directory, domain_id, data_prod_id + '-' + segment_id + '.csv'].join('/')
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
data/lib/gooddata/lcm/lcm2.rb
CHANGED
@@ -18,6 +18,7 @@ require 'active_support/core_ext/hash/compact'
|
|
18
18
|
require_relative 'actions/actions'
|
19
19
|
require_relative 'dsl/dsl'
|
20
20
|
require_relative 'helpers/helpers'
|
21
|
+
require_relative 'exceptions/lcm_execution_error'
|
21
22
|
|
22
23
|
using TrueExtensions
|
23
24
|
using FalseExtensions
|
@@ -357,10 +358,11 @@ module GoodData
|
|
357
358
|
|
358
359
|
if errors.any?
|
359
360
|
error_message = JSON.pretty_generate(errors)
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
361
|
+
if strict_mode
|
362
|
+
raise GoodData::LcmExecutionError.new(errors[0][:err], error_message)
|
363
|
+
else
|
364
|
+
GoodData.logger.error(error_message)
|
365
|
+
end
|
364
366
|
end
|
365
367
|
|
366
368
|
result
|
@@ -324,20 +324,42 @@ module GoodData
|
|
324
324
|
end
|
325
325
|
|
326
326
|
# Gets the array of projects
|
327
|
-
#
|
327
|
+
# @param limit [Integer] maximum number of projects to get.
|
328
|
+
# @param offset [Integer] offset of the first project, start from 0.
|
328
329
|
# @return [Array<GoodData::Project>] Array of project where account settings belongs to
|
329
|
-
def projects(limit = nil)
|
330
|
+
def projects(limit = nil, offset = nil)
|
330
331
|
url = @json['accountSetting']['links']['projects']
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
332
|
+
|
333
|
+
all_projects = []
|
334
|
+
|
335
|
+
raise ArgumentError, 'Params limit and offset are expected' if !offset.nil? && limit.nil?
|
336
|
+
|
337
|
+
if limit.nil?
|
338
|
+
url += "?limit=500"
|
339
|
+
loop do
|
340
|
+
projects = client.get url
|
341
|
+
projects['projects']['items'].each do |project|
|
342
|
+
all_projects << client.create(GoodData::Project, project)
|
343
|
+
end
|
344
|
+
if !projects['projects']['paging'].nil? && !projects['projects']['paging']['next'].nil?
|
345
|
+
url = projects['projects']['paging']['next']
|
346
|
+
else
|
347
|
+
break
|
348
|
+
end
|
349
|
+
end
|
350
|
+
else
|
351
|
+
limit = [limit, 500].min if limit.is_a?(Integer) && limit > 0
|
352
|
+
|
353
|
+
url += "?limit=#{limit}"
|
354
|
+
url += "&offset=#{offset}" if !offset.nil? && offset.is_a?(Integer) && offset > 0
|
355
|
+
|
356
|
+
projects = client.get url
|
357
|
+
projects['projects']['items'].each do |project|
|
358
|
+
all_projects << client.create(GoodData::Project, project)
|
359
|
+
end
|
340
360
|
end
|
361
|
+
|
362
|
+
all_projects
|
341
363
|
end
|
342
364
|
|
343
365
|
# Saves object if dirty, clears dirty flag
|
@@ -67,9 +67,9 @@ module GoodData
|
|
67
67
|
class << self
|
68
68
|
# Returns an array of all projects accessible by
|
69
69
|
# current user
|
70
|
-
def all(opts = { client: GoodData.connection }, limit = nil)
|
70
|
+
def all(opts = { client: GoodData.connection }, limit = nil, offset = nil)
|
71
71
|
c = GoodData.get_client(opts)
|
72
|
-
c.user.projects(limit)
|
72
|
+
c.user.projects(limit, offset)
|
73
73
|
end
|
74
74
|
|
75
75
|
# Returns a Project object identified by given string
|
@@ -47,6 +47,8 @@ module GoodData
|
|
47
47
|
unless response
|
48
48
|
maql_diff_params = [:includeGrain]
|
49
49
|
maql_diff_params << :excludeFactRule if opts[:exclude_fact_rule]
|
50
|
+
maql_diff_params << :includeDeprecated if opts[:include_deprecated]
|
51
|
+
|
50
52
|
maql_diff_time = Benchmark.realtime do
|
51
53
|
response = project.maql_diff(blueprint: bp, params: maql_diff_params)
|
52
54
|
end
|
data/lib/gooddata/rest/client.rb
CHANGED
@@ -188,11 +188,11 @@ module GoodData
|
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
191
|
-
def projects(id = :all, limit = nil)
|
191
|
+
def projects(id = :all, limit = nil, offset = nil)
|
192
192
|
if limit.nil?
|
193
193
|
GoodData::Project[id, client: self]
|
194
194
|
else
|
195
|
-
GoodData::Project.all({ client: self }, limit)
|
195
|
+
GoodData::Project.all({ client: self }, limit, offset)
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
@@ -30,6 +30,7 @@ module GoodData
|
|
30
30
|
LOGIN_PATH = '/gdc/account/login'
|
31
31
|
TOKEN_PATH = '/gdc/account/token'
|
32
32
|
KEYS_TO_SCRUB = [:password, :verifyPassword, :authorizationToken]
|
33
|
+
API_LEVEL = 2
|
33
34
|
|
34
35
|
ID_LENGTH = 16
|
35
36
|
|
@@ -307,7 +308,6 @@ module GoodData
|
|
307
308
|
# Remove when TT sent in headers. Currently we need to parse from body
|
308
309
|
merge_headers!(:x_gdc_authtt => GoodData::Helpers.get_path(response, %w(userToken token)))
|
309
310
|
rescue Exception => e # rubocop:disable RescueException
|
310
|
-
GoodData.logger.error(e.message)
|
311
311
|
raise e
|
312
312
|
end
|
313
313
|
end
|
@@ -350,6 +350,9 @@ module GoodData
|
|
350
350
|
profile method.to_s.upcase, uri, request_id, stats_on do
|
351
351
|
b = proc do
|
352
352
|
params = fresh_request_params(request_id).merge(options)
|
353
|
+
|
354
|
+
params['X-GDC-VERSION'] = API_LEVEL
|
355
|
+
|
353
356
|
case method
|
354
357
|
when :get
|
355
358
|
@server[uri].get(params, &user_block)
|
@@ -514,8 +517,7 @@ module GoodData
|
|
514
517
|
begin
|
515
518
|
request.execute
|
516
519
|
rescue => e
|
517
|
-
|
518
|
-
raise e
|
520
|
+
raise "Error when uploading file #{filename}. Error: #{e}"
|
519
521
|
end
|
520
522
|
end
|
521
523
|
|
@@ -1,51 +1,51 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
1
|
+
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
|