gooddata 2.1.10-java → 2.1.15-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,6 +49,8 @@ module GoodData
49
49
  param :include_deprecated, instance_of(Type::BooleanType), required: false, default: false
50
50
  end
51
51
 
52
+ RESULT_HEADER = %i[from to status]
53
+
52
54
  class << self
53
55
  def call(params)
54
56
  results = []
@@ -76,9 +78,9 @@ module GoodData
76
78
  include_deprecated = params.include_deprecated.to_b
77
79
  from_pid = segment_info[:from]
78
80
  from = params.development_client.projects(from_pid) || fail("Invalid 'from' project specified - '#{from_pid}'")
79
-
80
81
  GoodData.logger.info "Creating Blueprint, project: '#{from.title}', PID: #{from_pid}"
81
82
  blueprint = from.blueprint(include_ca: params.include_computed_attributes.to_b)
83
+ segment_info[:from_blueprint] = blueprint
82
84
  maql_diff = nil
83
85
  previous_master = segment_info[:previous_master]
84
86
  diff_against_master = %w(diff_against_master_with_fallback diff_against_master)
@@ -89,6 +91,13 @@ module GoodData
89
91
  maql_diff_params << :excludeFactRule if exclude_fact_rule
90
92
  maql_diff_params << :includeDeprecated if include_deprecated
91
93
  maql_diff = previous_master.maql_diff(blueprint: blueprint, params: maql_diff_params)
94
+ chunks = maql_diff['projectModelDiff']['updateScripts']
95
+ if chunks.empty?
96
+ GoodData.logger.info "Synchronize LDM to clients will not proceed in mode \
97
+ '#{params[:synchronize_ldm].downcase}' due to no LDM changes in the new master project. \
98
+ If you had changed LDM of clients manually, please use mode 'diff_against_clients' \
99
+ to force synchronize LDM to clients"
100
+ end
92
101
  end
93
102
 
94
103
  segment_info[:to] = segment_info[:to].pmap do |entry|
@@ -13,8 +13,6 @@ require 'gooddata/extensions/integer'
13
13
  require 'gooddata/extensions/string'
14
14
  require 'gooddata/extensions/nil'
15
15
 
16
- require 'active_support/core_ext/hash/compact'
17
-
18
16
  require_relative 'actions/actions'
19
17
  require_relative 'dsl/dsl'
20
18
  require_relative 'helpers/helpers'
@@ -138,6 +136,7 @@ module GoodData
138
136
  EnsureTechnicalUsersDomain,
139
137
  EnsureTechnicalUsersProject,
140
138
  SynchronizeLdm,
139
+ MigrateGdcDateDimension,
141
140
  SynchronizeClients,
142
141
  SynchronizeComputedAttributes,
143
142
  CollectDymanicScheduleParams,
@@ -8,8 +8,6 @@
8
8
  require_relative '../dsl/dsl'
9
9
  require_relative '../helpers/helpers'
10
10
 
11
- require 'active_support/core_ext/hash/compact'
12
-
13
11
  require 'gooddata/extensions/class'
14
12
 
15
13
  module GoodData
@@ -2,8 +2,6 @@
2
2
  # This source code is licensed under the BSD-style license found in the
3
3
  # LICENSE file in the root directory of this source tree.
4
4
 
5
- require 'active_support/core_ext/hash/compact'
6
-
7
5
  module GoodData
8
6
  module Model
9
7
  class ProjectBlueprint
