gooddata 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (517) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.editorconfig +12 -0
  4. data/.flayignore +6 -0
  5. data/.gitignore +38 -0
  6. data/.pronto.yml +3 -0
  7. data/.rspec +5 -0
  8. data/.rubocop.yml +101 -0
  9. data/.travis.yml +9 -0
  10. data/.yardopts +22 -0
  11. data/CHANGELOG.md +272 -0
  12. data/CLI.md +435 -0
  13. data/CONTRIBUTING.md +38 -0
  14. data/DEPENDENCIES.md +880 -0
  15. data/Dockerfile.jruby +17 -0
  16. data/Dockerfile.ruby +19 -0
  17. data/Gemfile +4 -0
  18. data/Guardfile +5 -0
  19. data/LICENSE +22 -0
  20. data/LICENSE.rb +5 -0
  21. data/README.md +78 -0
  22. data/Rakefile +204 -0
  23. data/TODO.md +32 -0
  24. data/authors.sh +4 -0
  25. data/bin/gooddata +7 -0
  26. data/ci.rake +47 -0
  27. data/dependency_decisions.yml +104 -0
  28. data/docker-compose.yml +34 -0
  29. data/gooddata +9 -0
  30. data/gooddata.gemspec +72 -0
  31. data/lib/gooddata.rb +34 -0
  32. data/lib/gooddata/app/app.rb +16 -0
  33. data/lib/gooddata/bricks/base_downloader.rb +86 -0
  34. data/lib/gooddata/bricks/brick.rb +37 -0
  35. data/lib/gooddata/bricks/bricks.rb +17 -0
  36. data/lib/gooddata/bricks/middleware/aws_middleware.rb +41 -0
  37. data/lib/gooddata/bricks/middleware/base_middleware.rb +57 -0
  38. data/lib/gooddata/bricks/middleware/bench_middleware.rb +25 -0
  39. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +37 -0
  40. data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +21 -0
  41. data/lib/gooddata/bricks/middleware/dwh_middleware.rb +41 -0
  42. data/lib/gooddata/bricks/middleware/fs_download_middleware.rb +48 -0
  43. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +36 -0
  44. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +112 -0
  45. data/lib/gooddata/bricks/middleware/logger_middleware.rb +33 -0
  46. data/lib/gooddata/bricks/middleware/middleware.rb +12 -0
  47. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +58 -0
  48. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +23 -0
  49. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +29 -0
  50. data/lib/gooddata/bricks/middleware/undot_params_middleware.rb +37 -0
  51. data/lib/gooddata/bricks/pipeline.rb +25 -0
  52. data/lib/gooddata/bricks/utils.rb +18 -0
  53. data/lib/gooddata/cli/cli.rb +27 -0
  54. data/lib/gooddata/cli/commands/auth_cmd.rb +29 -0
  55. data/lib/gooddata/cli/commands/domain_cmd.rb +28 -0
  56. data/lib/gooddata/cli/commands/project_cmd.rb +28 -0
  57. data/lib/gooddata/cli/hooks.rb +56 -0
  58. data/lib/gooddata/cli/shared.rb +66 -0
  59. data/lib/gooddata/cli/terminal.rb +20 -0
  60. data/lib/gooddata/client.rb +67 -0
  61. data/lib/gooddata/commands/api.rb +64 -0
  62. data/lib/gooddata/commands/auth.rb +107 -0
  63. data/lib/gooddata/commands/base.rb +12 -0
  64. data/lib/gooddata/commands/commands.rb +12 -0
  65. data/lib/gooddata/commands/datasets.rb +148 -0
  66. data/lib/gooddata/commands/datawarehouse.rb +20 -0
  67. data/lib/gooddata/commands/domain.rb +40 -0
  68. data/lib/gooddata/commands/process.rb +67 -0
  69. data/lib/gooddata/commands/project.rb +144 -0
  70. data/lib/gooddata/commands/projects.rb +20 -0
  71. data/lib/gooddata/commands/role.rb +36 -0
  72. data/lib/gooddata/commands/runners.rb +47 -0
  73. data/lib/gooddata/commands/scaffold.rb +69 -0
  74. data/lib/gooddata/commands/user.rb +39 -0
  75. data/lib/gooddata/connection.rb +127 -0
  76. data/lib/gooddata/core/core.rb +12 -0
  77. data/lib/gooddata/core/logging.rb +105 -0
  78. data/lib/gooddata/core/nil_logger.rb +32 -0
  79. data/lib/gooddata/core/project.rb +74 -0
  80. data/lib/gooddata/core/rest.rb +149 -0
  81. data/lib/gooddata/core/user.rb +20 -0
  82. data/lib/gooddata/data/data.rb +12 -0
  83. data/lib/gooddata/data/guesser.rb +122 -0
  84. data/lib/gooddata/exceptions/attr_element_not_found.rb +16 -0
  85. data/lib/gooddata/exceptions/command_failed.rb +11 -0
  86. data/lib/gooddata/exceptions/exceptions.rb +12 -0
  87. data/lib/gooddata/exceptions/execution_limit_exceeded.rb +13 -0
  88. data/lib/gooddata/exceptions/export_clone.rb +4 -0
  89. data/lib/gooddata/exceptions/filter_maqlization.rb +16 -0
  90. data/lib/gooddata/exceptions/import_clone.rb +4 -0
  91. data/lib/gooddata/exceptions/malformed_user.rb +15 -0
  92. data/lib/gooddata/exceptions/maql_execution.rb +16 -0
  93. data/lib/gooddata/exceptions/no_project_error.rb +19 -0
  94. data/lib/gooddata/exceptions/object_migration.rb +32 -0
  95. data/lib/gooddata/exceptions/project_not_found.rb +13 -0
  96. data/lib/gooddata/exceptions/segment_not_empty.rb +18 -0
  97. data/lib/gooddata/exceptions/uncomputable_report.rb +13 -0
  98. data/lib/gooddata/exceptions/user_in_different_domain.rb +15 -0
  99. data/lib/gooddata/exceptions/validation_error.rb +16 -0
  100. data/lib/gooddata/extensions/big_decimal.rb +17 -0
  101. data/lib/gooddata/extensions/class.rb +11 -0
  102. data/lib/gooddata/extensions/enumerable.rb +39 -0
  103. data/lib/gooddata/extensions/extensions.rb +10 -0
  104. data/lib/gooddata/extensions/false.rb +23 -0
  105. data/lib/gooddata/extensions/hash.rb +49 -0
  106. data/lib/gooddata/extensions/integer.rb +5 -0
  107. data/lib/gooddata/extensions/nil.rb +19 -0
  108. data/lib/gooddata/extensions/numeric.rb +15 -0
  109. data/lib/gooddata/extensions/object.rb +31 -0
  110. data/lib/gooddata/extensions/string.rb +7 -0
  111. data/lib/gooddata/extensions/symbol.rb +15 -0
  112. data/lib/gooddata/extensions/true.rb +23 -0
  113. data/lib/gooddata/extract.rb +21 -0
  114. data/lib/gooddata/goodzilla/goodzilla.rb +160 -0
  115. data/lib/gooddata/helpers/auth_helpers.rb +75 -0
  116. data/lib/gooddata/helpers/csv_helper.rb +61 -0
  117. data/lib/gooddata/helpers/data_helper.rb +129 -0
  118. data/lib/gooddata/helpers/erb_helper.rb +23 -0
  119. data/lib/gooddata/helpers/global_helpers.rb +266 -0
  120. data/lib/gooddata/helpers/global_helpers_params.rb +292 -0
  121. data/lib/gooddata/helpers/helpers.rb +10 -0
  122. data/lib/gooddata/lcm/actions/actions.rb +12 -0
  123. data/lib/gooddata/lcm/actions/apply_custom_maql.rb +80 -0
  124. data/lib/gooddata/lcm/actions/associate_clients.rb +87 -0
  125. data/lib/gooddata/lcm/actions/base_action.rb +23 -0
  126. data/lib/gooddata/lcm/actions/collect_ca_metrics.rb +53 -0
  127. data/lib/gooddata/lcm/actions/collect_client_projects.rb +78 -0
  128. data/lib/gooddata/lcm/actions/collect_clients.rb +128 -0
  129. data/lib/gooddata/lcm/actions/collect_data_product.rb +57 -0
  130. data/lib/gooddata/lcm/actions/collect_dynamic_schedule_params.rb +62 -0
  131. data/lib/gooddata/lcm/actions/collect_ldm_objects.rb +56 -0
  132. data/lib/gooddata/lcm/actions/collect_meta.rb +88 -0
  133. data/lib/gooddata/lcm/actions/collect_segment_clients.rb +113 -0
  134. data/lib/gooddata/lcm/actions/collect_segments.rb +72 -0
  135. data/lib/gooddata/lcm/actions/collect_tagged_objects.rb +80 -0
  136. data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +46 -0
  137. data/lib/gooddata/lcm/actions/create_segment_masters.rb +160 -0
  138. data/lib/gooddata/lcm/actions/ensure_data_product.rb +53 -0
  139. data/lib/gooddata/lcm/actions/ensure_release_table.rb +53 -0
  140. data/lib/gooddata/lcm/actions/ensure_segments.rb +32 -0
  141. data/lib/gooddata/lcm/actions/ensure_technical_users_domain.rb +70 -0
  142. data/lib/gooddata/lcm/actions/ensure_technical_users_project.rb +83 -0
  143. data/lib/gooddata/lcm/actions/execute_schedules.rb +128 -0
  144. data/lib/gooddata/lcm/actions/hello_world.rb +41 -0
  145. data/lib/gooddata/lcm/actions/import_object_collections.rb +60 -0
  146. data/lib/gooddata/lcm/actions/print_actions.rb +58 -0
  147. data/lib/gooddata/lcm/actions/print_modes.rb +69 -0
  148. data/lib/gooddata/lcm/actions/print_types.rb +52 -0
  149. data/lib/gooddata/lcm/actions/provision_clients.rb +89 -0
  150. data/lib/gooddata/lcm/actions/purge_clients.rb +58 -0
  151. data/lib/gooddata/lcm/actions/rename_existing_client_projects.rb +70 -0
  152. data/lib/gooddata/lcm/actions/segments_filter.rb +50 -0
  153. data/lib/gooddata/lcm/actions/synchronize_attribute_drillpaths.rb +64 -0
  154. data/lib/gooddata/lcm/actions/synchronize_cas.rb +72 -0
  155. data/lib/gooddata/lcm/actions/synchronize_clients.rb +94 -0
  156. data/lib/gooddata/lcm/actions/synchronize_color_palette.rb +67 -0
  157. data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +155 -0
  158. data/lib/gooddata/lcm/actions/synchronize_label_types.rb +64 -0
  159. data/lib/gooddata/lcm/actions/synchronize_ldm.rb +82 -0
  160. data/lib/gooddata/lcm/actions/synchronize_meta.rb +52 -0
  161. data/lib/gooddata/lcm/actions/synchronize_new_segments.rb +61 -0
  162. data/lib/gooddata/lcm/actions/synchronize_processes.rb +66 -0
  163. data/lib/gooddata/lcm/actions/synchronize_schedules.rb +91 -0
  164. data/lib/gooddata/lcm/actions/synchronize_tag_objects.rb +64 -0
  165. data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +210 -0
  166. data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +53 -0
  167. data/lib/gooddata/lcm/actions/synchronize_users.rb +336 -0
  168. data/lib/gooddata/lcm/actions/update_release_table.rb +77 -0
  169. data/lib/gooddata/lcm/data/create_lcm_release.sql.erb +6 -0
  170. data/lib/gooddata/lcm/data/insert_into_lcm_release.sql.erb +11 -0
  171. data/lib/gooddata/lcm/data/select_from_lcm_release.sql.erb +8 -0
  172. data/lib/gooddata/lcm/data/update_lcm_release.sql.erb +7 -0
  173. data/lib/gooddata/lcm/dsl/dsl.rb +50 -0
  174. data/lib/gooddata/lcm/dsl/params_dsl.rb +61 -0
  175. data/lib/gooddata/lcm/dsl/type_dsl.rb +62 -0
  176. data/lib/gooddata/lcm/helpers/check_helper.rb +41 -0
  177. data/lib/gooddata/lcm/helpers/helpers.rb +12 -0
  178. data/lib/gooddata/lcm/helpers/tags_helper.rb +36 -0
  179. data/lib/gooddata/lcm/lcm.rb +325 -0
  180. data/lib/gooddata/lcm/lcm2.rb +400 -0
  181. data/lib/gooddata/lcm/types/base_type.rb +29 -0
  182. data/lib/gooddata/lcm/types/class/ads_client.rb +35 -0
  183. data/lib/gooddata/lcm/types/class/class.rb +21 -0
  184. data/lib/gooddata/lcm/types/class/gd_client.rb +35 -0
  185. data/lib/gooddata/lcm/types/class/types.rb +12 -0
  186. data/lib/gooddata/lcm/types/complex/complex.rb +33 -0
  187. data/lib/gooddata/lcm/types/complex/release_query.rb +35 -0
  188. data/lib/gooddata/lcm/types/complex/segment.rb +40 -0
  189. data/lib/gooddata/lcm/types/complex/synchronization_info.rb +35 -0
  190. data/lib/gooddata/lcm/types/complex/tokens.rb +31 -0
  191. data/lib/gooddata/lcm/types/complex/types.rb +12 -0
  192. data/lib/gooddata/lcm/types/complex/update_preference.rb +38 -0
  193. data/lib/gooddata/lcm/types/complex/users_brick_config.rb +32 -0
  194. data/lib/gooddata/lcm/types/param.rb +16 -0
  195. data/lib/gooddata/lcm/types/scalar/bool.rb +22 -0
  196. data/lib/gooddata/lcm/types/scalar/hash.rb +22 -0
  197. data/lib/gooddata/lcm/types/scalar/integer.rb +22 -0
  198. data/lib/gooddata/lcm/types/scalar/object.rb +22 -0
  199. data/lib/gooddata/lcm/types/scalar/string.rb +22 -0
  200. data/lib/gooddata/lcm/types/scalar/types.rb +12 -0
  201. data/lib/gooddata/lcm/types/special/array.rb +33 -0
  202. data/lib/gooddata/lcm/types/special/enum.rb +15 -0
  203. data/lib/gooddata/lcm/types/special/types.rb +12 -0
  204. data/lib/gooddata/lcm/types/types.rb +12 -0
  205. data/lib/gooddata/lcm/user_bricks_helper.rb +32 -0
  206. data/lib/gooddata/mixins/author.rb +26 -0
  207. data/lib/gooddata/mixins/content_getter.rb +15 -0
  208. data/lib/gooddata/mixins/content_property_reader.rb +17 -0
  209. data/lib/gooddata/mixins/content_property_writer.rb +17 -0
  210. data/lib/gooddata/mixins/contributor.rb +20 -0
  211. data/lib/gooddata/mixins/data_getter.rb +15 -0
  212. data/lib/gooddata/mixins/data_property_reader.rb +19 -0
  213. data/lib/gooddata/mixins/data_property_writer.rb +19 -0
  214. data/lib/gooddata/mixins/inspector.rb +53 -0
  215. data/lib/gooddata/mixins/is_attribute.rb +17 -0
  216. data/lib/gooddata/mixins/is_dimension.rb +17 -0
  217. data/lib/gooddata/mixins/is_fact.rb +17 -0
  218. data/lib/gooddata/mixins/is_folder.rb +11 -0
  219. data/lib/gooddata/mixins/is_label.rb +19 -0
  220. data/lib/gooddata/mixins/links.rb +15 -0
  221. data/lib/gooddata/mixins/md_finders.rb +79 -0
  222. data/lib/gooddata/mixins/md_grantees.rb +42 -0
  223. data/lib/gooddata/mixins/md_id_to_uri.rb +39 -0
  224. data/lib/gooddata/mixins/md_json.rb +15 -0
  225. data/lib/gooddata/mixins/md_lock.rb +87 -0
  226. data/lib/gooddata/mixins/md_object_id.rb +15 -0
  227. data/lib/gooddata/mixins/md_object_indexer.rb +74 -0
  228. data/lib/gooddata/mixins/md_object_query.rb +134 -0
  229. data/lib/gooddata/mixins/md_relations.rb +43 -0
  230. data/lib/gooddata/mixins/meta_getter.rb +17 -0
  231. data/lib/gooddata/mixins/meta_property_reader.rb +19 -0
  232. data/lib/gooddata/mixins/meta_property_writer.rb +19 -0
  233. data/lib/gooddata/mixins/mixins.rb +19 -0
  234. data/lib/gooddata/mixins/not_attribute.rb +17 -0
  235. data/lib/gooddata/mixins/not_exportable.rb +15 -0
  236. data/lib/gooddata/mixins/not_fact.rb +17 -0
  237. data/lib/gooddata/mixins/not_group.rb +17 -0
  238. data/lib/gooddata/mixins/not_label.rb +19 -0
  239. data/lib/gooddata/mixins/not_metric.rb +19 -0
  240. data/lib/gooddata/mixins/obj_id.rb +15 -0
  241. data/lib/gooddata/mixins/rest_getters.rb +17 -0
  242. data/lib/gooddata/mixins/rest_resource.rb +47 -0
  243. data/lib/gooddata/mixins/root_key_getter.rb +15 -0
  244. data/lib/gooddata/mixins/root_key_setter.rb +15 -0
  245. data/lib/gooddata/mixins/timestamps.rb +19 -0
  246. data/lib/gooddata/mixins/to_json.rb +11 -0
  247. data/lib/gooddata/mixins/uri_getter.rb +9 -0
  248. data/lib/gooddata/models/ads_output_stage.rb +85 -0
  249. data/lib/gooddata/models/automated_data_distribution.rb +36 -0
  250. data/lib/gooddata/models/blueprint/anchor_field.rb +65 -0
  251. data/lib/gooddata/models/blueprint/attribute_field.rb +45 -0
  252. data/lib/gooddata/models/blueprint/blueprint.rb +11 -0
  253. data/lib/gooddata/models/blueprint/blueprint_field.rb +70 -0
  254. data/lib/gooddata/models/blueprint/dashboard_builder.rb +30 -0
  255. data/lib/gooddata/models/blueprint/dataset_blueprint.rb +455 -0
  256. data/lib/gooddata/models/blueprint/date_dimension.rb +20 -0
  257. data/lib/gooddata/models/blueprint/fact_field.rb +20 -0
  258. data/lib/gooddata/models/blueprint/label_field.rb +47 -0
  259. data/lib/gooddata/models/blueprint/project_blueprint.rb +791 -0
  260. data/lib/gooddata/models/blueprint/project_builder.rb +103 -0
  261. data/lib/gooddata/models/blueprint/reference_field.rb +43 -0
  262. data/lib/gooddata/models/blueprint/schema_blueprint.rb +160 -0
  263. data/lib/gooddata/models/blueprint/schema_builder.rb +89 -0
  264. data/lib/gooddata/models/blueprint/to_manifest.rb +185 -0
  265. data/lib/gooddata/models/blueprint/to_wire.rb +173 -0
  266. data/lib/gooddata/models/channel_configuration.rb +112 -0
  267. data/lib/gooddata/models/client.rb +236 -0
  268. data/lib/gooddata/models/client_synchronization_result.rb +31 -0
  269. data/lib/gooddata/models/client_synchronization_result_details.rb +41 -0
  270. data/lib/gooddata/models/data_product.rb +149 -0
  271. data/lib/gooddata/models/datawarehouse.rb +114 -0
  272. data/lib/gooddata/models/domain.rb +505 -0
  273. data/lib/gooddata/models/execution.rb +115 -0
  274. data/lib/gooddata/models/execution_detail.rb +81 -0
  275. data/lib/gooddata/models/from_wire.rb +173 -0
  276. data/lib/gooddata/models/invitation.rb +75 -0
  277. data/lib/gooddata/models/links.rb +50 -0
  278. data/lib/gooddata/models/membership.rb +441 -0
  279. data/lib/gooddata/models/metadata.rb +324 -0
  280. data/lib/gooddata/models/metadata/attribute.rb +155 -0
  281. data/lib/gooddata/models/metadata/dashboard.rb +120 -0
  282. data/lib/gooddata/models/metadata/dashboard/dashboard_item.rb +76 -0
  283. data/lib/gooddata/models/metadata/dashboard/filter_apply_item.rb +37 -0
  284. data/lib/gooddata/models/metadata/dashboard/filter_item.rb +64 -0
  285. data/lib/gooddata/models/metadata/dashboard/geo_chart_item.rb +56 -0
  286. data/lib/gooddata/models/metadata/dashboard/headline_item.rb +56 -0
  287. data/lib/gooddata/models/metadata/dashboard/iframe_item.rb +46 -0
  288. data/lib/gooddata/models/metadata/dashboard/report_item.rb +92 -0
  289. data/lib/gooddata/models/metadata/dashboard/text_item.rb +55 -0
  290. data/lib/gooddata/models/metadata/dashboard_tab.rb +141 -0
  291. data/lib/gooddata/models/metadata/dataset.rb +67 -0
  292. data/lib/gooddata/models/metadata/dimension.rb +57 -0
  293. data/lib/gooddata/models/metadata/fact.rb +51 -0
  294. data/lib/gooddata/models/metadata/folder.rb +49 -0
  295. data/lib/gooddata/models/metadata/label.rb +128 -0
  296. data/lib/gooddata/models/metadata/metadata.rb +12 -0
  297. data/lib/gooddata/models/metadata/metric.rb +206 -0
  298. data/lib/gooddata/models/metadata/report.rb +268 -0
  299. data/lib/gooddata/models/metadata/report_definition.rb +272 -0
  300. data/lib/gooddata/models/metadata/scheduled_mail.rb +277 -0
  301. data/lib/gooddata/models/metadata/scheduled_mail/dashboard_attachment.rb +62 -0
  302. data/lib/gooddata/models/metadata/scheduled_mail/report_attachment.rb +64 -0
  303. data/lib/gooddata/models/metadata/variable.rb +96 -0
  304. data/lib/gooddata/models/model.rb +293 -0
  305. data/lib/gooddata/models/models.rb +12 -0
  306. data/lib/gooddata/models/module_constants.rb +31 -0
  307. data/lib/gooddata/models/notification_rule.rb +113 -0
  308. data/lib/gooddata/models/process.rb +371 -0
  309. data/lib/gooddata/models/profile.rb +451 -0
  310. data/lib/gooddata/models/project.rb +2030 -0
  311. data/lib/gooddata/models/project_creator.rb +209 -0
  312. data/lib/gooddata/models/project_log_formatter.rb +204 -0
  313. data/lib/gooddata/models/project_metadata.rb +67 -0
  314. data/lib/gooddata/models/project_role.rb +79 -0
  315. data/lib/gooddata/models/report_data_result.rb +270 -0
  316. data/lib/gooddata/models/schedule.rb +538 -0
  317. data/lib/gooddata/models/segment.rb +274 -0
  318. data/lib/gooddata/models/style_setting.rb +62 -0
  319. data/lib/gooddata/models/subscription.rb +188 -0
  320. data/lib/gooddata/models/tab_builder.rb +27 -0
  321. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +76 -0
  322. data/lib/gooddata/models/user_filters/user_filter.rb +101 -0
  323. data/lib/gooddata/models/user_filters/user_filter_builder.rb +553 -0
  324. data/lib/gooddata/models/user_filters/user_filters.rb +13 -0
  325. data/lib/gooddata/models/user_filters/variable_user_filter.rb +33 -0
  326. data/lib/gooddata/models/user_group.rb +250 -0
  327. data/lib/gooddata/rest/README.md +37 -0
  328. data/lib/gooddata/rest/client.rb +396 -0
  329. data/lib/gooddata/rest/connection.rb +776 -0
  330. data/lib/gooddata/rest/object.rb +69 -0
  331. data/lib/gooddata/rest/object_factory.rb +51 -0
  332. data/lib/gooddata/rest/resource.rb +27 -0
  333. data/lib/gooddata/rest/rest.rb +24 -0
  334. data/lib/gooddata/version.rb +23 -0
  335. data/lib/templates/bricks/brick.rb.erb +7 -0
  336. data/lib/templates/bricks/main.rb.erb +5 -0
  337. data/lib/templates/project/Goodfile.erb +4 -0
  338. data/lib/templates/project/data/commits.csv +4 -0
  339. data/lib/templates/project/data/devs.csv +4 -0
  340. data/lib/templates/project/data/repos.csv +3 -0
  341. data/lib/templates/project/model/model.rb.erb +20 -0
  342. data/spec/.rubocop.yml +16 -0
  343. data/spec/bricks/bricks_spec.rb +110 -0
  344. data/spec/bricks/default-config.json +8 -0
  345. data/spec/data/.gooddata +4 -0
  346. data/spec/data/blueprints/additional_dataset_module.json +32 -0
  347. data/spec/data/blueprints/attribute_sort_order_blueprint.json +72 -0
  348. data/spec/data/blueprints/big_blueprint_not_pruned.json +2079 -0
  349. data/spec/data/blueprints/invalid_blueprint.json +103 -0
  350. data/spec/data/blueprints/m_n_model.json +104 -0
  351. data/spec/data/blueprints/model_module.json +25 -0
  352. data/spec/data/blueprints/test_blueprint.json +39 -0
  353. data/spec/data/blueprints/test_project_model_spec.json +106 -0
  354. data/spec/data/cc/data/source/commits.csv +4 -0
  355. data/spec/data/cc/data/source/devs.csv +4 -0
  356. data/spec/data/cc/data/source/repos.csv +3 -0
  357. data/spec/data/cc/devel.prm +0 -0
  358. data/spec/data/cc/graph/graph.grf +11 -0
  359. data/spec/data/cc/workspace.prm +19 -0
  360. data/spec/data/column_based_permissions.csv +7 -0
  361. data/spec/data/column_based_permissions2.csv +6 -0
  362. data/spec/data/dynamic_schedule_params_table.csv +7 -0
  363. data/spec/data/gd_gse_data_blueprint.json +1371 -0
  364. data/spec/data/gd_gse_data_manifest.json +1424 -0
  365. data/spec/data/gd_gse_data_model.json +1772 -0
  366. data/spec/data/gooddata_version_process/gooddata_version.rb +9 -0
  367. data/spec/data/gooddata_version_process/gooddata_version.zip +0 -0
  368. data/spec/data/hello_world_process/hello_world.rb +9 -0
  369. data/spec/data/hello_world_process/hello_world.zip +0 -0
  370. data/spec/data/line_based_permissions.csv +3 -0
  371. data/spec/data/manifests/test_blueprint.json +32 -0
  372. data/spec/data/manifests/test_project.json +107 -0
  373. data/spec/data/reports/left_attr_report.json +108 -0
  374. data/spec/data/reports/metric_only_one_line.json +83 -0
  375. data/spec/data/reports/report_1.json +197 -0
  376. data/spec/data/reports/top_attr_report.json +108 -0
  377. data/spec/data/ruby_params_process/ruby_params.rb +9 -0
  378. data/spec/data/ruby_process/deep_files/deep_stuff.txt +1 -0
  379. data/spec/data/ruby_process/process.rb +8 -0
  380. data/spec/data/ruby_process/stuff.txt +1 -0
  381. data/spec/data/superfluous_titles_view.json +81 -0
  382. data/spec/data/test-ci-data.csv +2 -0
  383. data/spec/data/users.csv +12 -0
  384. data/spec/data/wire_models/attribute_sort_by_model.json +73 -0
  385. data/spec/data/wire_models/model_view.json +1775 -0
  386. data/spec/data/wire_models/nu_model.json +3046 -0
  387. data/spec/data/wire_models/test_blueprint.json +66 -0
  388. data/spec/data/wire_test_project.json +150 -0
  389. data/spec/data/workspace_table.csv +3 -0
  390. data/spec/environment/default.rb +43 -0
  391. data/spec/environment/development.rb +32 -0
  392. data/spec/environment/environment.rb +38 -0
  393. data/spec/environment/production.rb +27 -0
  394. data/spec/environment/staging.rb +33 -0
  395. data/spec/environment/testing.rb +32 -0
  396. data/spec/helpers/blueprint_helper.rb +27 -0
  397. data/spec/helpers/cli_helper.rb +38 -0
  398. data/spec/helpers/connection_helper.rb +43 -0
  399. data/spec/helpers/crypto_helper.rb +19 -0
  400. data/spec/helpers/csv_helper.rb +20 -0
  401. data/spec/helpers/process_helper.rb +35 -0
  402. data/spec/helpers/project_helper.rb +74 -0
  403. data/spec/helpers/schedule_helper.rb +33 -0
  404. data/spec/helpers/spec_helper.rb +17 -0
  405. data/spec/integration/ads_output_stage_spec.rb +45 -0
  406. data/spec/integration/blueprint_updates_spec.rb +107 -0
  407. data/spec/integration/blueprint_with_ca_spec.rb +56 -0
  408. data/spec/integration/blueprint_with_grain_spec.rb +74 -0
  409. data/spec/integration/channel_configuration_spec.rb +67 -0
  410. data/spec/integration/clients_spec.rb +164 -0
  411. data/spec/integration/command_datawarehouse_spec.rb +45 -0
  412. data/spec/integration/command_projects_spec.rb +32 -0
  413. data/spec/integration/commands/command_projects_spec.rb +22 -0
  414. data/spec/integration/core/connection_spec.rb +56 -0
  415. data/spec/integration/core/logging_spec.rb +130 -0
  416. data/spec/integration/core/project_spec.rb +54 -0
  417. data/spec/integration/create_from_template_spec.rb +29 -0
  418. data/spec/integration/create_project_spec.rb +27 -0
  419. data/spec/integration/date_dim_switch_spec.rb +150 -0
  420. data/spec/integration/deprecated_load_spec.rb +60 -0
  421. data/spec/integration/full_process_schedule_spec.rb +367 -0
  422. data/spec/integration/full_project_spec.rb +592 -0
  423. data/spec/integration/helpers_spec.rb +16 -0
  424. data/spec/integration/lcm_spec.rb +54 -0
  425. data/spec/integration/mixins/id_to_uri_spec.rb +44 -0
  426. data/spec/integration/models/data_product_spec.rb +71 -0
  427. data/spec/integration/models/domain_spec.rb +162 -0
  428. data/spec/integration/models/invitation_spec.rb +17 -0
  429. data/spec/integration/models/membership_spec.rb +127 -0
  430. data/spec/integration/models/metadata/report_spec.rb +54 -0
  431. data/spec/integration/models/params_spec.rb +118 -0
  432. data/spec/integration/models/profile_spec.rb +210 -0
  433. data/spec/integration/models/project_role_spec.rb +94 -0
  434. data/spec/integration/models/project_spec.rb +225 -0
  435. data/spec/integration/models/schedule_spec.rb +485 -0
  436. data/spec/integration/models/unit_project_spec.rb +130 -0
  437. data/spec/integration/over_to_user_filters_spec.rb +98 -0
  438. data/spec/integration/partial_md_export_import_spec.rb +41 -0
  439. data/spec/integration/project_spec.rb +381 -0
  440. data/spec/integration/rest_spec.rb +214 -0
  441. data/spec/integration/schedule_spec.rb +613 -0
  442. data/spec/integration/segments_spec.rb +100 -0
  443. data/spec/integration/subscription_spec.rb +88 -0
  444. data/spec/integration/urn_date_dim_spec.rb +53 -0
  445. data/spec/integration/user_filters_spec.rb +306 -0
  446. data/spec/integration/user_group_spec.rb +147 -0
  447. data/spec/integration/variables_spec.rb +189 -0
  448. data/spec/logging_in_logging_out_spec.rb +91 -0
  449. data/spec/spec_helper.rb +66 -0
  450. data/spec/unit/actions/associate_clients_spec.rb +47 -0
  451. data/spec/unit/actions/collect_client_projects_spec.rb +47 -0
  452. data/spec/unit/actions/collect_clients_spec.rb +65 -0
  453. data/spec/unit/actions/collect_data_product_spec.rb +56 -0
  454. data/spec/unit/actions/collect_dynamic_schedule_params_spec.rb +56 -0
  455. data/spec/unit/actions/collect_meta_spec.rb +88 -0
  456. data/spec/unit/actions/collect_segment_clients_spec.rb +81 -0
  457. data/spec/unit/actions/collect_tagged_objects_spec.rb +126 -0
  458. data/spec/unit/actions/collect_users_brick_users_spec.rb +36 -0
  459. data/spec/unit/actions/create_segment_masters_spec.rb +64 -0
  460. data/spec/unit/actions/ensure_data_product_spec.rb +38 -0
  461. data/spec/unit/actions/ensure_technical_users_domain_spec.rb +51 -0
  462. data/spec/unit/actions/ensure_technical_users_project_spec.rb +72 -0
  463. data/spec/unit/actions/execute_schedules_spec.rb +94 -0
  464. data/spec/unit/actions/provision_clients_spec.rb +45 -0
  465. data/spec/unit/actions/purge_clients_spec.rb +47 -0
  466. data/spec/unit/actions/rename_existing_client_projects_spec.rb +54 -0
  467. data/spec/unit/actions/segments_filter_spec.rb +46 -0
  468. data/spec/unit/actions/shared_examples_for_user_actions.rb +26 -0
  469. data/spec/unit/actions/synchronize_cas_spec.rb +58 -0
  470. data/spec/unit/actions/synchronize_etls_in_segment_spec.rb +212 -0
  471. data/spec/unit/actions/synchronize_ldm_spec.rb +57 -0
  472. data/spec/unit/actions/synchronize_user_filters_spec.rb +146 -0
  473. data/spec/unit/actions/synchronize_user_groups_spec.rb +49 -0
  474. data/spec/unit/actions/synchronize_users_spec.rb +134 -0
  475. data/spec/unit/bricks/bricks_spec.rb +34 -0
  476. data/spec/unit/bricks/middleware/aws_middelware_spec.rb +98 -0
  477. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +15 -0
  478. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +15 -0
  479. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +15 -0
  480. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +30 -0
  481. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +15 -0
  482. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +15 -0
  483. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +15 -0
  484. data/spec/unit/cli/cli_spec.rb +17 -0
  485. data/spec/unit/cli/commands/cmd_auth_spec.rb +17 -0
  486. data/spec/unit/core/nil_logger_spec.rb +13 -0
  487. data/spec/unit/extensions/hash_spec.rb +22 -0
  488. data/spec/unit/godzilla/goodzilla_spec.rb +74 -0
  489. data/spec/unit/helpers/csv_helper_spec.rb +22 -0
  490. data/spec/unit/helpers/data_helper_spec.rb +67 -0
  491. data/spec/unit/helpers/global_helpers_spec.rb +264 -0
  492. data/spec/unit/helpers_spec.rb +254 -0
  493. data/spec/unit/lcm/user_bricks_helper_spec.rb +58 -0
  494. data/spec/unit/models/blueprint/attribute_sort_by_spec.rb +20 -0
  495. data/spec/unit/models/blueprint/attributes_spec.rb +28 -0
  496. data/spec/unit/models/blueprint/dataset_spec.rb +120 -0
  497. data/spec/unit/models/blueprint/labels_spec.rb +43 -0
  498. data/spec/unit/models/blueprint/project_blueprint_spec.rb +642 -0
  499. data/spec/unit/models/blueprint/reference_spec.rb +28 -0
  500. data/spec/unit/models/blueprint/schema_builder_spec.rb +36 -0
  501. data/spec/unit/models/blueprint/to_wire_spec.rb +195 -0
  502. data/spec/unit/models/execution_spec.rb +109 -0
  503. data/spec/unit/models/from_wire_spec.rb +301 -0
  504. data/spec/unit/models/metadata_spec.rb +140 -0
  505. data/spec/unit/models/metric_spec.rb +129 -0
  506. data/spec/unit/models/model_spec.rb +77 -0
  507. data/spec/unit/models/project_creator_spec.rb +90 -0
  508. data/spec/unit/models/project_spec.rb +94 -0
  509. data/spec/unit/models/report_result_data_spec.rb +194 -0
  510. data/spec/unit/models/to_manifest_spec.rb +136 -0
  511. data/spec/unit/models/user_filters/user_filter_builder_spec.rb +110 -0
  512. data/spec/unit/models/user_filters_spec.rb +95 -0
  513. data/spec/unit/models/variable_spec.rb +280 -0
  514. data/spec/unit/rest/polling_spec.rb +101 -0
  515. data/spec/unit/rest/resource_spec.rb +10 -0
  516. data/yard-server.sh +3 -0
  517. metadata +1207 -0
