gooddata 0.6.53 → 0.6.54

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.
Files changed (139) hide show
  1. checksums.yaml +5 -5
  2. data/.flayignore +6 -0
  3. data/.gitignore +1 -0
  4. data/.pronto.yml +3 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +4 -1
  7. data/CHANGELOG.md +18 -0
  8. data/CONTRIBUTING.md +14 -1
  9. data/DEPENDENCIES.md +324 -253
  10. data/Dockerfile.jruby +5 -7
  11. data/Dockerfile.ruby +8 -8
  12. data/Rakefile +24 -0
  13. data/ci.rake +47 -0
  14. data/docker-compose.yml +34 -0
  15. data/gooddata.gemspec +8 -2
  16. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +0 -3
  17. data/lib/gooddata/helpers/data_helper.rb +10 -7
  18. data/lib/gooddata/helpers/global_helpers_params.rb +8 -3
  19. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +2 -1
  20. data/lib/gooddata/lcm/actions/associate_clients.rb +10 -1
  21. data/lib/gooddata/lcm/actions/collect_client_projects.rb +78 -0
  22. data/lib/gooddata/lcm/actions/collect_clients.rb +20 -6
  23. data/lib/gooddata/lcm/actions/collect_data_product.rb +62 -0
  24. data/lib/gooddata/lcm/actions/collect_dynamic_schedule_params.rb +62 -0
  25. data/lib/gooddata/lcm/actions/{collect_attrs.rb → collect_ldm_objects.rb} +3 -3
  26. data/lib/gooddata/lcm/actions/collect_meta.rb +6 -3
  27. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +2 -1
  28. data/lib/gooddata/lcm/actions/collect_segments.rb +6 -7
  29. data/lib/gooddata/lcm/actions/collect_tagged_objects.rb +7 -4
  30. data/lib/gooddata/lcm/actions/create_segment_masters.rb +7 -3
  31. data/lib/gooddata/lcm/actions/ensure_data_product.rb +53 -0
  32. data/lib/gooddata/lcm/actions/ensure_technical_users_domain.rb +6 -2
  33. data/lib/gooddata/lcm/actions/ensure_technical_users_project.rb +30 -18
  34. data/lib/gooddata/lcm/actions/execute_schedules.rb +128 -0
  35. data/lib/gooddata/lcm/actions/provision_clients.rb +32 -21
  36. data/lib/gooddata/lcm/actions/purge_clients.rb +25 -39
  37. data/lib/gooddata/lcm/actions/rename_existing_client_projects.rb +70 -0
  38. data/lib/gooddata/lcm/actions/segments_filter.rb +6 -0
  39. data/lib/gooddata/lcm/actions/synchronize_cas.rb +11 -0
  40. data/lib/gooddata/lcm/actions/synchronize_clients.rb +2 -1
  41. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +34 -15
  42. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +10 -1
  43. data/lib/gooddata/lcm/actions/synchronize_new_segments.rb +2 -1
  44. data/lib/gooddata/lcm/actions/synchronize_processes.rb +4 -7
  45. data/lib/gooddata/lcm/actions/synchronize_tag_objects.rb +8 -5
  46. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +224 -0
  47. data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +53 -0
  48. data/lib/gooddata/lcm/actions/synchronize_users.rb +324 -0
  49. data/lib/gooddata/lcm/dsl/type_dsl.rb +1 -0
  50. data/lib/gooddata/lcm/helpers/check_helper.rb +4 -0
  51. data/lib/gooddata/lcm/helpers/tags_helper.rb +4 -3
  52. data/lib/gooddata/lcm/lcm2.rb +33 -1
  53. data/lib/gooddata/lcm/types/complex/segment.rb +3 -0
  54. data/lib/gooddata/lcm/types/complex/update_preference.rb +8 -2
  55. data/lib/gooddata/lcm/types/special/array.rb +1 -3
  56. data/lib/gooddata/lcm/types/special/enum.rb +1 -3
  57. data/lib/gooddata/mixins/md_id_to_uri.rb +0 -1
  58. data/lib/gooddata/mixins/md_json.rb +2 -2
  59. data/lib/gooddata/models/blueprint/project_blueprint.rb +15 -0
  60. data/lib/gooddata/models/blueprint/to_wire.rb +1 -0
  61. data/lib/gooddata/models/client.rb +21 -9
  62. data/lib/gooddata/models/data_product.rb +149 -0
  63. data/lib/gooddata/models/domain.rb +26 -72
  64. data/lib/gooddata/models/from_wire.rb +2 -0
  65. data/lib/gooddata/models/metadata/report.rb +9 -3
  66. data/lib/gooddata/models/metadata/report_definition.rb +2 -2
  67. data/lib/gooddata/models/model.rb +1 -1
  68. data/lib/gooddata/models/process.rb +4 -0
  69. data/lib/gooddata/models/project.rb +58 -35
  70. data/lib/gooddata/models/project_creator.rb +13 -0
  71. data/lib/gooddata/models/segment.rb +63 -16
  72. data/lib/gooddata/models/style_setting.rb +2 -15
  73. data/lib/gooddata/models/user_group.rb +2 -0
  74. data/lib/gooddata/rest/connection.rb +32 -9
  75. data/lib/gooddata/rest/object_factory.rb +0 -25
  76. data/lib/gooddata/version.rb +1 -1
  77. data/spec/data/blueprints/invalid_blueprint.json +2 -2
  78. data/spec/data/blueprints/test_project_model_spec.json +1 -1
  79. data/spec/data/dynamic_schedule_params_table.csv +7 -0
  80. data/spec/data/workspace_table.csv +3 -3
  81. data/spec/environment/staging.rb +3 -3
  82. data/spec/integration/ads_output_stage_spec.rb +0 -10
  83. data/spec/integration/clients_spec.rb +1 -1
  84. data/spec/{unit → integration}/commands/command_projects_spec.rb +0 -0
  85. data/spec/{unit → integration}/core/connection_spec.rb +0 -0
  86. data/spec/{unit → integration}/core/logging_spec.rb +0 -0
  87. data/spec/{unit → integration}/core/project_spec.rb +0 -0
  88. data/spec/integration/date_dim_switch_spec.rb +13 -0
  89. data/spec/integration/full_process_schedule_spec.rb +2 -2
  90. data/spec/integration/helpers_spec.rb +16 -0
  91. data/spec/integration/lcm_spec.rb +12 -2
  92. data/spec/integration/mixins/id_to_uri_spec.rb +44 -0
  93. data/spec/integration/models/data_product_spec.rb +71 -0
  94. data/spec/{unit → integration}/models/domain_spec.rb +2 -2
  95. data/spec/{unit → integration}/models/invitation_spec.rb +0 -0
  96. data/spec/{unit → integration}/models/membership_spec.rb +0 -0
  97. data/spec/{unit → integration}/models/params_spec.rb +0 -0
  98. data/spec/{unit → integration}/models/profile_spec.rb +0 -0
  99. data/spec/{unit → integration}/models/project_role_spec.rb +0 -0
  100. data/spec/integration/models/project_spec.rb +225 -0
  101. data/spec/{unit → integration}/models/schedule_spec.rb +0 -0
  102. data/spec/{unit → integration}/models/unit_project_spec.rb +0 -0
  103. data/spec/integration/project_spec.rb +40 -5
  104. data/spec/integration/segments_spec.rb +27 -26
  105. data/spec/integration/user_filters_spec.rb +1 -1
  106. data/spec/spec_helper.rb +15 -19
  107. data/spec/unit/actions/associate_clients_spec.rb +47 -0
  108. data/spec/unit/actions/collect_client_projects_spec.rb +47 -0
  109. data/spec/unit/actions/collect_clients_spec.rb +27 -0
  110. data/spec/unit/actions/collect_data_product_spec.rb +64 -0
  111. data/spec/unit/actions/collect_dynamic_schedule_params_spec.rb +56 -0
  112. data/spec/unit/actions/collect_meta_spec.rb +4 -4
  113. data/spec/unit/actions/collect_segment_clients_spec.rb +44 -3
  114. data/spec/unit/actions/collect_tagged_objects_spec.rb +20 -4
  115. data/spec/unit/actions/create_segment_masters_spec.rb +64 -0
  116. data/spec/unit/actions/ensure_data_product_spec.rb +38 -0
  117. data/spec/unit/actions/ensure_technical_users_domain_spec.rb +51 -0
  118. data/spec/unit/actions/ensure_technical_users_project_spec.rb +72 -0
  119. data/spec/unit/actions/execute_schedules_spec.rb +94 -0
  120. data/spec/unit/actions/provision_clients_spec.rb +45 -0
  121. data/spec/unit/actions/purge_clients_spec.rb +47 -0
  122. data/spec/unit/actions/rename_existing_client_projects_spec.rb +54 -0
  123. data/spec/unit/actions/segments_filter_spec.rb +46 -0
  124. data/spec/unit/actions/shared_examples_for_user_actions.rb +10 -0
  125. data/spec/unit/actions/synchronize_cas_spec.rb +58 -0
  126. data/spec/unit/actions/synchronize_etls_in_segment_spec.rb +174 -13
  127. data/spec/unit/actions/synchronize_ldm_spec.rb +57 -0
  128. data/spec/unit/actions/synchronize_user_filters_spec.rb +142 -0
  129. data/spec/unit/actions/synchronize_user_groups_spec.rb +49 -0
  130. data/spec/unit/actions/synchronize_users_spec.rb +76 -0
  131. data/spec/unit/helpers/data_helper_spec.rb +17 -0
  132. data/spec/unit/helpers/global_helpers_spec.rb +16 -0
  133. data/spec/unit/helpers_spec.rb +0 -6
  134. data/spec/unit/models/blueprint/project_blueprint_spec.rb +21 -4
  135. data/spec/unit/models/project_creator_spec.rb +16 -0
  136. data/spec/unit/models/project_spec.rb +66 -197
  137. metadata +202 -100
  138. data/PULL_REQUEST_TEMPLATE.md +0 -5
  139. data/lib/gooddata/bricks/middleware/params_inspect_middleware.rb +0 -21
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative 'base_action'
8
+
9
+ module GoodData
10
+ module LCM2
11
+ class CollectDataProduct < BaseAction
12
+ DESCRIPTION = 'Collect DataProduct to be used in the actions'
13
+
14
+ PARAMS = define_params(self) do
15
+ description 'Client Used for Connecting to GD'
16
+ param :gdc_gd_client, instance_of(Type::GdClientType), required: true
17
+
18
+ description 'DataProduct to manage'
19
+ param :data_product, instance_of(Type::StringType), required: false
20
+ end
21
+
22
+ RESULT_HEADER = [
23
+ :data_product
24
+ ]
25
+
26
+ class << self
27
+ def call(params)
28
+ params = params.to_hash
29
+ client = params.gdc_gd_client
30
+ domain_name = params.organization || params.domain
31
+ domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
32
+
33
+ if params.key?(:data_product)
34
+ begin
35
+ data_product = domain.data_products(params.data_product)
36
+ rescue RestClient::BadRequest
37
+ fail 'the specified DataProduct does not exist'
38
+ end
39
+ else
40
+ params.gdc_logger.info 'Please specify the data_product parameter when using the brick - trying to find a fallback'
41
+ data_products = domain.data_products(:all)
42
+ fail 'No data_product parameter specified - unable to fallback to a default' if data_products.length > 1 || data_products.empty?
43
+ data_product = data_products.first
44
+ end
45
+
46
+ results = [
47
+ {
48
+ data_product: data_product
49
+ }
50
+ ]
51
+
52
+ {
53
+ results: results,
54
+ params: {
55
+ data_product: data_product
56
+ }
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative 'base_action'
8
+
9
+ module GoodData
10
+ module LCM2
11
+ class CollectDymanicScheduleParams < BaseAction
12
+ DESCRIPTION = 'Collect Dynamic Schedule Params'
13
+
14
+ PARAMS = define_params(self) do
15
+ description 'Schedule Title Column'
16
+ param :schedule_title_column, instance_of(Type::StringType), required: false
17
+
18
+ description 'Dynamic Params'
19
+ param :dynamic_params, instance_of(Type::HashType), required: false
20
+ end
21
+
22
+ class << self
23
+ def call(params)
24
+ return [] unless params.dynamic_params
25
+
26
+ schedule_title_column = params.schedule_title_column || 'schedule_title'
27
+ client_id_column = params.client_id_column || 'client_id'
28
+ param_name_column = params.param_name_column || 'param_name'
29
+ param_value_column = params.param_value_column || 'param_value'
30
+ results = []
31
+
32
+ input_source = params.dynamic_params.input_source
33
+ data_source = GoodData::Helpers::DataSource.new(input_source)
34
+ input_data = File.open(data_source.realize(params), 'r:UTF-8')
35
+ GoodData.logger.debug("Input data: #{input_data.read}")
36
+
37
+ schedule_params = {}
38
+
39
+ CSV.foreach(input_data, :headers => true, :return_headers => false, encoding: 'utf-8') do |row|
40
+ GoodData.logger.debug("Processing row: #{row}")
41
+ results << row.to_hash
42
+
43
+ client_id = row[client_id_column] ? row[client_id_column] : :all_clients
44
+ schedule_name = row[schedule_title_column] ? row[schedule_title_column] : :all_schedules
45
+
46
+ schedule_params[client_id] ||= {}
47
+ schedule_params[client_id][schedule_name] ||= {}
48
+
49
+ schedule_params[client_id][schedule_name].merge!(row[param_name_column] => row[param_value_column])
50
+ end
51
+
52
+ {
53
+ results: results,
54
+ params: {
55
+ schedule_params: schedule_params
56
+ }
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -8,8 +8,8 @@ require_relative 'base_action'
8
8
 
9
9
  module GoodData
10
10
  module LCM2
11
- class CollectAttributes < BaseAction
12
- DESCRIPTION = "Collect all attributes (include CAs) to transfer label type and drill path"
11
+ class CollectLdmObjects < BaseAction
12
+ DESCRIPTION = "Collect all objects in LDM: attributes (include CAs), facts, datasets"
13
13
 
14
14
  PARAMS = define_params(self) do
15
15
  description 'Development Client Used for Connecting to GD'
@@ -28,7 +28,7 @@ module GoodData
28
28
  synchronize = params.synchronize.pmap do |info|
29
29
  from = info.from
30
30
  from_project = development_client.projects(from) || fail("Invalid 'from' project specified - '#{from}'")
31
- objects = (from_project.attributes.to_a + from_project.labels.to_a).map(&:uri)
31
+ objects = (from_project.attributes.to_a + from_project.labels.to_a + from_project.datasets.to_a + from_project.facts.to_a).map(&:uri)
32
32
 
33
33
  info[:transfer_uris] ||= []
34
34
  info[:transfer_uris] += objects
@@ -13,8 +13,11 @@ module GoodData
13
13
  with objects inside dashboards (reports, metrics ...) from development projects"
14
14
 
15
15
  PARAMS = define_params(self) do
16
- description 'Production Tag Name'
17
- param :production_tag, instance_of(Type::StringType), required: false
16
+ description 'Production Tag Names'
17
+ param :production_tags, array_of(instance_of(Type::StringType)), required: false
18
+
19
+ description 'Production Tag Names'
20
+ param :production_tag, instance_of(Type::StringType), required: false, deprecated: true, replacement: :production_tags
18
21
 
19
22
  description 'Development Client Used for Connecting to GD'
20
23
  param :development_client, instance_of(Type::GdClientType), required: true
@@ -42,7 +45,7 @@ module GoodData
42
45
  from_project = development_client.projects(from) || fail("Invalid 'from' project specified - '#{from}'")
43
46
 
44
47
  segment_tags = segments_to_tags[info.segment]
45
- production_tags = Helpers.parse_production_tags(params.production_tag, segment_tags)
48
+ production_tags = Helpers.parse_production_tags(params.production_tags || params.production_tag, segment_tags)
46
49
 
47
50
  if transfer_all || production_tags.empty?
48
51
  old_dashboards = GoodData::Dashboard.all(
@@ -43,7 +43,8 @@ module GoodData
43
43
 
44
44
  domain_name = params.organization || params.domain
45
45
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
46
- domain_segments = domain.segments
46
+ data_product = params.data_product
47
+ domain_segments = domain.segments(:all, data_product)
47
48
 
48
49
  segments = params.segments.map do |seg|
49
50
  domain_segments.find do |s|
@@ -24,19 +24,18 @@ module GoodData
24
24
 
25
25
  class << self
26
26
  def call(params)
27
- client = params.gdc_gd_client
28
-
29
- domain_name = params.organization || params.domain
30
- domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
31
- domain_segments = domain.segments
27
+ data_product = params.data_product
28
+ data_product_segments = data_product.segments
29
+ params.gdc_logger.info("Domain segments: #{data_product_segments}")
32
30
 
33
31
  if params.segments_filter
34
- domain_segments.select! do |segment|
32
+ params.gdc_logger.info("Segments filter: #{params.segments_filter}")
33
+ data_product_segments.select! do |segment|
35
34
  params.segments_filter.include?(segment.segment_id)
36
35
  end
37
36
  end
38
37
 
39
- segments = domain_segments.pmap do |segment|
38
+ segments = data_product_segments.pmap do |segment|
40
39
  project = nil
41
40
 
42
41
  begin
@@ -19,8 +19,11 @@ module GoodData
19
19
  description 'Synchronization Info'
20
20
  param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
21
21
 
22
- description 'Tag Name'
23
- param :production_tag, instance_of(Type::StringType), required: false
22
+ description 'Production Tag Names'
23
+ param :production_tags, array_of(instance_of(Type::StringType)), required: false
24
+
25
+ description 'Production Tag Names'
26
+ param :production_tag, instance_of(Type::StringType), required: false, deprecated: true, replacement: :production_tags
24
27
 
25
28
  description 'Segments to search for segment-specific production tags'
26
29
  param :segments, array_of(instance_of(Type::SegmentType)), required: false
@@ -34,7 +37,7 @@ module GoodData
34
37
  results = []
35
38
  segments_to_tags = Helpers.segment_production_tags(params.segments)
36
39
  transfer_all = GoodData::Helpers.to_boolean(params.transfer_all)
37
- return results unless params.production_tag || segments_to_tags.any? || transfer_all
40
+ return results unless params.production_tags || params.production_tag || segments_to_tags.any? || transfer_all
38
41
  development_client = params.development_client
39
42
 
40
43
  synchronize = params.synchronize.pmap do |info|
@@ -42,7 +45,7 @@ module GoodData
42
45
  from_project = development_client.projects(from) || fail("Invalid 'from' project specified - '#{from}'")
43
46
 
44
47
  segment_tags = segments_to_tags[info.segment]
45
- production_tags = Helpers.parse_production_tags(params.production_tag, segment_tags)
48
+ production_tags = Helpers.parse_production_tags(params.production_tags || params.production_tag, segment_tags)
46
49
  objects = []
47
50
  if transfer_all
48
51
  vizs = MdObject.query('visualization', MdObject, client: development_client, project: from_project)
@@ -32,6 +32,9 @@ module GoodData
32
32
 
33
33
  description 'Table Name'
34
34
  param :release_table_name, instance_of(Type::StringType), required: false
35
+
36
+ description 'Project Environment'
37
+ param :project_environment, instance_of(Type::StringType), required: false
35
38
  end
36
39
 
37
40
  DEFAULT_TABLE_NAME = 'LCM_RELEASE'
@@ -45,7 +48,8 @@ module GoodData
45
48
 
46
49
  domain_name = params.organization || params.domain
47
50
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
48
- domain_segments = domain.segments
51
+ data_product = params.data_product
52
+ domain_segments = domain.segments(:all, data_product)
49
53
 
50
54
  # TODO: Support for 'per segment' provisioning
51
55
  segments = params.segments
@@ -71,7 +75,7 @@ module GoodData
71
75
 
72
76
  # Create new master project
73
77
  params.gdc_logger.info "Creating master project - name: '#{master_name}' development_project: '#{development_pid}', segment: '#{segment_id}', driver: '#{driver}'"
74
- project = client.create_project(title: master_name, auth_token: token, driver: driver == 'vertica' ? 'vertica' : 'Pg')
78
+ project = client.create_project(title: master_name, auth_token: token, driver: driver == 'vertica' ? 'vertica' : 'Pg', environment: params.project_environment)
75
79
 
76
80
  # Does segment exists? If not, create new one and set initial master
77
81
  if segment
@@ -79,7 +83,7 @@ module GoodData
79
83
  status = 'untouched'
80
84
  else
81
85
  params.gdc_logger.info "Creating segment #{segment_id}, master #{project.pid}"
82
- segment = domain.create_segment(segment_id: segment_id, master_project: project)
86
+ segment = data_product.create_segment(segment_id: segment_id, master_project: project)
83
87
  segment.synchronize_clients
84
88
  segment_in[:is_new] = true
85
89
  status = 'created'
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative 'base_action'
8
+
9
+ module GoodData
10
+ module LCM2
11
+ class EnsureDataProduct < BaseAction
12
+ DESCRIPTION = 'Creates the DataProduct if it does not exist yet'
13
+
14
+ PARAMS = define_params(self) do
15
+ description 'client to connect to GD'
16
+ param :gdc_gd_client, instance_of(Type::GdClientType), required: true
17
+
18
+ description 'DataProduct to ensure'
19
+ param :data_product, instance_of(Type::StringType), required: false
20
+ end
21
+
22
+ RESULT_HEADER = [
23
+ :data_product
24
+ ]
25
+
26
+ class << self
27
+ def call(params)
28
+ params = params.to_hash
29
+ client = params.gdc_gd_client
30
+ domain_name = params.organization || params.domain
31
+ domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
32
+
33
+ if params.key?(:data_product)
34
+ begin
35
+ data_product = domain.data_products(params.data_product)
36
+ rescue RestClient::BadRequest
37
+ params.gdc_logger.info "Can not find DataProduct #{params.data_product}, creating it instead"
38
+ data_product = domain.create_data_product(id: params.data_product)
39
+ end
40
+ end
41
+
42
+ {
43
+ results: [
44
+ {
45
+ data_product: data_product
46
+ }
47
+ ]
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -19,7 +19,11 @@ module GoodData
19
19
  param :organization, instance_of(Type::StringType), required: true
20
20
 
21
21
  description 'Technical users'
22
- param :technical_user, array_of(instance_of(Type::StringType)), required: false
22
+ param :technical_user, array_of(instance_of(Type::StringType)),
23
+ required: false, deprecated: true, replacement: :technical_users
24
+
25
+ description 'Technical users'
26
+ param :technical_users, array_of(instance_of(Type::StringType)), required: false
23
27
  end
24
28
 
25
29
  RESULT_HEADER = [
@@ -36,7 +40,7 @@ module GoodData
36
40
  domain_name = params.organization || params.domain
37
41
  domain = client.domain(domain_name) || fail("Invalid domain name specified - #{domain_name}")
38
42
 
39
- technical_users = (params.technical_user || []).uniq
43
+ technical_users = (params.technical_users || params.technical_user || []).uniq
40
44
  technical_users.pmap do |technical_user|
41
45
  domain_user = domain.users.find do |du|
42
46
  du.login == technical_user
@@ -16,7 +16,11 @@ module GoodData
16
16
  param :gdc_gd_client, instance_of(Type::GdClientType), required: true
17
17
 
18
18
  description 'Technical users'
19
- param :technical_user, array_of(instance_of(Type::StringType)), required: false
19
+ param :technical_user, array_of(instance_of(Type::StringType)),
20
+ required: false, deprecated: true, replacement: :technical_users
21
+
22
+ description 'Technical users'
23
+ param :technical_users, array_of(instance_of(Type::StringType)), required: false
20
24
 
21
25
  description 'Synchronization Info'
22
26
  param :synchronize, array_of(instance_of(Type::SynchronizationInfoType)), required: true, generated: true
@@ -36,7 +40,7 @@ module GoodData
36
40
  def call(params)
37
41
  client = params.gdc_gd_client
38
42
 
39
- technical_users = params.technical_user || []
43
+ technical_users = params.technical_users || params.technical_user || []
40
44
  new_users = technical_users.map do |technical_user|
41
45
  {
42
46
  login: technical_user,
@@ -46,24 +50,32 @@ module GoodData
46
50
 
47
51
  results = params.synchronize.pmap do |synchronize_info|
48
52
  synchronize_info[:to].pmap do |entry|
49
- project = client.projects(entry[:pid])
50
- res = project.create_users(new_users)
51
-
52
- new_users.zip(res).map do |f, s|
53
- {
54
- project: project.title,
55
- pid: project.pid,
56
- login: f[:login],
57
- role: f[:role],
58
- result: s[:type],
59
- message: s[:message],
60
- url: s[:user]
61
- }
62
- end
53
+ ensure_users(client, entry[:pid], new_users)
63
54
  end
64
- end
55
+ end.flatten
56
+
57
+ results += params.clients.pmap { |input_client| input_client[:project] }.compact.pmap { |pid| ensure_users(client, pid, new_users) }.flatten if params.clients
58
+
59
+ results
60
+ end
61
+
62
+ private
63
+
64
+ def ensure_users(client, project_id, new_users)
65
+ project = client.projects(project_id)
66
+ res = project.create_users(new_users)
65
67
 
66
- results.flatten
68
+ new_users.zip(res).map do |f, s|
69
+ {
70
+ project: project.title,
71
+ pid: project.pid,
72
+ login: f[:login],
73
+ role: f[:role],
74
+ result: s[:type],
75
+ message: s[:message],
76
+ url: s[:user]
77
+ }
78
+ end
67
79
  end
68
80
  end
69
81
  end
@@ -0,0 +1,128 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright (c) 2010-2017 GoodData Corporation. All rights reserved.
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ require_relative 'base_action'
8
+
9
+ module GoodData
10
+ module LCM2
11
+ class ExecuteSchedules < BaseAction
12
+ DESCRIPTION = 'Execute schedules'
13
+
14
+ PARAMS = define_params(self) do
15
+ description 'Client Used for Connecting to GD'
16
+ param :gdc_gd_client, instance_of(Type::GdClientType), required: true
17
+
18
+ description 'List Of Modes'
19
+ param :list_of_modes, instance_of(Type::StringType), required: true
20
+
21
+ description 'Work Done Identificator'
22
+ param :work_done_identificator, instance_of(Type::StringType), required: true
23
+
24
+ description 'Number Of Schedules In Batch'
25
+ param :number_of_schedules_in_batch, instance_of(Type::StringType), required: false, default: '1000'
26
+
27
+ description 'Delay Between Batches'
28
+ param :delay_between_batches, instance_of(Type::StringType), required: false, default: '0'
29
+
30
+ description 'Control Parameter'
31
+ param :control_parameter, instance_of(Type::StringType), required: false, default: 'MODE'
32
+
33
+ description 'Wait For Schedule'
34
+ param :wait_for_schedule, instance_of(Type::StringType), required: false, default: 'false'
35
+
36
+ description 'Segment List'
37
+ param :segment_list, instance_of(Type::StringType), required: false
38
+
39
+ description 'Domain'
40
+ param :domain, instance_of(Type::StringType), required: false
41
+
42
+ description 'Number Of Threads'
43
+ param :number_of_threads, instance_of(Type::StringType), required: false, default: '5'
44
+ end
45
+
46
+ class << self
47
+ def call(params)
48
+ logger = params.gdc_logger
49
+
50
+ client = params.gdc_gd_client
51
+ project = client.projects(params.gdc_project) || client.projects(params.gdc_project_id)
52
+
53
+ list_of_modes = params.list_of_modes.split('|').map(&:strip)
54
+ work_done_identificator = params.work_done_identificator
55
+ number_of_schedules_in_batch = Integer(params.number_of_schedules_in_batch || "1000")
56
+ delay_between_batches = Integer(params.delay_between_batches || "0")
57
+ control_parameter = params.control_parameter || "MODE"
58
+ wait = GoodData::Helpers.to_boolean(params.wait_for_schedule)
59
+
60
+ segment_list = params.segment_list
61
+ domain_name = params.domain
62
+ fail "In case that you are using SEGMENT_LIST parameter, you need to fill out DOMAIN parameter" if !segment_list.nil? && domain_name.nil?
63
+
64
+ number_of_threads = Integer(params.number_of_threads || '5')
65
+
66
+ # The WORK_DONE_IDENTIFICATOR is flag which tells the executor to execute the schedules
67
+ # It could have special value IGNORE. In this case all corresponding schedules will be started during every run of this brick
68
+
69
+ start_schedules = work_done_identificator == 'IGNORE' || GoodData::Helpers.to_boolean(project.metadata[work_done_identificator])
70
+
71
+ project_list = []
72
+ if !segment_list.nil? && segment_list != ''
73
+ domain = client.domain(domain_name)
74
+ segment_list.split('|').each do |segment_identification|
75
+ segment = domain.segments(segment_identification)
76
+ project_list += segment.clients.map { |c| !c.project.nil? ? c.project.obj_id : nil }.compact
77
+ end
78
+ project_list.uniq!
79
+ end
80
+
81
+ if start_schedules
82
+ schedules_to_filter = client.projects.pmapcat do |p|
83
+ begin
84
+ p.schedules
85
+ rescue => e
86
+ logger.info "The retrieval of project schedules, for project #{p.obj_id} has failed. Message: #{e.message}."
87
+ []
88
+ end
89
+ end
90
+
91
+ schedules_to_start = schedules_to_filter.select { |schedule| list_of_modes.include?(schedule.params[control_parameter]) }
92
+
93
+ if !segment_list.nil? && segment_list != ''
94
+ schedules_to_start.delete_if { |schedule| !project_list.include?(schedule.project.obj_id) }
95
+ end
96
+
97
+ logger.info "Found #{schedules_to_start.count} schedules to execute"
98
+
99
+ schedules_to_start.each_slice(number_of_schedules_in_batch).each_with_index do |batch_schedules, batch_index|
100
+ batch_number = batch_index + 1
101
+ logger.info "Starting batch number #{batch_number}. Number of schedules in batch #{batch_schedules.count}."
102
+ batch_schedules.peach(number_of_threads) do |schedule|
103
+ begin
104
+ tries ||= 5
105
+ logger.info "Starting schedule for project #{schedule.project.pid} - #{schedule.project.title}. Schedule ID is #{schedule.obj_id}"
106
+ schedule.execute(wait: wait)
107
+ rescue => e
108
+ if (tries -= 1) > 0
109
+ logger.warn "There was error during operation: #{e.message}. Retrying"
110
+ sleep(5)
111
+ retry
112
+ else
113
+ logger.info "We could not start schedule for project #{schedule.project.pid} - #{schedule.project.title} - #{e.message}"
114
+ end
115
+ else
116
+ logger.info "Operation finished"
117
+ end
118
+ end
119
+ logger.info "Entering sleep mode for #{delay_between_batches} seconds"
120
+ sleep(delay_between_batches)
121
+ end
122
+ project.set_metadata(work_done_identificator, 'false') unless work_done_identificator == 'IGNORE'
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end