@@ -0,0 +1,662 @@
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 '../rest/resource'
9
+
10
+ module GoodData
11
+ class DataSource < Rest::Resource
12
+ attr_accessor :connection_info
13
+
14
+ DATA_SOURCES_URL = '/gdc/dataload/dataSources'
15
+ SNOWFLAKE = 'snowflake'
16
+ REDSHIFT = 'redshift'
17
+ BIGQUERY = 'bigQuery'
18
+ GENERIC = 'generic'
19
+ S3 = 's3'
20
+ ADS = 'ads'
21
+
22
+ class << self
23
+ # Get all data sources or get a specify data source from data source identify
24
+ # Expected parameter value:
25
+ # - :all return all data sources
26
+ # - :data_source_id return a data source with the specify data source identify
27
+ def [](id = :all, options = { client: GoodData.client })
28
+ c = GoodData.get_client(options)
29
+
30
+ if id == :all
31
+ data = c.get(DATA_SOURCES_URL)
32
+ data['dataSources']['items'].map do |ds_data|
33
+ c.create(DataSource, ds_data)
34
+ end
35
+ else
36
+ c.create(DataSource, c.get("#{DATA_SOURCES_URL}/#{id}"))
37
+ end
38
+ end
39
+
40
+ # Get a specify data source from data source identify
41
+ #
42
+ # @param [String] id Data source identify
43
+ # @return [DataSource] Data source corresponding in backend or throw exception if the data source identify doesn't exist
44
+ def from_id(id, options = { client: GoodData.client })
45
+ DataSource[id, options]
46
+ end
47
+
48
+ # Get a specify data source from data source alias
49
+ #
50
+ # @param [String] data_source_alias Data source alias
51
+ # @return [DataSource] Data source corresponding in backend or throw exception if the data source alias doesn't exist
52
+ def from_alias(data_source_alias, options = { client: GoodData.client })
53
+ data_sources = all(options)
54
+ result = data_sources.find do |data_source|
55
+ data_source.alias == data_source_alias
56
+ end
57
+ fail "Data source alias '#{data_source_alias}' has not found" unless result
58
+
59
+ result
60
+ end
61
+
62
+ # Get all data sources
63
+ def all(options = { client: GoodData.client })
64
+ DataSource[:all, options]
65
+ end
66
+
67
+ # Create data source from json
68
+ # Expected keys:
69
+ # - :name (mandatory)
70
+ # - :alias (optional)
71
+ # - :prefix (optional)
72
+ # - :connectionInfo (mandatory)
73
+ # - :client (mandatory)
74
+ def create(opts)
75
+ ds_name = opts[:name]
76
+ ds_alias = opts[:alias]
77
+ ds_prefix = opts[:prefix]
78
+ ds_connection_info = opts[:connectionInfo]
79
+
80
+ GoodData.logger.info "Creating data source '#{ds_name}'"
81
+ fail ArgumentError, 'Data source name has to be provided' if ds_name.nil? || ds_name.blank?
82
+ fail ArgumentError, 'Data source connection info has to be provided' if ds_connection_info.nil?
83
+
84
+ json = {
85
+ 'dataSource' => {
86
+ 'name' => ds_name,
87
+ 'connectionInfo' => ds_connection_info
88
+ }
89
+ }
90
+ json['dataSource']['alias'] = ds_alias if ds_alias
91
+ json['dataSource']['prefix'] = ds_prefix if ds_prefix
92
+
93
+ # Create data source
94
+ c = GoodData.get_client(opts)
95
+ res = c.post(DATA_SOURCES_URL, json)
96
+
97
+ # create the public facing object
98
+ c.create(DataSource, res)
99
+ end
100
+ end
101
+
102
+ # Save data source to backend. The saving will validate existing data source name and connection info. So need set
103
+ # values for them.
104
+ #
105
+ # Input info:
106
+ # - :name (mandatory)
107
+ # - :alias (optional)
108
+ # - :prefix (optional)
109
+ # - :connectionInfo (mandatory)
110
+ #
111
+ # Return: create data source in backend and return data source object corresponding with data source in backend.
112
+ def save
113
+ validate
114
+ validate_connection_info
115
+ if saved?
116
+ update_obj_json = client.put(uri, to_update_payload)
117
+ @json = update_obj_json
118
+ else
119
+ res = client.post(DATA_SOURCES_URL, to_update_payload)
120
+ fail 'Unable to create new Data Source' if res.nil?
121
+
122
+ @json = res
123
+ end
124
+ @connection_info = build_connection_info
125
+ self
126
+ end
127
+
128
+ def delete
129
+ saved? ? client.delete(uri) : nil
130
+ end
131
+
132
+ def initialize(json)
133
+ super
134
+ @json = json
135
+ validate
136
+ @connection_info = build_connection_info
137
+ end
138
+
139
+ def saved?
140
+ !uri.blank?
141
+ end
142
+
143
+ def name
144
+ @json['dataSource']['name']
145
+ end
146
+
147
+ def name=(new_name)
148
+ @json['dataSource']['name'] = new_name
149
+ end
150
+
151
+ def alias
152
+ @json['dataSource']['alias']
153
+ end
154
+
155
+ def alias=(new_alias)
156
+ @json['dataSource']['alias'] = new_alias
157
+ end
158
+
159
+ def prefix
160
+ @json['dataSource']['prefix']
161
+ end
162
+
163
+ def prefix=(new_prefix)
164
+ @json['dataSource']['prefix'] = new_prefix
165
+ end
166
+
167
+ def uri
168
+ @json['dataSource']['links']['self'] if @json && @json['dataSource'] && @json['dataSource']['links']
169
+ end
170
+
171
+ def id
172
+ uri.split('/')[-1]
173
+ end
174
+
175
+ def is(type)
176
+ @json['dataSource']['connectionInfo'][type]
177
+ end
178
+
179
+ private
180
+
181
+ def build_connection_info
182
+ return snowflake_connection_info if is(SNOWFLAKE)
183
+ return redshift_connection_info if is(REDSHIFT)
184
+ return bigquery_connection_info if is(BIGQUERY)
185
+ return generic_connection_info if is(GENERIC)
186
+ return s3_connection_info if is(S3)
187
+ return ads_connection_info if is(ADS)
188
+
189
+ # In case don't know data source type then support get or set directly json data for connection info
190
+ ConnectionInfo.new(@json['dataSource']['connectionInfo'])
191
+ end
192
+
193
+ def support_connection_info(connection_info)
194
+ [SnowflakeConnectionInfo, RedshiftConnectionInfo, BigQueryConnectionInfo,
195
+ GenericConnectionInfo, S3ConnectionInfo, AdsConnectionInfo].include? connection_info.class
196
+ end
197
+
198
+ def snowflake_connection_info
199
+ return nil unless is(SNOWFLAKE)
200
+
201
+ SnowflakeConnectionInfo.new(@json['dataSource']['connectionInfo'])
202
+ end
203
+
204
+ def redshift_connection_info
205
+ return nil unless is(REDSHIFT)
206
+
207
+ RedshiftConnectionInfo.new(@json['dataSource']['connectionInfo'])
208
+ end
209
+
210
+ def bigquery_connection_info
211
+ return nil unless is(BIGQUERY)
212
+
213
+ BigQueryConnectionInfo.new(@json['dataSource']['connectionInfo'])
214
+ end
215
+
216
+ def generic_connection_info
217
+ return nil unless is(GENERIC)
218
+
219
+ GenericConnectionInfo.new(@json['dataSource']['connectionInfo'])
220
+ end
221
+
222
+ def s3_connection_info
223
+ return nil unless is(S3)
224
+
225
+ S3ConnectionInfo.new(@json['dataSource']['connectionInfo'])
226
+ end
227
+
228
+ def ads_connection_info
229
+ return nil unless is(ADS)
230
+
231
+ AdsConnectionInfo.new(@json['dataSource']['connectionInfo'])
232
+ end
233
+
234
+ def to_update_payload
235
+ json_data = {
236
+ 'dataSource' => {
237
+ 'name' => name,
238
+ 'connectionInfo' => @connection_info.to_update_payload
239
+ }
240
+ }
241
+ json_data['dataSource']['alias'] = self.alias if self.alias
242
+ json_data['dataSource']['prefix'] = prefix if prefix
243
+ json_data
244
+ end
245
+
246
+ def validate
247
+ fail 'Invalid data source json data' unless @json['dataSource']
248
+ fail 'Data source connection info has to be provided' unless @json['dataSource']['connectionInfo']
249
+ fail 'Data source name has to be provided' if name.nil? || name.blank?
250
+ end
251
+
252
+ def validate_connection_info
253
+ @connection_info.validate
254
+ end
255
+
256
+ class ConnectionInfo < Rest::Resource
257
+ def initialize(connection_info_json)
258
+ @json = connection_info_json
259
+ end
260
+
261
+ def connection_info
262
+ @json
263
+ end
264
+
265
+ def connection_info=(connection_info_json)
266
+ @json = connection_info_json
267
+ end
268
+
269
+ def to_update_payload
270
+ @json
271
+ end
272
+
273
+ def validate
274
+ end
275
+ end
276
+
277
+ class SnowflakeConnectionInfo < ConnectionInfo
278
+ def initialize(connection_info_json)
279
+ @json = connection_info_json[GoodData::DataSource::SNOWFLAKE]
280
+ end
281
+
282
+ def url
283
+ @json['url']
284
+ end
285
+
286
+ def url=(new_url)
287
+ @json['url'] = new_url
288
+ end
289
+
290
+ def user_name
291
+ @json['authentication']['basic']['userName'] if @json && @json['authentication'] && @json['authentication']['basic']
292
+ end
293
+
294
+ def user_name=(new_user_name)
295
+ @json['authentication']['basic']['userName'] = new_user_name
296
+ end
297
+
298
+ def password
299
+ @json['authentication']['basic']['password'] if @json && @json['authentication'] && @json['authentication']['basic']
300
+ end
301
+
302
+ def password=(new_password)
303
+ @json['authentication']['basic']['password'] = new_password
304
+ end
305
+
306
+ def database
307
+ @json['database']
308
+ end
309
+
310
+ def database=(new_database)
311
+ @json['database'] = new_database
312
+ end
313
+
314
+ def schema
315
+ @json['schema']
316
+ end
317
+
318
+ def schema=(new_schema)
319
+ @json['schema'] = new_schema
320
+ end
321
+
322
+ def warehouse
323
+ @json['warehouse']
324
+ end
325
+
326
+ def warehouse=(new_warehouse)
327
+ @json['warehouse'] = new_warehouse
328
+ end
329
+
330
+ def to_update_payload
331
+ {
332
+ 'snowflake' => {
333
+ 'url' => url,
334
+ 'authentication' => {
335
+ 'basic' => {
336
+ 'userName' => user_name,
337
+ 'password' => password
338
+ }
339
+ },
340
+ 'database' => database,
341
+ 'schema' => schema,
342
+ 'warehouse' => warehouse
343
+ }
344
+ }
345
+ end
346
+
347
+ def validate
348
+ fail 'Data source url has to be provided' if url.nil? || url.blank?
349
+ fail 'Data source database has to be provided' if database.nil? || database.blank?
350
+ fail 'Data source schema has to be provided' if schema.nil? || schema.blank?
351
+ fail 'Data source warehouse has to be provided' if warehouse.nil? || warehouse.blank?
352
+ fail 'Data source username has to be provided' if user_name.nil? || user_name.blank?
353
+ end
354
+ end
355
+
356
+ class RedshiftConnectionInfo < ConnectionInfo
357
+ def initialize(connection_info_json)
358
+ @json = connection_info_json[GoodData::DataSource::REDSHIFT]
359
+ end
360
+
361
+ def url
362
+ @json['url']
363
+ end
364
+
365
+ def url=(new_url)
366
+ @json['url'] = new_url
367
+ end
368
+
369
+ def user_name
370
+ @json['authentication']['basic']['userName'] if basic_authentication
371
+ end
372
+
373
+ def user_name=(new_user_name)
374
+ @json['authentication']['basic']['userName'] = new_user_name
375
+ end
376
+
377
+ def password
378
+ @json['authentication']['basic']['password'] if basic_authentication
379
+ end
380
+
381
+ def password=(new_password)
382
+ @json['authentication']['basic']['password'] = new_password
383
+ end
384
+
385
+ def db_user
386
+ @json['authentication']['iam']['dbUser'] if iam_authentication
387
+ end
388
+
389
+ def db_user=(new_db_user)
390
+ @json['authentication']['iam']['dbUser'] = new_db_user
391
+ end
392
+
393
+ def access_key_id
394
+ @json['authentication']['iam']['accessKeyId'] if iam_authentication
395
+ end
396
+
397
+ def access_key_id=(new_access_key_id)
398
+ @json['authentication']['iam']['accessKeyId'] = new_access_key_id
399
+ end
400
+
401
+ def secret_access_key
402
+ @json['authentication']['iam']['secretAccessKey'] if iam_authentication
403
+ end
404
+
405
+ def secret_access_key=(new_secret_access_key)
406
+ @json['authentication']['iam']['secretAccessKey'] = new_secret_access_key
407
+ end
408
+
409
+ def basic_authentication
410
+ @json && @json['authentication'] && @json['authentication']['basic']
411
+ end
412
+
413
+ def iam_authentication
414
+ @json && @json['authentication'] && @json['authentication']['iam']
415
+ end
416
+
417
+ def database
418
+ @json['database']
419
+ end
420
+
421
+ def database=(new_database)
422
+ @json['database'] = new_database
423
+ end
424
+
425
+ def schema
426
+ @json['schema']
427
+ end
428
+
429
+ def schema=(new_schema)
430
+ @json['schema'] = new_schema
431
+ end
432
+
433
+ def to_update_payload
434
+ if basic_authentication
435
+ {
436
+ 'redshift' => {
437
+ 'url' => url,
438
+ 'authentication' => {
439
+ 'basic' => {
440
+ 'userName' => user_name,
441
+ 'password' => password
442
+ }
443
+ },
444
+ 'database' => database,
445
+ 'schema' => schema
446
+ }
447
+ }
448
+ else
449
+ {
450
+ 'redshift' => {
451
+ 'url' => url,
452
+ 'authentication' => {
453
+ 'iam' => {
454
+ 'dbUser' => db_user,
455
+ 'accessKeyId' => access_key_id,
456
+ 'secretAccessKey' => secret_access_key
457
+ }
458
+ },
459
+ 'database' => database,
460
+ 'schema' => schema
461
+ }
462
+ }
463
+ end
464
+ end
465
+
466
+ def validate
467
+ fail 'Data source url has to be provided' if url.nil? || url.blank?
468
+ fail 'Data source database has to be provided' if database.nil? || database.blank?
469
+ fail 'Data source schema has to be provided' if schema.nil? || schema.blank?
470
+
471
+ if basic_authentication
472
+ fail 'Data source username has to be provided' if user_name.nil? || user_name.blank?
473
+ elsif iam_authentication
474
+ fail 'Data source db_user has to be provided' if db_user.nil? || db_user.blank?
475
+ fail 'Data source access key has to be provided' if access_key_id.nil? || access_key_id.blank?
476
+ end
477
+ end
478
+ end
479
+
480
+ class BigQueryConnectionInfo < ConnectionInfo
481
+ def initialize(connection_info_json)
482
+ @json = connection_info_json[GoodData::DataSource::BIGQUERY]
483
+ end
484
+
485
+ def client_email
486
+ @json['authentication']['serviceAccount']['clientEmail'] if @json && @json['authentication'] && @json['authentication']['serviceAccount']
487
+ end
488
+
489
+ def client_email=(new_client_email)
490
+ @json['authentication']['serviceAccount']['clientEmail'] = new_client_email
491
+ end
492
+
493
+ def private_key
494
+ @json['authentication']['serviceAccount']['privateKey'] if @json && @json['authentication'] && @json['authentication']['serviceAccount']
495
+ end
496
+
497
+ def private_key=(new_private_key)
498
+ @json['authentication']['serviceAccount']['privateKey'] = new_private_key
499
+ end
500
+
501
+ def project
502
+ @json['project']
503
+ end
504
+
505
+ def project=(new_project)
506
+ @json['project'] = new_project
507
+ end
508
+
509
+ def schema
510
+ @json['schema']
511
+ end
512
+
513
+ def schema=(new_schema)
514
+ @json['schema'] = new_schema
515
+ end
516
+
517
+ def to_update_payload
518
+ {
519
+ 'bigQuery' => {
520
+ 'authentication' => {
521
+ 'serviceAccount' => {
522
+ 'clientEmail' => client_email,
523
+ 'privateKey' => private_key
524
+ }
525
+ },
526
+ 'project' => project,
527
+ 'schema' => schema
528
+ }
529
+ }
530
+ end
531
+
532
+ def validate
533
+ fail 'Data source client email has to be provided' if client_email.nil? || client_email.blank?
534
+ fail 'Data source project has to be provided' if project.nil? || project.blank?
535
+ fail 'Data source schema has to be provided' if schema.nil? || schema.blank?
536
+ end
537
+ end
538
+
539
+ class GenericConnectionInfo < ConnectionInfo
540
+ def initialize(connection_info_json)
541
+ @json = connection_info_json[GoodData::DataSource::GENERIC]
542
+ end
543
+
544
+ def params
545
+ @json['params']
546
+ end
547
+
548
+ def params=(new_params)
549
+ @json['params'] = new_params
550
+ end
551
+
552
+ def secure_params
553
+ @json['secureParams']
554
+ end
555
+
556
+ def secure_params=(new_secure_params)
557
+ @json['secureParams'] = new_secure_params
558
+ end
559
+
560
+ def to_update_payload
561
+ {
562
+ 'generic' => {
563
+ 'params' => params,
564
+ 'secureParams' => secure_params
565
+ }
566
+ }
567
+ end
568
+
569
+ def validate
570
+ end
571
+ end
572
+
573
+ class S3ConnectionInfo < ConnectionInfo
574
+ def initialize(connection_info_json)
575
+ @json = connection_info_json[GoodData::DataSource::S3]
576
+ end
577
+
578
+ def bucket
579
+ @json['bucket']
580
+ end
581
+
582
+ def bucket=(new_bucket)
583
+ @json['bucket'] = new_bucket
584
+ end
585
+
586
+ def access_key
587
+ @json['accessKey']
588
+ end
589
+
590
+ def access_key=(new_access_key)
591
+ @json['accessKey'] = new_access_key
592
+ end
593
+
594
+ def secret_key
595
+ @json['secretKey']
596
+ end
597
+
598
+ def secret_key=(new_secret_key)
599
+ @json['secretKey'] = new_secret_key
600
+ end
601
+
602
+ def server_side_encryption
603
+ @json['serverSideEncryption']
604
+ end
605
+
606
+ def server_side_encryption=(new_server_side_encryption)
607
+ @json['serverSideEncryption'] = new_server_side_encryption
608
+ end
609
+
610
+ def to_update_payload
611
+ {
612
+ 's3' => {
613
+ 'bucket' => bucket,
614
+ 'accessKey' => access_key,
615
+ 'secretKey' => secret_key,
616
+ 'serverSideEncryption' => server_side_encryption
617
+ }
618
+ }
619
+ end
620
+
621
+ def validate
622
+ fail 'S3 bucket has to be provided' if bucket.nil? || bucket.blank?
623
+ fail 'S3 access key has to be provided' if access_key.nil? || access_key.blank?
624
+ end
625
+ end
626
+
627
+ class AdsConnectionInfo < ConnectionInfo
628
+ def initialize(connection_info_json)
629
+ @json = connection_info_json[GoodData::DataSource::ADS]
630
+ end
631
+
632
+ def instance
633
+ @json['instance']
634
+ end
635
+
636
+ def instance=(new_instance)
637
+ @json['instance'] = new_instance
638
+ end
639
+
640
+ def exportable
641
+ @json['exportable']
642
+ end
643
+
644
+ def exportable=(new_exportable)
645
+ @json['exportable'] = new_exportable
646
+ end
647
+
648
+ def to_update_payload
649
+ {
650
+ 'ads' => {
651
+ 'instance' => instance,
652
+ 'exportable' => exportable
653
+ }
654
+ }
655
+ end
656
+
657
+ def validate
658
+ fail 'Data source instance has to be provided' if instance.nil? || instance.blank?
659
+ end
660
+ end
661
+ end
662
+ end