@@ -0,0 +1,776 @@
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 'terminal-table'
8
+ require 'securerandom'
9
+ require 'monitor'
10
+ require 'thread_safe'
11
+ require 'rest-client'
12
+
13
+ require_relative '../version'
14
+ require_relative '../exceptions/exceptions'
15
+
16
+ require_relative '../helpers/global_helpers'
17
+
18
+ module RestClient
19
+ module AbstractResponse
20
+ alias_method :old_follow_redirection, :follow_redirection
21
+ def follow_redirection(request = nil, result = nil, &block)
22
+ if RestClient::VERSION != '1.8.0'
23
+ fail 'Using monkey patched version of RestClient::AbstractResponse#' \
24
+ 'follow_redirection which is guaranteed to be compatible only ' \
25
+ 'with RestClient 1.8.0'
26
+ end
27
+
28
+ new_args = @args.dup
29
+
30
+ url = headers[:location]
31
+ url = URI.parse(request.url).merge(url).to_s if url !~ /^http/
32
+
33
+ new_args[:url] = url
34
+ if request
35
+ fail MaxRedirectsReached if request.max_redirects.zero?
36
+ new_args[:password] = request.password
37
+ new_args[:user] = request.user
38
+ new_args[:headers] = request.headers
39
+ new_args[:max_redirects] = request.max_redirects - 1
40
+
41
+ # TODO: figure out what to do with original :cookie, :cookies values
42
+ new_args[:cookies] = get_redirection_cookies(request, result, new_args)
43
+ end
44
+
45
+ Request.execute(new_args, &block)
46
+ end
47
+
48
+ # Returns cookies which should be passed when following redirect
49
+ #
50
+ # @param request [RestClient::Request] Original request
51
+ # @param result [Net::HTTPResponse] Response
52
+ # @param args [Hash] Original arguments
53
+ # @return [Hash] Cookies to be passsed when following redirect
54
+ def get_redirection_cookies(request, _result, _args)
55
+ request.cookies
56
+ end
57
+ end
58
+ end
59
+
60
+ module GoodData
61
+ module Rest
62
+ class RestRetryError < StandardError
63
+ end
64
+
65
+ # Wrapper of low-level HTTP/REST client/library
66
+ class Connection
67
+ include MonitorMixin
68
+
69
+ DEFAULT_URL = 'https://secure.gooddata.com'
70
+ LOGIN_PATH = '/gdc/account/login'
71
+ TOKEN_PATH = '/gdc/account/token'
72
+ KEYS_TO_SCRUB = [:password, :verifyPassword, :authorizationToken]
73
+
74
+ ID_LENGTH = 16
75
+
76
+ DEFAULT_HEADERS = {
77
+ :content_type => :json,
78
+ :accept => [:json, :zip],
79
+ :user_agent => GoodData.gem_version_string
80
+ }
81
+
82
+ DEFAULT_WEBDAV_HEADERS = {
83
+ :user_agent => GoodData.gem_version_string
84
+ }
85
+
86
+ DEFAULT_LOGIN_PAYLOAD = {
87
+ :headers => DEFAULT_HEADERS,
88
+ :verify_ssl => true
89
+ }
90
+
91
+ RETRYABLE_ERRORS = [
92
+ Net::HTTPBadResponse,
93
+ RestClient::InternalServerError,
94
+ RestClient::RequestTimeout,
95
+ RestClient::MethodNotAllowed,
96
+ SystemCallError,
97
+ Timeout::Error
98
+ ]
99
+
100
+ RETRIES_ON_TOO_MANY_REQUESTS_ERROR = 12
101
+ RETRY_TIME_INITIAL_VALUE = 1
102
+ RETRY_TIME_COEFFICIENT = 1.5
103
+ RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
104
+
105
+ class << self
106
+ def construct_login_payload(username, password)
107
+ res = {
108
+ 'postUserLogin' => {
109
+ 'login' => username,
110
+ 'password' => password,
111
+ 'remember' => 1,
112
+ 'verify_level' => 2
113
+ }
114
+ }
115
+ res
116
+ end
117
+
118
+ # Generate random string with URL safe base64 encoding
119
+ #
120
+ # @param [String] length Length of random string to be generated
121
+ #
122
+ # @return [String] Generated random string
123
+ def generate_string(length = ID_LENGTH)
124
+ SecureRandom.urlsafe_base64(length)
125
+ end
126
+
127
+ # Retry block if exception thrown
128
+ def retryable(options = {}, &_block)
129
+ opts = { :tries => 1, :on => RETRYABLE_ERRORS }.merge(options)
130
+
131
+ retry_exception = opts[:on]
132
+ retries = opts[:tries]
133
+ too_many_requests_tries = RETRIES_ON_TOO_MANY_REQUESTS_ERROR
134
+
135
+ unless retry_exception.is_a?(Array)
136
+ retry_exception = [retry_exception]
137
+ end
138
+
139
+ retry_time = RETRY_TIME_INITIAL_VALUE
140
+ begin
141
+ return yield
142
+ rescue RestClient::Unauthorized, RestClient::Forbidden => e # , RestClient::Unauthorized => e
143
+ raise e unless options[:refresh_token]
144
+ raise e if options[:dont_reauth]
145
+ options[:refresh_token].call # (dont_reauth: true)
146
+ retry if (retries -= 1) > 0
147
+ rescue RestClient::TooManyRequests, RestClient::ServiceUnavailable
148
+ GoodData.logger.warn "Too many requests, retrying in #{retry_time} seconds"
149
+ sleep retry_time
150
+ retry_time *= RETRY_TIME_COEFFICIENT
151
+ # 10 requests with 1.5 coefficent should take ~ 3 mins to finish
152
+ retry if (too_many_requests_tries -= 1) > 1
153
+ rescue *retry_exception => e
154
+ GoodData.logger.warn e.inspect
155
+ retry if (retries -= 1) > 1
156
+ end
157
+ yield
158
+ end
159
+ end
160
+
161
+ attr_reader :request_params
162
+
163
+ # backward compatibility
164
+ alias_method :cookies, :request_params
165
+ alias_method :headers, :request_params
166
+ attr_reader :server
167
+ attr_reader :stats
168
+ attr_reader :user
169
+ attr_reader :verify_ssl
170
+
171
+ def initialize(opts)
172
+ super()
173
+ @stats = ThreadSafe::Hash.new
174
+
175
+ headers = opts[:headers] || {}
176
+ @webdav_headers = DEFAULT_WEBDAV_HEADERS.merge(headers)
177
+
178
+ @user = nil
179
+ @server = nil
180
+ @opts = opts
181
+ @verify_ssl = @opts[:verify_ssl] == false || @opts[:verify_ssl] == OpenSSL::SSL::VERIFY_NONE ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
182
+
183
+ # Initialize headers
184
+ reset_headers!
185
+
186
+ @at_exit_handler_installed = nil
187
+ end
188
+
189
+ # Connect using username and password
190
+ def connect(username, password, options = {})
191
+ server = options[:server] || Helpers::AuthHelper.read_server
192
+ options = DEFAULT_LOGIN_PAYLOAD.merge(options)
193
+ headers = options[:headers] || {}
194
+
195
+ options = options.merge(headers)
196
+ @server = RestClient::Resource.new server, options
197
+
198
+ # Install at_exit handler first
199
+ unless @at_exit_handler_installed
200
+ begin
201
+ at_exit { disconnect if @user }
202
+ rescue RestClient::Unauthorized
203
+ GoodData.logger.info 'Already logged out'
204
+ ensure
205
+ @at_exit_handler_installed = true
206
+ end
207
+ end
208
+
209
+ # Reset old cookies first
210
+ if options[:sst_token]
211
+ merge_headers!(:x_gdc_authsst => options[:sst_token])
212
+ get('/gdc/account/token', @request_params)
213
+
214
+ @user = get(get('/gdc/app/account/bootstrap')['bootstrapResource']['accountSetting']['links']['self'])
215
+ GoodData.logger.info("Connected using SST to server #{@server.url} to profile \"#{@user['accountSetting']['login']}\"")
216
+ @auth = {}
217
+ refresh_token :dont_reauth => true
218
+ else
219
+ GoodData.logger.info("Connected using username \"#{username}\" to server #{@server.url}")
220
+ credentials = Connection.construct_login_payload(username, password)
221
+ generate_session_id
222
+ @auth = post(LOGIN_PATH, credentials, :dont_reauth => true)['userLogin']
223
+
224
+ refresh_token :dont_reauth => true
225
+ @user = get(@auth['profile'])
226
+ end
227
+ GoodData.logger.info('Connection successful')
228
+ rescue RestClient::Unauthorized => e
229
+ GoodData.logger.info('Bad Login or Password')
230
+ GoodData.logger.info('Connection failed')
231
+ raise e
232
+ rescue RestClient::Forbidden => e
233
+ GoodData.logger.info('Connection failed')
234
+ raise e
235
+ end
236
+
237
+ # Disconnect
238
+ def disconnect
239
+ # TODO: Wrap somehow
240
+ url = @auth['state']
241
+
242
+ begin
243
+ clear_session_id
244
+ delete(url, :x_gdc_authsst => sst_token) if url
245
+ rescue RestClient::Unauthorized
246
+ GoodData.logger.info 'Already disconnected'
247
+ end
248
+
249
+ @auth = nil
250
+ @server = nil
251
+ @user = nil
252
+
253
+ reset_headers!
254
+ end
255
+
256
+ # @param what Address of the remote file.
257
+ # @param where Full path to the target file.
258
+ # @option [Bool] :url_encode ('true') URL encode the address.
259
+ def download(what, where, options = {})
260
+ # handle the path (directory) given in what
261
+ ilast_slash = what.rindex('/')
262
+ if ilast_slash.nil?
263
+ what_dir = ''
264
+ else
265
+ # take the directory from the path
266
+ what_dir = what[0..ilast_slash - 1]
267
+ # take the filename from the path
268
+ what = what[ilast_slash + 1..-1]
269
+ end
270
+
271
+ option_dir = options[:directory] || ''
272
+ option_dir = option_dir[0..-2] if option_dir[-1] == '/'
273
+
274
+ # join the otion dir with the what_dir
275
+ # [option dir empty, what dir empty] => the joined dir
276
+ dir_hash = {
277
+ [true, true] => '',
278
+ [true, false] => what_dir,
279
+ [false, true] => option_dir,
280
+ [false, false] => "#{what_dir}/#{option_dir}"
281
+ }
282
+ dir = dir_hash[[option_dir.empty?, what_dir.empty?]]
283
+
284
+ staging_uri = options[:staging_url].to_s
285
+
286
+ base_url = dir.empty? ? staging_uri : URI.join("#{server}", staging_uri, "#{dir}/").to_s
287
+ sanitized_what = options[:url_encode] == false ? what : CGI.escape(what)
288
+ url = URI.join("#{server}", base_url, sanitized_what).to_s
289
+
290
+ b = proc do |f|
291
+ raw = {
292
+ :headers => @webdav_headers.merge(:x_gdc_authtt => headers[:x_gdc_authtt]),
293
+ :method => :get,
294
+ :url => url,
295
+ :verify_ssl => verify_ssl
296
+ }
297
+ RestClient::Request.execute(raw) do |chunk, _x, response|
298
+ if response.code.to_s == '202'
299
+ fail RestRetryError, 'Got 202, retry'
300
+ elsif response.code.to_s != '200'
301
+ fail ArgumentError, "Error downloading #{url}. Got response: #{response.code} #{response} #{response.body}"
302
+ end
303
+ f.write chunk
304
+ end
305
+ end
306
+
307
+ GoodData::Rest::Connection.retryable(:tries => Helpers::GD_MAX_RETRY, :refresh_token => proc { refresh_token }, :on => RestRetryError) do
308
+ if where.is_a?(IO) || where.is_a?(StringIO)
309
+ b.call(where)
310
+ else
311
+ # Assume it is a string or file
312
+ File.open(where, 'w') do |f|
313
+ b.call(f)
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ def refresh_token(_options = {})
320
+ begin # rubocop:disable RedundantBegin
321
+ # avoid infinite loop GET fails with 401
322
+ response = get(TOKEN_PATH, :x_gdc_authsst => sst_token, :dont_reauth => true)
323
+ # Remove when TT sent in headers. Currently we need to parse from body
324
+ merge_headers!(:x_gdc_authtt => GoodData::Helpers.get_path(response, %w(userToken token)))
325
+ rescue Exception => e # rubocop:disable RescueException
326
+ puts e.message
327
+ raise e
328
+ end
329
+ end
330
+
331
+ # Returns server URI
332
+ #
333
+ # @return [String] server uri
334
+ def server_url
335
+ @server && @server.url
336
+ end
337
+
338
+ # HTTP DELETE
339
+ #
340
+ # @param uri [String] Target URI
341
+ def delete(uri, options = {})
342
+ request(:delete, uri, nil, options)
343
+ end
344
+
345
+ # Helper for logging error
346
+ #
347
+ # @param e [RuntimeException] Exception to log
348
+ # @param uri [String] Uri on which the request failed
349
+ # @param params [Hash] Additional params
350
+ def log_error(e, uri, params, options = {})
351
+ return if e.response && e.response.code == 401 && !uri.include?('token') && !uri.include?('login')
352
+
353
+ if options[:do_not_log].nil? || options[:do_not_log].index(e.class).nil?
354
+ GoodData.logger.error(format_error(e, params))
355
+ end
356
+ end
357
+
358
+ def request(method, uri, data, options = {}, &user_block)
359
+ request_id = options[:request_id] || generate_request_id
360
+ log_info(options.merge(request_id: request_id))
361
+ payload = data.is_a?(Hash) ? data.to_json : data
362
+
363
+ GoodData.rest_logger.info "#{method.to_s.upcase}: #{@server.url}#{uri}, #{scrub_params(data, KEYS_TO_SCRUB)}"
364
+ profile "#{method.to_s.upcase} #{uri}" do
365
+ b = proc do
366
+ params = fresh_request_params(request_id).merge(options)
367
+ begin
368
+ case method
369
+ when :get
370
+ @server[uri].get(params, &user_block)
371
+ when :put
372
+ @server[uri].put(payload, params)
373
+ when :delete
374
+ @server[uri].delete(params)
375
+ when :post
376
+ @server[uri].post(payload, params)
377
+ end
378
+ rescue RestClient::Exception => e
379
+ log_error(e, uri, params, options)
380
+ raise e
381
+ end
382
+ end
383
+ process_response(options, &b)
384
+ end
385
+ end
386
+
387
+ # HTTP GET
388
+ #
389
+ # @param uri [String] Target URI
390
+ def get(uri, options = {}, &user_block)
391
+ request(:get, uri, nil, options, &user_block)
392
+ end
393
+
394
+ # HTTP PUT
395
+ #
396
+ # @param uri [String] Target URI
397
+ def put(uri, data, options = {})
398
+ request(:put, uri, data, options)
399
+ end
400
+
401
+ # HTTP POST
402
+ #
403
+ # @param uri [String] Target URI
404
+ def post(uri, data = nil, options = {})
405
+ request(:post, uri, data, options)
406
+ end
407
+
408
+ # Reader method for SST token
409
+ #
410
+ # @return uri [String] SST token
411
+ def sst_token
412
+ request_params[:x_gdc_authsst]
413
+ end
414
+
415
+ def stats_table(values = stats)
416
+ sorted = values.sort_by { |_k, v| v[:avg] }
417
+ Terminal::Table.new :headings => %w(title avg min max total calls) do |t|
418
+ overall = {
419
+ :avg => 0,
420
+ :calls => 0,
421
+ :total => 0
422
+ }
423
+
424
+ sorted.each do |l|
425
+ avg = l[1][:avg]
426
+ min = l[1][:min]
427
+ max = l[1][:max]
428
+ total = l[1][:total]
429
+ calls = l[1][:calls]
430
+
431
+ row = [
432
+ l[0],
433
+ sprintf('%.3f', avg),
434
+ sprintf('%.3f', min),
435
+ sprintf('%.3f', max),
436
+ sprintf('%.3f', total),
437
+ calls
438
+ ]
439
+
440
+ overall[:min] = min if overall[:min].nil? || min < overall[:min]
441
+ overall[:max] = max if overall[:max].nil? || max > overall[:max]
442
+ overall[:total] += total
443
+ overall[:calls] += calls
444
+ overall[:avg] += avg
445
+
446
+ t.add_row row
447
+ end
448
+
449
+ overall[:avg] = overall[:avg] / sorted.length
450
+ row = [
451
+ 'TOTAL',
452
+ sprintf('%.3f', overall[:avg]),
453
+ sprintf('%.3f', overall[:min]),
454
+ sprintf('%.3f', overall[:max]),
455
+ sprintf('%.3f', overall[:total]),
456
+ overall[:calls]
457
+ ]
458
+
459
+ t.add_row :separator
460
+ t.add_row row
461
+ end
462
+ end
463
+
464
+ # Reader method for TT token
465
+ #
466
+ # @return uri [String] TT token
467
+ def tt_token
468
+ request_params[:x_gdc_authtt]
469
+ end
470
+
471
+ # Uploads a file to GoodData server
472
+
473
+ def upload(file, options = {})
474
+ dir = options[:directory] || ''
475
+ staging_uri = options[:staging_url].to_s
476
+ url = dir.empty? ? staging_uri : URI.join("#{server}", staging_uri, "#{dir}/").to_s
477
+ # Make a directory, if needed
478
+ create_webdav_dir_if_needed url unless dir.empty?
479
+
480
+ webdav_filename = options[:filename] || File.basename(file)
481
+ do_stream_file URI.join("#{server}", url, CGI.escape(webdav_filename)), file
482
+ end
483
+
484
+ def generate_request_id
485
+ "#{session_id}:#{call_id}"
486
+ end
487
+
488
+ private
489
+
490
+ def create_webdav_dir_if_needed(url)
491
+ return if webdav_dir_exists?(url)
492
+
493
+ method = :mkcol
494
+ b = proc do
495
+ raw = {
496
+ :method => method,
497
+ :url => url,
498
+ :headers => @webdav_headers.merge(:x_gdc_authtt => headers[:x_gdc_authtt]),
499
+ :verify_ssl => verify_ssl
500
+ }
501
+ RestClient::Request.execute(raw)
502
+ end
503
+
504
+ GoodData::Rest::Connection.retryable(:tries => Helpers::GD_MAX_RETRY, :refresh_token => proc { refresh_token }) do
505
+ b.call
506
+ end
507
+ end
508
+
509
+ def do_stream_file(uri, filename, _options = {})
510
+ GoodData.logger.info "Uploading file user storage #{uri}"
511
+
512
+ request = RestClient::Request.new(:method => :put,
513
+ :url => uri.to_s,
514
+ :verify_ssl => verify_ssl,
515
+ :headers => @webdav_headers.merge(:x_gdc_authtt => headers[:x_gdc_authtt]),
516
+ :payload => File.new(filename, 'rb'))
517
+
518
+ begin
519
+ request.execute
520
+ rescue => e
521
+ GoodData.logger.error("Error when uploading file #{filename}", e)
522
+ raise e
523
+ end
524
+ end
525
+
526
+ def format_error(e, params = {})
527
+ return e unless e.respond_to?(:response)
528
+ error = MultiJson.load(e.response)
529
+ message = GoodData::Helpers.interpolate_error_message(error)
530
+ if error && error['error'] && error['error']['errorClass'] == 'com.gooddata.security.authorization.AuthorizationFailedException'
531
+ message = "#{message}, accessing with #{user['accountSetting']['login']}"
532
+ end
533
+ <<-ERR
534
+
535
+ #{e}: #{message}
536
+ Request ID: #{params[:x_gdc_request]}
537
+ Full response:
538
+ #{JSON.pretty_generate(error)}
539
+ Backtrace:\n#{e.backtrace.join("\n")}
540
+ ERR
541
+ rescue MultiJson::ParseError
542
+ "Failed to parse #{e}. Raw response: #{e.response}"
543
+ end
544
+
545
+ # generate session id to be passed as the first part to
546
+ # x_gdc_request header
547
+ def session_id
548
+ @session_id ||= Connection.generate_string
549
+ end
550
+
551
+ def call_id
552
+ Connection.generate_string
553
+ end
554
+
555
+ def generate_session_id
556
+ @session_id = Connection.generate_string
557
+ end
558
+
559
+ def clear_session_id
560
+ @session_id = nil
561
+ end
562
+
563
+ # log info_message given in options and make sure request_id is there
564
+ def log_info(options)
565
+ # if info_message given, log it with request_id (given or generated)
566
+ if options[:info_message]
567
+ GoodData.logger.info "#{options[:info_message]} Request id: #{options[:request_id]}"
568
+ end
569
+ end
570
+
571
+ # request heders with freshly generated request id
572
+ def fresh_request_params(request_id = nil)
573
+ tt = { :x_gdc_authtt => tt_token }
574
+ tt.merge(:x_gdc_request => request_id || generate_request_id)
575
+ end
576
+
577
+ def merge_headers!(headers)
578
+ @request_params.merge! headers.slice(:x_gdc_authtt, :x_gdc_authsst)
579
+ end
580
+
581
+ def process_response(options = {}, &block)
582
+ retries = options[:tries] || Helpers::GD_MAX_RETRY
583
+ process = options[:process]
584
+ dont_reauth = options[:dont_reauth]
585
+ options = options.reject { |k, _| [:process, :dont_reauth].include?(k) }
586
+ opts = { tries: retries, refresh_token: proc { refresh_token unless dont_reauth } }.merge(options)
587
+ response = GoodData::Rest::Connection.retryable(opts) do
588
+ block.call
589
+ end
590
+ merge_headers! response.headers
591
+ content_type = response.headers[:content_type]
592
+ return response if process == false
593
+ if content_type == 'application/json' || content_type == 'application/json;charset=UTF-8'
594
+ result = response.to_str == '""' ? {} : MultiJson.load(response.to_str)
595
+ GoodData.rest_logger.debug "Request ID: #{response.headers[:x_gdc_request]} - Response: #{result.inspect}"
596
+ elsif ['text/plain;charset=UTF-8', 'text/plain; charset=UTF-8', 'text/plain'].include?(content_type)
597
+ result = response
598
+ GoodData.rest_logger.debug 'Response: plain text'
599
+ elsif content_type == 'application/zip'
600
+ result = response
601
+ GoodData.rest_logger.debug 'Response: a zipped stream'
602
+ elsif content_type == 'text/csv'
603
+ result = response
604
+ GoodData.rest_logger.debug 'Response: CSV text'
605
+ elsif response.headers[:content_length].to_s == '0'
606
+ result = nil
607
+ GoodData.rest_logger.debug 'Response: Empty response possibly 204'
608
+ elsif response.code == 204
609
+ result = nil
610
+ GoodData.rest_logger.debug 'Response: 204 no content'
611
+ elsif response.code == 200 && content_type.nil? && response.body.empty?
612
+ result = nil
613
+ # TMA-696
614
+ GoodData.rest_logger.warn 'Got response status 200 but no content-type and body.'
615
+ else
616
+ fail "Unsupported response content type '%s':\n%s" % [content_type, response.to_str[0..127]]
617
+ end
618
+ result
619
+ rescue RestClient::Exception => e
620
+ GoodData.logger.error "Response: #{e.response}"
621
+ raise $ERROR_INFO
622
+ end
623
+
624
+ def profile(title, &block)
625
+ t1 = Time.now
626
+ res = block.call
627
+ t2 = Time.now
628
+ delta = t2 - t1
629
+
630
+ update_stats title, delta
631
+ res
632
+ end
633
+
634
+ def reset_headers!
635
+ @request_params = {}
636
+ end
637
+
638
+ def scrub_params(params, keys)
639
+ keys = keys.reduce([]) { |acc, elem| acc.concat([elem.to_s, elem.to_sym]) }
640
+
641
+ new_params = GoodData::Helpers.deep_dup(params)
642
+ GoodData::Helpers.hash_dfs(new_params) do |k, _key|
643
+ keys.each do |key_to_scrub|
644
+ k[key_to_scrub] = ('*' * k[key_to_scrub].length) if k && k.key?(key_to_scrub) && k[key_to_scrub]
645
+ end
646
+ end
647
+ new_params
648
+ end
649
+
650
+ # TODO: Store PH_MAP for wildcarding of URLs in reports in separate file
651
+ PH_MAP = [
652
+ ['/gdc/account/profile/{id}', %r{/gdc/account/profile/[\w]+}],
653
+ ['/gdc/account/login/{id}', %r{/gdc/account/login/[\w]+}],
654
+ ['/gdc/account/domains/{id}/users?login={login}', %r{/gdc/account/domains/[\w\d-]+/users\?login=[^&$]+}],
655
+ ['/gdc/account/domains/{id}', %r{/gdc/account/domains/[\w\d-]+}],
656
+
657
+ ['/gdc/projects/{id}/execute', %r{/gdc/projects/[\w]+/execute}],
658
+
659
+ ['/gdc/datawarehouse/instances/{id}', %r{/gdc/datawarehouse/instances/[\w]+}],
660
+ ['/gdc/datawarehouse/executions/{id}', %r{/gdc/datawarehouse/executions/[\w]+}],
661
+
662
+ ['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}',
663
+ %r{/gdc/domains/[\w-]+/segments/[\w-]+/synchronizeClients/results/[\w]+/details/\?offset=[\d]+&limit=[\d]+}],
664
+ ['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}',
665
+ %r{/gdc/domains/[\w-]+/segments/[\w-]+/synchronizeClients/results/[\w]+}],
666
+ ['/gdc/domains/{id}/segments/{segment}/', %r{/gdc/domains/[\w-]+/segments/[\w-]+/}],
667
+ ['/gdc/domains/{id}/segments/{segment}', %r{/gdc/domains/[\w-]+/segments/[\w-]+}],
668
+ ['/gdc/domains/{id}/clients?segment={segment}', %r{/gdc/domains/[\w-]+/clients\?segment=[\w-]+}],
669
+ ['/gdc/domains/{id}/clients/{client_id}/settings/lcm.title', %r{/gdc/domains/[\w-]+/clients/[\w-]+/settings/lcm.title}],
670
+ ['/gdc/domains/{id}/clients/{client_id}/settings/lcm.token', %r{/gdc/domains/[\w-]+/clients/[\w-]+/settings/lcm.token}],
671
+ ['/gdc/domains/{id}/clients/{client_id}', %r{/gdc/domains/[\w-]+/clients/[\w-]+}],
672
+ ['/gdc/domains/{id}/provisionClientProjects/results/{result}/details?offset={offset}&limit={limit}',
673
+ %r{/gdc/domains/[\w-]+/provisionClientProjects/results/[\w]+/details/\?offset=[\d]+&limit=[\d]+}],
674
+ ['/gdc/domains/{id}/provisionClientProjects/results/{result}', %r{/gdc/domains/[\w-]+/provisionClientProjects/results/[\w]+}],
675
+ ['/gdc/domains/{id}/provisionClientProjects', %r{/gdc/domains/[\w-]+/provisionClientProjects}],
676
+ ['/gdc/domains/{id}/updateClients', %r{/gdc/domains/[\w-]+/updateClients}],
677
+ ['/gdc/domains/{id}/', %r{/gdc/domains/[\w-]+/}],
678
+
679
+ ['/gdc/exporter/result/{id}/{id}', %r{/gdc/exporter/result/[\w]+/[\w]+}],
680
+
681
+ ['/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses/{process}',
682
+ %r{/gdc/internal/lcm/domains/[\w-]+/dataproducts/[\w-]+/segments/[\w-]+/syncProcesses/[\w]+}],
683
+ ['/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses',
684
+ %r{/gdc/internal/lcm/domains/[\w-]+/dataproducts/[\w-]+/segments/[\w-]+/syncProcesses}],
685
+
686
+ ['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[\w]+/objects/setPermissions}],
687
+
688
+ ['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[\w]+/variables/item/[\d]+}],
689
+ ['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[\w]+/validate/task/[\w]+}],
690
+ ['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[\w]+/using2/[\d]+/[\d]+}],
691
+ ['/gdc/md/{id}/using2/{id}', %r{/gdc/md/[\w]+/using2/[\d]+}],
692
+ ['/gdc/md/{id}/userfilters?users={users}', %r{/gdc/md/[\w]+/userfilters\?users=[/\w]+}],
693
+ ['/gdc/md/{id}/userfilters?count={count}&offset={offset}', %r{/gdc/md/[\w]+/userfilters\?count=[\d]+&offset=[\d]+}],
694
+ ['/gdc/md/{id}/usedby2/{id}/{id}', %r{/gdc/md/[\w]+/usedby2/[\d]+/[\d]+}],
695
+ ['/gdc/md/{id}/usedby2/{id}', %r{/gdc/md/[\w]+/usedby2/[\d]+}],
696
+ ['/gdc/md/{id}/tasks/{id}/status', %r{/gdc/md/[\w]+/tasks/[\w]+/status}],
697
+ ['/gdc/md/{id}/obj/{id}/validElements', %r{/gdc/md/[\w]+/obj/[\d]+/validElements(/)?(\?.*)?}],
698
+ ['/gdc/md/{id}/obj/{id}/elements', %r{/gdc/md/[\w]+/obj/[\d]+/elements(/)?(\?.*)?}],
699
+ ['/gdc/md/{id}/obj/{id}', %r{/gdc/md/[\w]+/obj/[\d]+}],
700
+ ['/gdc/md/{id}/etltask/{id}', %r{/gdc/md/[\w]+/etltask/[\w]+}],
701
+ ['/gdc/md/{id}/dataResult/{id}', %r{/gdc/md/[\w]+/dataResult/[\d]+}],
702
+ ['/gdc/md/{id}', %r{/gdc/md/[\w]+}],
703
+
704
+ ['/gdc/projects/{id}/users/{id}/roles', %r{/gdc/projects/[\w]+/users/[\w]+/roles}],
705
+ ['/gdc/projects/{id}/users/{id}/permissions', %r{/gdc/projects/[\w]+/users/[\w]+/permissions}],
706
+ ['/gdc/projects/{id}/users', %r{/gdc/projects/[\w]+/users}],
707
+ ['/gdc/projects/{id}/schedules/{id}/executions/{id}', %r{/gdc/projects/[\w]+/schedules/[\w]+/executions/[\w]+}],
708
+ ['/gdc/projects/{id}/schedules/{id}', %r{/gdc/projects/[\w]+/schedules/[\w]+}],
709
+ ['/gdc/projects/{id}/roles/{id}', %r{/gdc/projects/[\w]+/roles/[\d]+}],
710
+ ['/gdc/projects/{id}/model/view/{id}', %r{/gdc/projects/[\w]+/model/view/[\w]+}],
711
+ ['/gdc/projects/{id}/model/view', %r{/gdc/projects/[\w]+/model/view}],
712
+ ['/gdc/projects/{id}/model/diff/{id}', %r{/gdc/projects/[\w]+/model/diff/[\w]+}],
713
+ ['/gdc/projects/{id}/model/diff', %r{/gdc/projects/[\w]+/model/diff}],
714
+ ['/gdc/projects/{id}/dataload/processes/{id}/executions/{id}', %r{/gdc/projects/[\w]+/dataload/processes/[\w-]+/executions/[\w-]+}],
715
+ ['/gdc/projects/{id}/dataload/processes/{id}', %r{/gdc/projects/[\w]+/dataload/processes/[\w-]+}],
716
+ ['/gdc/projects/{id}/', %r{/gdc/projects/[\w]+/}],
717
+ ['/gdc/projects/{id}', %r{/gdc/projects/[\w]+}]
718
+ ]
719
+
720
+ def update_stats(title, delta)
721
+ synchronize do
722
+ orig_title = title
723
+
724
+ placeholders = true
725
+
726
+ if placeholders
727
+ PH_MAP.each do |pm|
728
+ break if title.gsub!(pm[1], pm[0])
729
+ end
730
+ end
731
+
732
+ stat = stats[title]
733
+ if stat.nil?
734
+ stat = {
735
+ :min => delta,
736
+ :max => delta,
737
+ :total => 0,
738
+ :avg => 0,
739
+ :calls => 0,
740
+ :entries => []
741
+ }
742
+ end
743
+
744
+ stat[:min] = delta if delta < stat[:min]
745
+ stat[:max] = delta if delta > stat[:max]
746
+ stat[:total] += delta
747
+ stat[:calls] += 1
748
+ stat[:avg] = stat[:total] / stat[:calls]
749
+
750
+ stat[:entries] << orig_title if placeholders
751
+
752
+ stats[title] = stat
753
+ end
754
+ end
755
+
756
+ def webdav_dir_exists?(url)
757
+ method = :get
758
+ GoodData.logger.debug "#{method}: #{url}"
759
+
760
+ GoodData::Rest::Connection.retryable(:tries => Helpers::GD_MAX_RETRY, :refresh_token => proc { refresh_token }) do
761
+ raw = {
762
+ :method => method,
763
+ :url => url,
764
+ :headers => @webdav_headers.merge(:x_gdc_authtt => headers[:x_gdc_authtt]),
765
+ :verify_ssl => verify_ssl
766
+ }.merge(headers)
767
+ begin
768
+ RestClient::Request.execute(raw)
769
+ rescue RestClient::Exception => e
770
+ false if e.http_code == 404
771
+ end
772
+ end
773
+ end
774
+ end
775
+ end
776
+ end