gooddata 1.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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