gooddata 2.2.0-java → 2.3.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +60 -55
- data/lib/gooddata/cloud_resources/redshift/drivers/log4j.properties +0 -15
@@ -19,6 +19,18 @@ module GoodData
|
|
19
19
|
|
20
20
|
description 'Synchronization Info'
|
21
21
|
param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
|
22
|
+
|
23
|
+
description 'Abort on error'
|
24
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
25
|
+
|
26
|
+
description 'Logger'
|
27
|
+
param :gdc_logger, instance_of(Type::GdLogger), required: false
|
28
|
+
|
29
|
+
description 'Collect synced status'
|
30
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
31
|
+
|
32
|
+
description 'Sync failed list'
|
33
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
22
34
|
end
|
23
35
|
|
24
36
|
RESULT_HEADER = %i[from to status]
|
@@ -27,6 +39,8 @@ module GoodData
|
|
27
39
|
def call(params)
|
28
40
|
results = []
|
29
41
|
params.synchronize.map do |segment_info|
|
42
|
+
next if sync_failed_segment(segment_info[:segment_id], params)
|
43
|
+
|
30
44
|
result = migrate_date_dimension(params, segment_info)
|
31
45
|
results.concat(result)
|
32
46
|
end
|
@@ -47,8 +61,13 @@ module GoodData
|
|
47
61
|
# check latest master and previous master
|
48
62
|
master_upgrade_datasets = get_upgrade_dates(latest_blueprint, previous_blueprint) if params[:synchronize_ldm].downcase == 'diff_against_master' && previous_blueprint
|
49
63
|
unless master_upgrade_datasets&.empty?
|
64
|
+
collect_synced_status = collect_synced_status(params)
|
65
|
+
failed_projects = ThreadSafe::Array.new
|
66
|
+
|
50
67
|
segment_info[:to].pmap do |entry|
|
51
68
|
pid = entry[:pid]
|
69
|
+
next if sync_failed_project(pid, params)
|
70
|
+
|
52
71
|
to_project = client.projects(pid) || fail("Invalid 'to' project specified - '#{pid}'")
|
53
72
|
GoodData.logger.info "Migrating date dimension, project: '#{to_project.title}', PID: #{pid}"
|
54
73
|
to_blueprint = to_project.blueprint
|
@@ -56,13 +75,18 @@ module GoodData
|
|
56
75
|
next if upgrade_datasets.empty?
|
57
76
|
|
58
77
|
message = get_upgrade_message(upgrade_datasets)
|
78
|
+
failed_message = "Failed to migrate date dimension for project #{pid}"
|
79
|
+
update_status = to_project.upgrade_custom_v2(message)
|
80
|
+
process_failed_project(pid, failed_message, failed_projects, collect_synced_status) if collect_synced_status && update_status != 'OK'
|
59
81
|
|
60
82
|
results << {
|
61
83
|
from: segment_info[:from],
|
62
84
|
to: pid,
|
63
|
-
status:
|
85
|
+
status: update_status
|
64
86
|
}
|
65
87
|
end
|
88
|
+
|
89
|
+
process_failed_projects(failed_projects, short_name, params) if collect_synced_status
|
66
90
|
end
|
67
91
|
|
68
92
|
results
|
@@ -104,8 +128,10 @@ module GoodData
|
|
104
128
|
get_date_dimensions(blueprint).any? { |e| e[:urn] == DATE_DIMENSION_CUSTOM_V2 }
|
105
129
|
end
|
106
130
|
|
131
|
+
# Get date dimension from blue print. Return nil if date dimension not existing
|
107
132
|
def get_date_dimension(blueprint, id)
|
108
|
-
|
133
|
+
date_dimensions = get_date_dimensions(blueprint)
|
134
|
+
date_dimensions.find { |d| d[:id] == id }
|
109
135
|
end
|
110
136
|
|
111
137
|
def get_date_dimensions(blueprint)
|
@@ -29,7 +29,16 @@ module GoodData
|
|
29
29
|
param :data_product, instance_of(Type::GDDataProductType), required: false
|
30
30
|
|
31
31
|
description 'Logger'
|
32
|
-
param :gdc_logger, instance_of(Type::GdLogger), required:
|
32
|
+
param :gdc_logger, instance_of(Type::GdLogger), required: false
|
33
|
+
|
34
|
+
description 'Abort on error'
|
35
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
36
|
+
|
37
|
+
description 'Collect synced status'
|
38
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
39
|
+
|
40
|
+
description 'Sync failed list'
|
41
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
33
42
|
end
|
34
43
|
|
35
44
|
RESULT_HEADER = [
|
@@ -45,6 +54,8 @@ module GoodData
|
|
45
54
|
synchronize_projects = []
|
46
55
|
data_product = params.data_product
|
47
56
|
client = params.gdc_gd_client
|
57
|
+
collect_synced_status = collect_synced_status(params)
|
58
|
+
continue_on_error = continue_on_error(params)
|
48
59
|
domain_name = params.organization || params.domain
|
49
60
|
fail "Either organisation or domain has to be specified in params" unless domain_name
|
50
61
|
domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
|
@@ -52,6 +63,8 @@ module GoodData
|
|
52
63
|
invalid_client_ids = []
|
53
64
|
begin
|
54
65
|
results = params.segments.map do |segment|
|
66
|
+
next if sync_failed_segment(segment.segment_id, params)
|
67
|
+
|
55
68
|
segment_object = domain.segments(segment.segment_id, data_product)
|
56
69
|
tmp = segment_object.provision_client_projects.map do |m|
|
57
70
|
Hash[m.each_pair.to_a].merge(type: :provision_result)
|
@@ -65,10 +78,21 @@ module GoodData
|
|
65
78
|
unless entry[:project_uri]
|
66
79
|
error_message = "There was error during provisioning clients: #{entry[:error]}" unless error_message
|
67
80
|
invalid_client_ids << entry[:id]
|
81
|
+
if collect_synced_status
|
82
|
+
failed_message = "Failed to provision client #{entry[:id]} in segment #{segment.segment_id}. Error: #{entry[:error]}"
|
83
|
+
add_failed_client(entry[:id], failed_message, short_name, params)
|
84
|
+
end
|
68
85
|
next
|
69
86
|
end
|
87
|
+
|
88
|
+
project_id = entry[:project_uri].split('/').last
|
89
|
+
if collect_synced_status && entry[:status] == 'CREATED' && entry[:id]
|
90
|
+
# Update project client mappings when there are create new clients during provision clients of the segment
|
91
|
+
add_new_clients_to_project_client_mapping(project_id, entry[:id], segment.segment_id, params)
|
92
|
+
end
|
93
|
+
|
70
94
|
{
|
71
|
-
pid:
|
95
|
+
pid: project_id,
|
72
96
|
client_id: entry[:id]
|
73
97
|
}
|
74
98
|
end.compact
|
@@ -93,15 +117,20 @@ module GoodData
|
|
93
117
|
end
|
94
118
|
|
95
119
|
params.gdc_logger.debug "Deleted clients: #{deleted_client_ids.join(', ')}"
|
96
|
-
|
120
|
+
unless error_message['TooManyProjectsCreatedException'] || error_message['Max number registered projects']
|
121
|
+
raise error_message unless continue_on_error
|
122
|
+
|
123
|
+
next
|
124
|
+
end
|
125
|
+
|
97
126
|
break tmp
|
98
127
|
end
|
99
128
|
|
100
129
|
tmp
|
101
130
|
end
|
102
131
|
rescue => e
|
103
|
-
params.gdc_logger.error "Problem occurs when provisioning clients."
|
104
|
-
raise e
|
132
|
+
params.gdc_logger.error "Problem occurs when provisioning clients. Error: #{e}"
|
133
|
+
raise e unless continue_on_error
|
105
134
|
end
|
106
135
|
|
107
136
|
results.flatten! if results
|
@@ -32,6 +32,15 @@ module GoodData
|
|
32
32
|
|
33
33
|
description 'Additional Hidden Parameters'
|
34
34
|
param :additional_hidden_params, instance_of(Type::HashType), required: false
|
35
|
+
|
36
|
+
description 'Abort on error'
|
37
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
38
|
+
|
39
|
+
description 'Collect synced status'
|
40
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
41
|
+
|
42
|
+
description 'Sync failed list'
|
43
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
35
44
|
end
|
36
45
|
|
37
46
|
class << self
|
@@ -46,6 +55,8 @@ module GoodData
|
|
46
55
|
return results unless include_ca
|
47
56
|
|
48
57
|
client = params.gdc_gd_client
|
58
|
+
collect_synced_status = collect_synced_status(params)
|
59
|
+
failed_projects = ThreadSafe::Array.new
|
49
60
|
|
50
61
|
params.synchronize.each do |info|
|
51
62
|
from = info.from
|
@@ -58,24 +69,33 @@ module GoodData
|
|
58
69
|
next unless ca_scripts
|
59
70
|
|
60
71
|
pid = entry[:pid]
|
72
|
+
next if sync_failed_project(pid, params)
|
73
|
+
|
61
74
|
ca_chunks = ca_scripts[:maqlDdlChunks]
|
62
|
-
to_project = client.projects(pid)
|
63
|
-
|
75
|
+
to_project = client.projects(pid)
|
76
|
+
unless to_project
|
77
|
+
process_failed_project(pid, "Invalid 'to' project specified - '#{pid}'", failed_projects, collect_synced_status)
|
78
|
+
next
|
79
|
+
end
|
64
80
|
|
81
|
+
params.gdc_logger.info "Synchronizing Computed Attributes to project: '#{to_project.title}', PID: #{pid}"
|
82
|
+
error_message = nil
|
65
83
|
begin
|
66
84
|
ca_chunks.each { |chunk| to_project.execute_maql(chunk) }
|
67
85
|
rescue => e
|
68
|
-
|
86
|
+
error_message = "Error occurred when executing MAQL for project: \"#{to_project.title}\" reason: \"#{e.message}\", chunks: #{ca_chunks.inspect}"
|
87
|
+
process_failed_project(pid, error_message, failed_projects, collect_synced_status)
|
69
88
|
end
|
70
89
|
|
71
90
|
results << {
|
72
91
|
from: from,
|
73
92
|
to: pid,
|
74
|
-
status: 'ok'
|
93
|
+
status: error_message.nil? ? 'ok' : 'failed'
|
75
94
|
}
|
76
95
|
end
|
77
96
|
end
|
78
97
|
|
98
|
+
process_failed_projects(failed_projects, short_name, params) if collect_synced_status
|
79
99
|
results
|
80
100
|
end
|
81
101
|
end
|
@@ -38,6 +38,18 @@ module GoodData
|
|
38
38
|
|
39
39
|
description 'Additional Hidden Parameters'
|
40
40
|
param :additional_hidden_params, instance_of(Type::HashType), required: false
|
41
|
+
|
42
|
+
description 'Abort on error'
|
43
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
44
|
+
|
45
|
+
description 'Logger'
|
46
|
+
param :gdc_logger, instance_of(Type::GdLogger), required: false
|
47
|
+
|
48
|
+
description 'Collect synced status'
|
49
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
50
|
+
|
51
|
+
description 'Sync failed list'
|
52
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
41
53
|
end
|
42
54
|
|
43
55
|
RESULT_HEADER = [
|
@@ -65,6 +77,8 @@ module GoodData
|
|
65
77
|
end
|
66
78
|
|
67
79
|
results = segments.map do |segment|
|
80
|
+
next if sync_failed_segment(segment.segment_id, params)
|
81
|
+
|
68
82
|
if params.ads_client
|
69
83
|
master_projects = GoodData::LCM2::Helpers.get_master_project_list_from_ads(params.release_table_name, params.ads_client, segment.segment_id)
|
70
84
|
else
|
@@ -83,8 +97,7 @@ module GoodData
|
|
83
97
|
failed_count = sync_result['failedClients']['count']
|
84
98
|
|
85
99
|
if failed_count.to_i > 0
|
86
|
-
|
87
|
-
"Details: #{sync_result['links']['details']}")
|
100
|
+
error_handle(segment, res, collect_synced_status(params), params)
|
88
101
|
end
|
89
102
|
|
90
103
|
if keep_only_previous_masters_count >= 0
|
@@ -102,8 +115,8 @@ module GoodData
|
|
102
115
|
|
103
116
|
{
|
104
117
|
segment: segment.id,
|
105
|
-
master_pid: master.pid,
|
106
|
-
master_name: master.title,
|
118
|
+
master_pid: master.nil? ? '' : master.pid,
|
119
|
+
master_name: master.nil? ? '' : master.title,
|
107
120
|
successful_count: sync_result['successfulClients']['count']
|
108
121
|
}
|
109
122
|
end
|
@@ -147,6 +160,45 @@ module GoodData
|
|
147
160
|
end
|
148
161
|
end
|
149
162
|
# rubocop:enable Metrics/ParameterLists
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def error_handle(segment, error_result, continue_on_error, params)
|
167
|
+
sync_result = error_result.json['synchronizationResult']
|
168
|
+
success_count = sync_result['successfulClients']['count'].to_i
|
169
|
+
failed_count = sync_result['failedClients']['count'].to_i
|
170
|
+
|
171
|
+
# Synchronize failure for all clients in segment
|
172
|
+
if continue_on_error && success_count.zero? && failed_count.positive?
|
173
|
+
segment_warning_message = "Failed to synchronize clients for #{segment.segment_id} segment. Details: #{sync_result['links']['details']}"
|
174
|
+
add_failed_segment(segment.segment_id, segment_warning_message, short_name, params)
|
175
|
+
return
|
176
|
+
end
|
177
|
+
|
178
|
+
summary_error_message = "#{failed_count} clients failed to synchronize. Details: #{sync_result['links']['details']}"
|
179
|
+
fail(summary_error_message) unless continue_on_error
|
180
|
+
|
181
|
+
GoodData.logger.warn summary_error_message
|
182
|
+
if error_result.details # rubocop:disable Style/SafeNavigation
|
183
|
+
error_result.details.items.each do |item|
|
184
|
+
next if item['status'] == 'OK'
|
185
|
+
|
186
|
+
error_client_id = item['id']
|
187
|
+
error_message = error_message(item, segment)
|
188
|
+
add_failed_client(error_client_id, error_message, short_name, params)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def error_message(error_item, segment)
|
194
|
+
error_client_id = error_item['id']
|
195
|
+
error_message = "Failed to synchronize #{error_client_id} client in #{segment.segment_id} segment."
|
196
|
+
error_message = "#{error_message}. Detail: #{error_item['error']['message']}" if error_item['error'] && error_item['error']['message']
|
197
|
+
|
198
|
+
error_message = "#{error_message}. Error items: #{error_item['error']['parameters']}" if error_item['error'] && error_item['error']['parameters']
|
199
|
+
|
200
|
+
error_message
|
201
|
+
end
|
150
202
|
end
|
151
203
|
end
|
152
204
|
end
|
@@ -24,6 +24,15 @@ module GoodData
|
|
24
24
|
|
25
25
|
description 'Logger'
|
26
26
|
param :gdc_logger, instance_of(Type::GdLogger), required: true
|
27
|
+
|
28
|
+
description 'Abort on error'
|
29
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
30
|
+
|
31
|
+
description 'Collect synced status'
|
32
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
33
|
+
|
34
|
+
description 'Sync failed list'
|
35
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
27
36
|
end
|
28
37
|
|
29
38
|
RESULT_HEADER = %i[from to count status]
|
@@ -31,6 +40,8 @@ module GoodData
|
|
31
40
|
class << self
|
32
41
|
def call(params)
|
33
42
|
results = []
|
43
|
+
collect_synced_status = collect_synced_status(params)
|
44
|
+
failed_projects = ThreadSafe::Array.new
|
34
45
|
|
35
46
|
client = params.gdc_gd_client
|
36
47
|
development_client = params.development_client
|
@@ -39,22 +50,36 @@ module GoodData
|
|
39
50
|
from_project = info.from
|
40
51
|
to_projects = info.to
|
41
52
|
|
42
|
-
from = development_client.projects(from_project)
|
53
|
+
from = development_client.projects(from_project)
|
54
|
+
unless from
|
55
|
+
process_failed_project(from_project, "Invalid 'from' project specified - '#{from_project}'", failed_projects, collect_synced_status)
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
43
59
|
dataset_mapping = from.dataset_mapping
|
44
60
|
if dataset_mapping&.dig('datasetMappings', 'items').nil? || dataset_mapping['datasetMappings']['items'].empty?
|
45
61
|
params.gdc_logger.info "Project: '#{from.title}', PID: '#{from.pid}' has no model mapping, skip synchronizing model mapping."
|
46
62
|
else
|
47
63
|
to_projects.peach do |to|
|
48
64
|
pid = to[:pid]
|
49
|
-
|
65
|
+
next if sync_failed_project(pid, params)
|
66
|
+
|
67
|
+
to_project = client.projects(pid)
|
68
|
+
process_failed_project(pid, "Invalid 'to' project specified - '#{pid}'", failed_projects, collect_synced_status) unless to_project
|
50
69
|
|
51
|
-
|
70
|
+
message_to_project = "to project: '#{to_project.title}', PID: '#{to_project.pid}'"
|
71
|
+
params.gdc_logger.info "Transferring model mapping, from project: '#{from.title}', PID: '#{from.pid}', #{message_to_project}"
|
52
72
|
res = to_project.update_dataset_mapping(dataset_mapping)
|
53
73
|
res[:from] = from.pid
|
54
74
|
results << res
|
75
|
+
|
76
|
+
failed_message = "Failed to transfer model mapping from project '#{from.pid}' to project '#{to_project.pid}'"
|
77
|
+
process_failed_project(pid, failed_message, failed_projects, collect_synced_status) if collect_synced_status && res[:status] != 'OK'
|
55
78
|
end
|
56
79
|
end
|
57
80
|
end
|
81
|
+
|
82
|
+
process_failed_projects(failed_projects, short_name, params) if collect_synced_status
|
58
83
|
# Return results
|
59
84
|
results.flatten
|
60
85
|
end
|
@@ -44,6 +44,15 @@ module GoodData
|
|
44
44
|
|
45
45
|
description 'Delete extra process schedule flag'
|
46
46
|
param :delete_extra_process_schedule, instance_of(Type::BooleanType), required: false, default: true
|
47
|
+
|
48
|
+
description 'Abort on error'
|
49
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
50
|
+
|
51
|
+
description 'Collect synced status'
|
52
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
53
|
+
|
54
|
+
description 'Sync failed list'
|
55
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
47
56
|
end
|
48
57
|
|
49
58
|
# will be updated later based on the way etl synchronization
|
@@ -59,6 +68,8 @@ module GoodData
|
|
59
68
|
def call(params)
|
60
69
|
client = params.gdc_gd_client
|
61
70
|
data_product = params.data_product
|
71
|
+
collect_synced_status = collect_synced_status(params)
|
72
|
+
failed_projects = ThreadSafe::Array.new
|
62
73
|
|
63
74
|
schedule_additional_params = params.schedule_additional_params || params.additional_params
|
64
75
|
schedule_additional_hidden_params = params.schedule_additional_hidden_params || params.additional_hidden_params
|
@@ -68,6 +79,8 @@ module GoodData
|
|
68
79
|
end
|
69
80
|
|
70
81
|
results = synchronize_segments.pmap do |segment_id, synchronize|
|
82
|
+
next if collect_synced_status && sync_failed_segment(segment_id, params)
|
83
|
+
|
71
84
|
segment = data_product.segments.find { |s| s.segment_id == segment_id }
|
72
85
|
res = segment.synchronize_processes(
|
73
86
|
synchronize.flat_map do |info|
|
@@ -80,7 +93,11 @@ module GoodData
|
|
80
93
|
res = GoodData::Helpers.symbolize_keys(res)
|
81
94
|
|
82
95
|
if res[:syncedResult][:errors]
|
83
|
-
|
96
|
+
error_message = "Failed to sync processes/schedules for segment #{segment_id}. Error: #{res[:syncedResult][:errors].pretty_inspect}"
|
97
|
+
fail error_message unless collect_synced_status
|
98
|
+
|
99
|
+
add_failed_segment(segment_id, error_message, short_name, params)
|
100
|
+
next
|
84
101
|
end
|
85
102
|
|
86
103
|
if res[:syncedResult][:clients]
|
@@ -111,12 +128,19 @@ module GoodData
|
|
111
128
|
hidden_params_for_all_schedules_in_all_projects = hidden_params_for_all_projects[:all_schedules]
|
112
129
|
|
113
130
|
params.synchronize.peach do |info|
|
114
|
-
from_project_etl_names = get_process_n_schedule_names(client, info.from) if delete_extra_process_schedule
|
131
|
+
from_project_etl_names = get_process_n_schedule_names(client, info.from, failed_projects, collect_synced_status) if delete_extra_process_schedule
|
132
|
+
next if delete_extra_process_schedule && from_project_etl_names.nil?
|
115
133
|
|
116
134
|
to_projects = info.to
|
117
135
|
to_projects.peach do |entry|
|
118
136
|
pid = entry[:pid]
|
119
|
-
|
137
|
+
next if collect_synced_status && sync_failed_project(pid, params)
|
138
|
+
|
139
|
+
to_project = client.projects(pid)
|
140
|
+
unless to_project
|
141
|
+
process_failed_project(pid, "Invalid 'to' project specified - '#{pid}'", failed_projects, collect_synced_status)
|
142
|
+
next
|
143
|
+
end
|
120
144
|
|
121
145
|
if delete_extra_process_schedule
|
122
146
|
to_project_process_id_names = {}
|
@@ -140,24 +164,31 @@ module GoodData
|
|
140
164
|
to_project.set_metadata('GOODOT_CUSTOM_PROJECT_ID', client_id) # TMA-210
|
141
165
|
|
142
166
|
to_project.schedules.each do |schedule|
|
167
|
+
schedule_name = schedule.name
|
143
168
|
if delete_extra_process_schedule
|
144
|
-
|
169
|
+
schedule_project_info = [schedule_name, to_project_process_id_names[schedule.process_id]]
|
170
|
+
unless from_project_etl_names[:schedules].include?(schedule_project_info)
|
145
171
|
schedule.delete
|
146
172
|
next
|
147
173
|
end
|
148
174
|
end
|
149
175
|
|
176
|
+
params_for_all_projects_schedule_name = params_for_all_projects[schedule_name]
|
177
|
+
params_for_this_client_schedule_name = params_for_this_client[schedule_name]
|
178
|
+
hidden_params_for_all_projects_schedule_name = hidden_params_for_all_projects[schedule_name]
|
179
|
+
hidden_params_for_this_client_schedule_name = hidden_params_for_this_client[schedule_name]
|
180
|
+
|
150
181
|
schedule.update_params(schedule_additional_params) if schedule_additional_params
|
151
|
-
schedule.update_params(params_for_all_schedules_in_all_projects) if params_for_all_schedules_in_all_projects
|
152
|
-
schedule.update_params(
|
182
|
+
schedule.update_params(**params_for_all_schedules_in_all_projects) if params_for_all_schedules_in_all_projects
|
183
|
+
schedule.update_params(**params_for_all_projects_schedule_name) if params_for_all_projects_schedule_name
|
153
184
|
schedule.update_params(params_for_all_schedules_in_this_client) if params_for_all_schedules_in_this_client
|
154
|
-
schedule.update_params(
|
185
|
+
schedule.update_params(**params_for_this_client_schedule_name) if params_for_this_client_schedule_name
|
155
186
|
|
156
187
|
schedule.update_hidden_params(schedule_additional_hidden_params) if schedule_additional_hidden_params
|
157
188
|
schedule.update_hidden_params(hidden_params_for_all_schedules_in_all_projects) if hidden_params_for_all_schedules_in_all_projects
|
158
|
-
schedule.update_hidden_params(
|
189
|
+
schedule.update_hidden_params(hidden_params_for_all_projects_schedule_name) if hidden_params_for_all_projects_schedule_name
|
159
190
|
schedule.update_hidden_params(hidden_params_for_all_schedules_in_this_client) if hidden_params_for_all_schedules_in_this_client
|
160
|
-
schedule.update_hidden_params(
|
191
|
+
schedule.update_hidden_params(hidden_params_for_this_client_schedule_name) if hidden_params_for_this_client_schedule_name
|
161
192
|
|
162
193
|
schedule.enable
|
163
194
|
schedule.save
|
@@ -165,13 +196,19 @@ module GoodData
|
|
165
196
|
end
|
166
197
|
end
|
167
198
|
|
199
|
+
process_failed_projects(failed_projects, short_name, params) if collect_synced_status
|
168
200
|
results.flatten
|
169
201
|
end
|
170
202
|
|
171
203
|
private
|
172
204
|
|
173
|
-
def get_process_n_schedule_names(client, project_id)
|
174
|
-
project = client.projects(project_id)
|
205
|
+
def get_process_n_schedule_names(client, project_id, failed_projects, continue_on_error)
|
206
|
+
project = client.projects(project_id)
|
207
|
+
unless project
|
208
|
+
process_failed_project(project_id, "Invalid 'from' project specified - '#{project_id}'", failed_projects, continue_on_error)
|
209
|
+
return nil
|
210
|
+
end
|
211
|
+
|
175
212
|
processes = project.processes
|
176
213
|
process_id_names = Hash[processes.map { |process| [process.process_id, process.name] }]
|
177
214
|
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010-2021 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_relative 'base_action'
|
9
|
+
require 'thread_safe'
|
10
|
+
|
11
|
+
module GoodData
|
12
|
+
module LCM2
|
13
|
+
class SynchronizeKDDashboardPermissions < BaseAction
|
14
|
+
DESCRIPTION = 'Synchronize KD Dashboard Permission'
|
15
|
+
|
16
|
+
PARAMS = define_params(self) do
|
17
|
+
description 'Client used to connecting to development domain'
|
18
|
+
param :development_client, instance_of(Type::GdClientType), required: true
|
19
|
+
|
20
|
+
description 'Client Used for Connecting to GD'
|
21
|
+
param :gdc_gd_client, instance_of(Type::GdClientType), required: true
|
22
|
+
|
23
|
+
description 'Logger'
|
24
|
+
param :gdc_logger, instance_of(Type::GdLogger), required: true
|
25
|
+
|
26
|
+
description 'Additional Hidden Parameters'
|
27
|
+
param :additional_hidden_params, instance_of(Type::HashType), required: false
|
28
|
+
|
29
|
+
description 'Synchronization Info'
|
30
|
+
param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
|
31
|
+
|
32
|
+
description 'Disable synchronizing dashboard permissions for AD/KD dashboards.'
|
33
|
+
param :disable_kd_dashboard_permission, instance_of(Type::BooleanType), required: false, default: false
|
34
|
+
|
35
|
+
description 'Abort on error'
|
36
|
+
param :abort_on_error, instance_of(Type::StringType), required: false
|
37
|
+
|
38
|
+
description 'Collect synced status'
|
39
|
+
param :collect_synced_status, instance_of(Type::BooleanType), required: false
|
40
|
+
|
41
|
+
description 'Sync failed list'
|
42
|
+
param :sync_failed_list, instance_of(Type::HashType), required: false
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def call(params)
|
47
|
+
results = ThreadSafe::Array.new
|
48
|
+
collect_synced_status = collect_synced_status(params)
|
49
|
+
failed_projects = ThreadSafe::Array.new
|
50
|
+
|
51
|
+
disable_kd_dashboard_permission = GoodData::Helpers.to_boolean(params.disable_kd_dashboard_permission)
|
52
|
+
|
53
|
+
# rubocop:disable Style/UnlessElse
|
54
|
+
unless disable_kd_dashboard_permission
|
55
|
+
dashboard_type = "KD"
|
56
|
+
dev_client = params.development_client
|
57
|
+
gdc_client = params.gdc_gd_client
|
58
|
+
|
59
|
+
params.synchronize.peach do |param_info|
|
60
|
+
from_project_info = param_info.from
|
61
|
+
to_projects_info = param_info.to
|
62
|
+
|
63
|
+
from_project = dev_client.projects(from_project_info)
|
64
|
+
unless from_project
|
65
|
+
process_failed_project(from_project_info, "Invalid 'from' project specified - '#{from_project_info}'", failed_projects, collect_synced_status)
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
from_dashboards = from_project.analytical_dashboards
|
70
|
+
|
71
|
+
params.gdc_logger.info "Transferring #{dashboard_type} Dashboard permission, from project: '#{from_project.title}', PID: '#{from_project.pid}' for dashboard(s): #{from_dashboards.map { |d| "#{d.title.inspect}" }.join(', ')}" # rubocop:disable Metrics/LineLength
|
72
|
+
to_projects_info.peach do |item|
|
73
|
+
to_project_pid = item[:pid]
|
74
|
+
next if sync_failed_project(to_project_pid, params)
|
75
|
+
|
76
|
+
to_project = gdc_client.projects(to_project_pid)
|
77
|
+
unless to_project
|
78
|
+
process_failed_project(to_project_pid, "Invalid 'to' project specified - '#{to_project_pid}'", failed_projects, collect_synced_status)
|
79
|
+
next
|
80
|
+
end
|
81
|
+
|
82
|
+
to_dashboards = to_project.analytical_dashboards
|
83
|
+
GoodData::Project.transfer_dashboard_permission(from_project, to_project, from_dashboards, to_dashboards)
|
84
|
+
end
|
85
|
+
|
86
|
+
results << {
|
87
|
+
from_project_name: from_project.title,
|
88
|
+
from_project_pid: from_project.pid,
|
89
|
+
status: 'ok'
|
90
|
+
}
|
91
|
+
end
|
92
|
+
else
|
93
|
+
params.gdc_logger.info "Skip synchronize KD dashboard permission."
|
94
|
+
end
|
95
|
+
|
96
|
+
process_failed_projects(failed_projects, short_name, params) if collect_synced_status
|
97
|
+
results
|
98
|
+
# rubocop:enable Style/UnlessElse
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|