dtk-shell 0.10.0

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 (191) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile_dev +13 -0
  4. data/README.md +121 -0
  5. data/bin/dtk-execute +32 -0
  6. data/bin/dtk-run +92 -0
  7. data/bin/dtk-shell +31 -0
  8. data/dtk-shell.gemspec +50 -0
  9. data/lib/auxiliary.rb +61 -0
  10. data/lib/bundler_monkey_patch.rb +26 -0
  11. data/lib/client.rb +58 -0
  12. data/lib/command_helper.rb +33 -0
  13. data/lib/command_helpers/git_repo.rb +589 -0
  14. data/lib/command_helpers/git_repo/merge.rb +153 -0
  15. data/lib/command_helpers/jenkins_client.rb +106 -0
  16. data/lib/command_helpers/jenkins_client/config_xml.rb +288 -0
  17. data/lib/command_helpers/service_importer.rb +251 -0
  18. data/lib/command_helpers/service_link.rb +33 -0
  19. data/lib/command_helpers/test_module_creator.rb +69 -0
  20. data/lib/command_helpers/test_module_templates/dtk.model.yaml.eruby +10 -0
  21. data/lib/command_helpers/test_module_templates/spec_helper.rb.eruby +10 -0
  22. data/lib/command_helpers/test_module_templates/temp_component_spec.rb.eruby +5 -0
  23. data/lib/commands.rb +57 -0
  24. data/lib/commands/common/thor/access_control.rb +133 -0
  25. data/lib/commands/common/thor/action_result_handler.rb +74 -0
  26. data/lib/commands/common/thor/assembly_template.rb +92 -0
  27. data/lib/commands/common/thor/assembly_workspace.rb +1801 -0
  28. data/lib/commands/common/thor/base_command_helper.rb +59 -0
  29. data/lib/commands/common/thor/clone.rb +82 -0
  30. data/lib/commands/common/thor/common.rb +88 -0
  31. data/lib/commands/common/thor/common_base.rb +49 -0
  32. data/lib/commands/common/thor/create_target.rb +70 -0
  33. data/lib/commands/common/thor/edit.rb +255 -0
  34. data/lib/commands/common/thor/inventory_parser.rb +98 -0
  35. data/lib/commands/common/thor/list_diffs.rb +128 -0
  36. data/lib/commands/common/thor/module.rb +1011 -0
  37. data/lib/commands/common/thor/module/import.rb +210 -0
  38. data/lib/commands/common/thor/node.rb +53 -0
  39. data/lib/commands/common/thor/poller.rb +65 -0
  40. data/lib/commands/common/thor/pull_clone_changes.rb +28 -0
  41. data/lib/commands/common/thor/pull_from_remote.rb +152 -0
  42. data/lib/commands/common/thor/puppet_forge.rb +72 -0
  43. data/lib/commands/common/thor/purge_clone.rb +101 -0
  44. data/lib/commands/common/thor/push_clone_changes.rb +162 -0
  45. data/lib/commands/common/thor/push_to_remote.rb +94 -0
  46. data/lib/commands/common/thor/remotes.rb +71 -0
  47. data/lib/commands/common/thor/reparse.rb +40 -0
  48. data/lib/commands/common/thor/set_required_attributes.rb +46 -0
  49. data/lib/commands/thor/account.rb +239 -0
  50. data/lib/commands/thor/assembly.rb +356 -0
  51. data/lib/commands/thor/attribute.rb +79 -0
  52. data/lib/commands/thor/component.rb +70 -0
  53. data/lib/commands/thor/component_module.rb +501 -0
  54. data/lib/commands/thor/component_template.rb +174 -0
  55. data/lib/commands/thor/dependency.rb +34 -0
  56. data/lib/commands/thor/developer.rb +144 -0
  57. data/lib/commands/thor/dtk.rb +152 -0
  58. data/lib/commands/thor/library.rb +125 -0
  59. data/lib/commands/thor/node.rb +504 -0
  60. data/lib/commands/thor/node_template.rb +94 -0
  61. data/lib/commands/thor/project.rb +34 -0
  62. data/lib/commands/thor/provider.rb +233 -0
  63. data/lib/commands/thor/remotes.rb +49 -0
  64. data/lib/commands/thor/service.rb +941 -0
  65. data/lib/commands/thor/service_module.rb +914 -0
  66. data/lib/commands/thor/state_change.rb +25 -0
  67. data/lib/commands/thor/target.rb +250 -0
  68. data/lib/commands/thor/task.rb +116 -0
  69. data/lib/commands/thor/test_module.rb +310 -0
  70. data/lib/commands/thor/utils.rb +21 -0
  71. data/lib/commands/thor/workspace.rb +685 -0
  72. data/lib/config/cacert.pem +3785 -0
  73. data/lib/config/client.conf.header +20 -0
  74. data/lib/config/configuration.rb +99 -0
  75. data/lib/config/default.conf +16 -0
  76. data/lib/config/disk_cacher.rb +80 -0
  77. data/lib/configurator.rb +176 -0
  78. data/lib/context_router.rb +44 -0
  79. data/lib/core.rb +497 -0
  80. data/lib/domain/git_adapter.rb +412 -0
  81. data/lib/domain/git_error_handler.rb +64 -0
  82. data/lib/domain/response.rb +285 -0
  83. data/lib/domain/response/error_handler.rb +86 -0
  84. data/lib/dtk-shell/version.rb +20 -0
  85. data/lib/dtk_constants.rb +40 -0
  86. data/lib/dtk_error.rb +114 -0
  87. data/lib/dtk_logger.rb +126 -0
  88. data/lib/dtk_shell.rb +31 -0
  89. data/lib/error.rb +85 -0
  90. data/lib/execute.rb +29 -0
  91. data/lib/execute/cli_pure/cli_rerouter.rb +102 -0
  92. data/lib/execute/command.rb +40 -0
  93. data/lib/execute/command/api_call.rb +60 -0
  94. data/lib/execute/command/api_call/map.rb +60 -0
  95. data/lib/execute/command/api_call/service.rb +91 -0
  96. data/lib/execute/command/api_call/translation_term.rb +119 -0
  97. data/lib/execute/command/rest_call.rb +37 -0
  98. data/lib/execute/command_processor.rb +30 -0
  99. data/lib/execute/command_processor/rest_call.rb +59 -0
  100. data/lib/execute/error_usage.rb +21 -0
  101. data/lib/execute/execute_context.rb +86 -0
  102. data/lib/execute/execute_context/result_store.rb +37 -0
  103. data/lib/execute/script.rb +64 -0
  104. data/lib/execute/script/add_tenant.rb +121 -0
  105. data/lib/git-logs/git.log +0 -0
  106. data/lib/parser/adapters/option_parser.rb +70 -0
  107. data/lib/parser/adapters/thor.rb +555 -0
  108. data/lib/parser/adapters/thor/common_option_defs.rb +40 -0
  109. data/lib/require_first.rb +104 -0
  110. data/lib/search_hash.rb +44 -0
  111. data/lib/shell.rb +261 -0
  112. data/lib/shell/context.rb +1065 -0
  113. data/lib/shell/context_aux.rb +46 -0
  114. data/lib/shell/domain/active_context.rb +186 -0
  115. data/lib/shell/domain/context_entity.rb +89 -0
  116. data/lib/shell/domain/context_params.rb +223 -0
  117. data/lib/shell/domain/override_tasks.rb +88 -0
  118. data/lib/shell/domain/shadow_entity.rb +76 -0
  119. data/lib/shell/header_shell.rb +44 -0
  120. data/lib/shell/help_monkey_patch.rb +283 -0
  121. data/lib/shell/interactive_wizard.rb +225 -0
  122. data/lib/shell/message_queue.rb +63 -0
  123. data/lib/shell/parse_monkey_patch.rb +39 -0
  124. data/lib/shell/status_monitor.rb +124 -0
  125. data/lib/task_status.rb +83 -0
  126. data/lib/task_status/refresh_mode.rb +77 -0
  127. data/lib/task_status/snapshot_mode.rb +28 -0
  128. data/lib/task_status/stream_mode.rb +48 -0
  129. data/lib/task_status/stream_mode/element.rb +101 -0
  130. data/lib/task_status/stream_mode/element/format.rb +101 -0
  131. data/lib/task_status/stream_mode/element/hierarchical_task.rb +100 -0
  132. data/lib/task_status/stream_mode/element/hierarchical_task/result.rb +72 -0
  133. data/lib/task_status/stream_mode/element/hierarchical_task/result/action.rb +93 -0
  134. data/lib/task_status/stream_mode/element/hierarchical_task/result/components.rb +26 -0
  135. data/lib/task_status/stream_mode/element/hierarchical_task/result/node_level.rb +26 -0
  136. data/lib/task_status/stream_mode/element/hierarchical_task/steps.rb +34 -0
  137. data/lib/task_status/stream_mode/element/hierarchical_task/steps/action.rb +53 -0
  138. data/lib/task_status/stream_mode/element/hierarchical_task/steps/components.rb +53 -0
  139. data/lib/task_status/stream_mode/element/hierarchical_task/steps/node_level.rb +42 -0
  140. data/lib/task_status/stream_mode/element/no_results.rb +26 -0
  141. data/lib/task_status/stream_mode/element/render.rb +59 -0
  142. data/lib/task_status/stream_mode/element/stage.rb +84 -0
  143. data/lib/task_status/stream_mode/element/stage/render.rb +76 -0
  144. data/lib/task_status/stream_mode/element/task_end.rb +35 -0
  145. data/lib/task_status/stream_mode/element/task_start.rb +37 -0
  146. data/lib/util/common_util.rb +37 -0
  147. data/lib/util/console.rb +235 -0
  148. data/lib/util/dtk_puppet.rb +65 -0
  149. data/lib/util/module_util.rb +66 -0
  150. data/lib/util/os_util.rb +385 -0
  151. data/lib/util/permission_util.rb +31 -0
  152. data/lib/util/remote_dependency_util.rb +84 -0
  153. data/lib/util/ssh_util.rb +94 -0
  154. data/lib/view_processor.rb +129 -0
  155. data/lib/view_processor/augmented_simple_list.rb +44 -0
  156. data/lib/view_processor/hash_pretty_print.rb +123 -0
  157. data/lib/view_processor/simple_list.rb +156 -0
  158. data/lib/view_processor/table_print.rb +309 -0
  159. data/lib/violation.rb +86 -0
  160. data/lib/violation/attribute.rb +76 -0
  161. data/lib/violation/fix.rb +26 -0
  162. data/lib/violation/fix/result.rb +73 -0
  163. data/lib/violation/fix/result/error.rb +34 -0
  164. data/lib/violation/fix/set_attribute.rb +41 -0
  165. data/lib/violation/sub_classes.rb +60 -0
  166. data/puppet/manifests/init.pp +72 -0
  167. data/puppet/manifests/params.pp +16 -0
  168. data/puppet/r8meta.puppet.yml +35 -0
  169. data/puppet/templates/bash_profile.erb +2 -0
  170. data/puppet/templates/client.conf.erb +1 -0
  171. data/puppet/templates/dtkclient.erb +2 -0
  172. data/spec/component_module_spec.rb +34 -0
  173. data/spec/dependency_spec.rb +6 -0
  174. data/spec/dtk_shell_spec.rb +13 -0
  175. data/spec/dtk_spec.rb +33 -0
  176. data/spec/lib/spec_helper.rb +10 -0
  177. data/spec/lib/spec_thor.rb +108 -0
  178. data/spec/node_template_spec.rb +24 -0
  179. data/spec/project_spec.rb +6 -0
  180. data/spec/repo_spec.rb +7 -0
  181. data/spec/response_spec.rb +52 -0
  182. data/spec/service_module_spec.rb +38 -0
  183. data/spec/service_spec.rb +50 -0
  184. data/spec/state_change_spec.rb +7 -0
  185. data/spec/table_print_spec.rb +48 -0
  186. data/spec/target_spec.rb +57 -0
  187. data/spec/task_spec.rb +28 -0
  188. data/views/assembly/augmented_simple_list.rb +12 -0
  189. data/views/assembly_template/augmented_simple_list.rb +12 -0
  190. data/views/list_task/augmented_simple_list.rb +12 -0
  191. metadata +421 -0
@@ -0,0 +1,20 @@
1
+ development_mode=false
2
+ meta_table_ttl=7200000 # time to live (ms)
3
+ meta_constants_ttl=7200000 # time to live (ms)
4
+ meta_pretty_print_ttl=7200000 # time to live (ms)
5
+ task_check_frequency=60 # check frequency for task status threads (seconds)
6
+ tail_log_frequency=2 # assembly - frequency between requests (seconds)
7
+ debug_task_frequency=5 # assembly - frequency between requests (seconds)
8
+ auto_commit_changes=false # autocommit for modules
9
+ verbose_rest_calls=false # logging of REST calls
10
+
11
+ # if relative path is used we will use HOME + relative path, apsoluth path will override this
12
+ module_location=component_modules
13
+ service_location=service_modules
14
+ test_module_location=test_modules
15
+ backups_location=backups
16
+
17
+ # server connection details
18
+ server_port=80
19
+ secure_connection_server_port=443
20
+ secure_connection=true
@@ -0,0 +1,99 @@
1
+ #
2
+ # Copyright (C) 2010-2016 dtk contributors
3
+ #
4
+ # This file is part of the dtk project.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ #
19
+ # Singleton patern to hold configuration for dtk client.
20
+ #
21
+ # DEFAULT: Configuration
22
+ # DEVELOPMENT: Can add lib/config/local.conf, this is git ignored
23
+ #
24
+ # NOTE: Singleton here is not necessery since it will not persist in memory due
25
+ # to nature of DTK Client, but it is right approach for possible re-use
26
+ #
27
+ # Pririoty of load
28
+ # 1) LOCAL
29
+ # 2) EXTERNAL
30
+ # 3) DEFAULT
31
+ #
32
+ # NOTE: Default will be used if there some parameters missing in other configuration
33
+ #
34
+ require 'singleton'
35
+
36
+ dtk_require_from_base('util/os_util')
37
+
38
+ module DTK
39
+ class Configuration
40
+ include Singleton
41
+
42
+ EXTERNAL_APP_CONF = "client.conf"
43
+ DEVELOPMENT_CONF = 'local.conf'
44
+ DEFAULT_CONF = 'default.conf'
45
+
46
+ def self.get(name, default=nil)
47
+ Configuration.instance.get(name, default)
48
+ end
49
+
50
+ def self.[](k)
51
+ Configuration.instance.get(k)
52
+ end
53
+
54
+ def initialize
55
+ # default configuration
56
+ @cache = load_configuration_to_hash(File.expand_path("../#{DEFAULT_CONF}",__FILE__))
57
+
58
+ # we will not use local.conf from gemfile because client.conf is required so this is deprecated
59
+ if File.exist?(File.expand_path("../#{DEVELOPMENT_CONF}",__FILE__))
60
+ local_configuration = load_configuration_to_hash(File.expand_path("../#{DEVELOPMENT_CONF}",__FILE__))
61
+ # we override only values from local configuration
62
+ # that way developer does not have updates its local configuration all the time
63
+ @cache.merge!(local_configuration)
64
+ # if we have loaded local configuration we will not check external
65
+ return
66
+ end
67
+
68
+ # We load this if there is no local configuration
69
+ external_file_location = File.join(::DTK::Client::OsUtil.dtk_local_folder(), "#{EXTERNAL_APP_CONF}")
70
+
71
+ if File.exist?(external_file_location)
72
+ external_configuration = load_configuration_to_hash(external_file_location)
73
+ @cache.merge!(external_configuration)
74
+ end
75
+ end
76
+
77
+ def get(name, default=nil)
78
+ return @cache[name.to_s] || default
79
+ end
80
+
81
+ private
82
+
83
+ def load_configuration_to_hash(path_to_file)
84
+ configuration = Hash[*File.read(path_to_file).gsub(/#.+/,'').strip().gsub(/( |\t)+$/,'').split(/[=\n\r\r\n]+/)]
85
+
86
+ # check for types
87
+ return configuration.each do |k,v|
88
+ case v
89
+ when /^(true|false)$/
90
+ configuration[k] = v.eql?('true') ? true : false
91
+ when /^[0-9]+$/
92
+ configuration[k] = v.to_i
93
+ when /^[0-9\.]+$/
94
+ configuration[k] = v.to_f
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,16 @@
1
+ development_mode=false
2
+ debug_grit=false
3
+ meta_table_ttl=7200000 # time to live (ms)
4
+ meta_constants_ttl=7200000 # time to live (ms)
5
+ meta_pretty_print_ttl=7200000 # time to live (ms)
6
+ task_check_frequency=60 # check frequency for task status threads (seconds)
7
+ tail_log_frequency=2 # assembly - frequency between requests (seconds)
8
+ debug_task_frequency=5 # assembly - frequency between requests (seconds)
9
+ auto_commit_changes=false # autocommit for modules
10
+ verbose_rest_calls=false # logging of REST calls
11
+
12
+ # if relative path is used we will use HOME + relative path, apsoluth path will override this
13
+ module_location=component_modules
14
+ service_location=service_modules
15
+ test_module_location=test_modules
16
+ backups_location=backups
@@ -0,0 +1,80 @@
1
+ #
2
+ # Copyright (C) 2010-2016 dtk contributors
3
+ #
4
+ # This file is part of the dtk project.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'net/http'
19
+ #require 'md5' => Ruby 1.8.7 specific
20
+ require File.expand_path('../util/os_util', File.dirname(__FILE__))
21
+ dtk_require("../commands")
22
+
23
+
24
+ #
25
+ # Class dedicated for caching data on local system as well as for cookie management
26
+ #
27
+ class DiskCacher
28
+ include DTK::Client::CommandBase
29
+ extend DTK::Client::CommandBase
30
+
31
+ # file name to hold cookies
32
+ COOKIE_HOLDER_NAME = 'tempdtkstore'
33
+ FILE_DELIMITER = '--'
34
+
35
+ def initialize(cache_dir = DTK::Client::OsUtil.get_temp_location)
36
+ @cache_dir = cache_dir
37
+ @current_user = ::DTK::Client::Configurator.client_username
38
+ end
39
+
40
+ def fetch(file_name, max_age = 0, use_mock_up = true)
41
+ file = Digest::MD5.hexdigest(file_name)
42
+ # current user is important so that there are no clashes in writting to temp file
43
+ # between multiple users on same machine
44
+ file_path = File.join(@cache_dir, "#{@current_user}#{FILE_DELIMITER}#{file}")
45
+
46
+ # we check if the file -- a MD5 hexdigest of the URL -- exists
47
+ # in the dir. If it does and the data is fresh, we just read
48
+ # data from the file and return
49
+ if File.exists? file_path
50
+ return File.new(file_path).read if ((Time.now - File.mtime(file_path)) < max_age)
51
+ end
52
+
53
+ # if the file does not exist (or if the data is not fresh), we
54
+ # make an get request and save it to a file
55
+ response_string = ""
56
+ response = get rest_url("metadata/get_metadata/#{file_name}")
57
+
58
+ if (response["status"] == "ok")
59
+ file = File.open(file_path, "w") do |data|
60
+ data << response_string = response["data"]
61
+ end
62
+ end
63
+
64
+ return response_string
65
+ end
66
+
67
+ def save_cookie(cookie_content)
68
+ file_path = File.join(@cache_dir, COOKIE_HOLDER_NAME)
69
+ File.open(file_path, "w") do |file|
70
+ Marshal.dump(cookie_content, file)
71
+ end
72
+ end
73
+
74
+ def load_cookie
75
+ file_path = File.join(@cache_dir, COOKIE_HOLDER_NAME)
76
+ cookie_content = File.exists?(file_path) ? File.open(file_path) {|f| Marshal.load(f)} : nil
77
+ cookie_content
78
+ end
79
+
80
+ end
@@ -0,0 +1,176 @@
1
+ #
2
+ # Copyright (C) 2010-2016 dtk contributors
3
+ #
4
+ # This file is part of the dtk project.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'rubygems'
19
+ require 'fileutils'
20
+ dtk_require_from_base('util/os_util')
21
+
22
+ module DTK
23
+ module Client
24
+ class Configurator
25
+
26
+ CONFIG_FILE = File.join(OsUtil.dtk_local_folder, "client.conf")
27
+ CRED_FILE = File.join(OsUtil.dtk_local_folder, ".connection")
28
+ DIRECT_ACCESS = File.join(OsUtil.dtk_local_folder, ".add_direct_access")
29
+ NODE_SSH_CREDENTIALS = File.join(OsUtil.dtk_local_folder, "ssh_credentials.yaml")
30
+
31
+ FileUtils.mkdir(OsUtil.dtk_local_folder) unless File.directory?(OsUtil.dtk_local_folder)
32
+
33
+ def self.check_config_exists
34
+ exists = true
35
+ if !File.exists?(CONFIG_FILE)
36
+ puts "", "Please enter the DTK server address (example: instance.dtk.io)"
37
+ header = File.read(File.expand_path('../lib/config/client.conf.header', File.dirname(__FILE__)))
38
+ generate_conf_file(CONFIG_FILE, [['server_host', 'Server address']], header)
39
+ exists = false
40
+ end
41
+ if !File.exists?(CRED_FILE)
42
+ puts "", "Please enter your DTK login details"
43
+ generate_conf_file(CRED_FILE, [['username', 'Username'], ['password', 'Password']], '')
44
+ exists = false
45
+ end
46
+
47
+ exists
48
+ end
49
+
50
+ def self.check_git
51
+ if OsUtil.which('git') == nil
52
+ OsUtil.put_warning "[WARNING]", "Can't find the 'git' command in you path. Please make sure git is installed in order to use all features of DTK Client.", :yellow
53
+ else
54
+ OsUtil.put_warning "[WARNING]", 'Git username not set. This can cause issues while using DTK Client. To set it, run `git config --global user.name "User Name"`', :yellow if `git config --get user.name` == ""
55
+ OsUtil.put_warning "[WARNING]", 'Git email not set. This can cause issues while using DTK Client. To set it, run `git config --global user.email "me@here.com"`', :yellow if `git config --get user.email` == ""
56
+ end
57
+ end
58
+
59
+ # return true/false, .add_direct_access file location and ssk key file location
60
+ def self.check_direct_access
61
+ username_exists = check_for_username_entry(client_username())
62
+ ssh_key_path = SSHUtil.default_rsa_pub_key_path()
63
+
64
+ {:username_exists => username_exists, :file_path => DIRECT_ACCESS, :ssh_key_path => ssh_key_path}
65
+ end
66
+
67
+ def self.generate_conf_file(file_path, properties, header)
68
+ require 'highline/import'
69
+ property_template = []
70
+
71
+ properties.each do |p,d|
72
+ begin
73
+ trap("INT") {
74
+ puts "", "Exiting..."
75
+ abort
76
+ }
77
+ end
78
+ value = ask("#{d}: ") { |q| q.echo = false if p == 'password'}
79
+ property_template << [p,value]
80
+ end
81
+
82
+ File.open(file_path, 'w') do |f|
83
+ f.puts(header)
84
+ property_template.each do |prop|
85
+ f.puts("#{prop[0]}=#{prop[1]}")
86
+ end
87
+ end
88
+ end
89
+
90
+ def self.regenerate_conf_file(file_path, properties, header)
91
+ File.open(file_path, 'w') do |f|
92
+ f.puts(header)
93
+ properties.each do |prop|
94
+ f.puts("#{prop[0]}=#{prop[1]}")
95
+ end
96
+ end
97
+ end
98
+
99
+ def self.create_missing_clone_dirs
100
+ FileUtils.mkdir(OsUtil.component_clone_location) unless File.directory?(OsUtil.component_clone_location)
101
+ FileUtils.mkdir(OsUtil.service_clone_location) unless File.directory?(OsUtil.service_clone_location)
102
+ FileUtils.mkdir(OsUtil.test_clone_location) unless File.directory?(OsUtil.test_clone_location)
103
+ FileUtils.mkdir(OsUtil.backups_location) unless File.directory?(OsUtil.backups_location)
104
+ end
105
+
106
+
107
+ def self.parse_key_value_file(file)
108
+ # adapted from mcollective config
109
+ ret = Hash.new
110
+ raise DTK::Client::DtkError,"Config file (#{file}) does not exists" unless File.exists?(file)
111
+ File.open(file).each do |line|
112
+ # strip blank spaces, tabs etc off the end of all lines
113
+ line.gsub!(/\s*$/, "")
114
+ unless line =~ /^#|^$/
115
+ if (line =~ /(.+?)\s*=\s*(.+)/)
116
+ key = $1
117
+ val = $2
118
+ ret[key.to_sym] = val
119
+ end
120
+ end
121
+ end
122
+ ret
123
+ end
124
+ def self.add_current_user_to_direct_access()
125
+ username = client_username()
126
+
127
+ File.open(DIRECT_ACCESS, 'a') do |file|
128
+ file.puts(username)
129
+ end
130
+
131
+ true
132
+ end
133
+
134
+ def self.client_username()
135
+ parse_key_value_file(CRED_FILE)[:username]
136
+ end
137
+
138
+ #
139
+ # Method will check if there is username entry in DIRECT_ACCESS file
140
+ #
141
+ def self.check_for_username_entry(username)
142
+ if File.exists?(DIRECT_ACCESS)
143
+ File.open(DIRECT_ACCESS).each do |line|
144
+ if line.strip.eql?(username)
145
+ return true
146
+ end
147
+ end
148
+ end
149
+
150
+ return false
151
+ end
152
+
153
+ def self.ask_catalog_credentials()
154
+ are_there_creds = Console.confirmation_prompt("Do you have DTK catalog credentials", true)
155
+ property_template = {}
156
+ if are_there_creds
157
+ property_template = self.enter_catalog_credentials()
158
+ end
159
+
160
+ property_template
161
+ end
162
+
163
+ def self.enter_catalog_credentials()
164
+ property_template = {}
165
+ # needed to preserve the order for ruby 1.8.7
166
+ # ruby 1.8 does not preserve order of insertation
167
+ wizard_values = { :username => 'Catalog Username', :password => 'Catalog Password' }
168
+ [:username, :password].each do |p|
169
+ value = ask("#{wizard_values[p]}: ") { |q| q.echo = false if p == :password }
170
+ property_template.store(p, value)
171
+ end
172
+ property_template
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # Copyright (C) 2010-2016 dtk contributors
3
+ #
4
+ # This file is part of the dtk project.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module DTK
19
+ module Client
20
+
21
+ #
22
+ # This class is used to reroute commands/tasks (Method invocations) from one context (Class) to another
23
+ #
24
+ class ContextRouter
25
+
26
+ extend DTK::Client::Auxiliary
27
+
28
+ # This method invokes target context task
29
+ def self.routeTask(target_context, target_method, target_context_params, conn)
30
+ target_context = target_context.to_s
31
+ target_method = target_method.to_s
32
+
33
+ # Initing required params and invoking target_context.target_method
34
+ load_command(target_context)
35
+ target_context_class = DTK::Client.const_get "#{cap_form(target_context)}"
36
+
37
+ ret = target_context_class.execute_from_cli(conn, target_method, target_context_params, [], false)
38
+ ret.kind_of?(Response::NoOp) ? Response::Ok.new() : ret
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,497 @@
1
+ #
2
+ # Copyright (C) 2010-2016 dtk contributors
3
+ #
4
+ # This file is part of the dtk project.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ #TODO: user common utils in DTK::Common::Rest
19
+
20
+ require 'rubygems'
21
+ require 'singleton'
22
+ require 'restclient'
23
+ require 'colorize'
24
+ require 'json'
25
+ require 'pp'
26
+
27
+ # Development Gems
28
+ if ::DTK::Configuration.get(:development_mode)
29
+ require 'ap'
30
+ # require 'looksee'
31
+ end
32
+
33
+ #TODO: for testing; fix by pass in commadn line argument
34
+ #RestClient.log = STDOUT
35
+
36
+ dtk_require_from_base('domain/response')
37
+ dtk_require_from_base('util/os_util')
38
+ dtk_require_from_base('util/ssh_util')
39
+ dtk_require_from_base('util/common_util')
40
+ dtk_require_from_base('util/permission_util')
41
+ dtk_require_from_base('util/remote_dependency_util')
42
+ dtk_require_from_base('util/module_util')
43
+ dtk_require_from_base('shell/message_queue')
44
+
45
+ dtk_require("config/configuration")
46
+
47
+ def top_level_execute(entity_name, method_name, context_params=nil, options_args=nil, shell_execute=false)
48
+ begin
49
+ top_level_execute_core(entity_name, method_name, context_params, options_args, shell_execute)
50
+ rescue DTK::Client::DtkLoginRequiredError
51
+ # re-logging user and repeating request
52
+ DTK::Client::OsUtil.print("Session expired: re-establishing session & repeating given task", :yellow)
53
+ DTK::Client::Session.re_initialize
54
+ top_level_execute_core(entity_name, method_name, context_params, options_args, shell_execute)
55
+ end
56
+ end
57
+
58
+ def top_level_execute_core(entity_name, method_name, context_params=nil, options_args=nil, shell_execute=false)
59
+ extend DTK::Client::OsUtil
60
+
61
+ entity_class = nil
62
+
63
+ begin
64
+ include DTK::Client::Auxiliary
65
+
66
+ entity_name = entity_name.gsub("-","_")
67
+ load_command(entity_name)
68
+ conn = DTK::Client::Session.get_connection
69
+
70
+ # if connection parameters are not set up properly then don't execute any command
71
+ return if validate_connection(conn)
72
+
73
+ # call proper thor class and task
74
+ entity_class = DTK::Client.const_get "#{cap_form(entity_name)}"
75
+
76
+ # call forwarding, in case there is no task for given entity we switch to last (n-context) and try than
77
+ unless (entity_class.task_names.include?(method_name))
78
+ entity_class = DTK::Client.const_get "#{cap_form(context_params.last_entity_name.to_s)}"
79
+ end
80
+
81
+ response_ruby_obj = entity_class.execute_from_cli(conn,method_name,context_params,options_args,shell_execute)
82
+
83
+ # it will raise DTK::Client::Error in case of error response
84
+ print_method_response!(response_ruby_obj)
85
+
86
+ # process/print queued message from server
87
+ DTK::Shell::MessageQueue.print_messages
88
+
89
+ rescue DTK::Client::DtkLoginRequiredError => e
90
+ # this error is handled in method above
91
+ raise e
92
+ rescue DTK::Client::DSLParsing => e
93
+ DTK::Client::OsUtil.print(e.message, :red)
94
+ rescue DTK::Client::DtkValidationError => e
95
+ validation_message = e.message
96
+
97
+ # if !e.skip_usage_info && entity_class && method_name
98
+ # usage_info = entity_class.get_usage_info(entity_name, method_name)
99
+ # validation_message += ", usage: #{usage_info}"
100
+ # end
101
+
102
+ if e.display_usage_info && entity_class && method_name
103
+ usage_info = entity_class.get_usage_info(entity_name, method_name)
104
+ validation_message += ", usage: #{usage_info}"
105
+
106
+ validation_message.gsub!("^^", '') if validation_message.include?("^^")
107
+ validation_message.gsub!("HIDE_FROM_BASE ", '') if validation_message.include?("HIDE_FROM_BASE")
108
+ end
109
+
110
+ DTK::Client::OsUtil.print(validation_message, :yellow)
111
+ rescue DTK::Client::DtkError => e
112
+ # this are expected application errors
113
+ DtkLogger.instance.error_pp(e.message, e.backtrace)
114
+ rescue Exception => e
115
+ client_internal_error = DTK::Client::DtkError::Client.label()
116
+ DtkLogger.instance.fatal_pp("[#{client_internal_error}] DTK has encountered an error #{e.class}: #{e.message}", e.backtrace)
117
+ end
118
+ end
119
+
120
+ def print_method_response!(response_ruby_obj)
121
+ # this will raise error if found
122
+ DTK::Client::ResponseErrorHandler.check(response_ruby_obj)
123
+
124
+ # this will find appropriate render adapter and give output, returns boolean
125
+ if print = response_ruby_obj.render_data
126
+ print = [print] unless print.kind_of?(Array)
127
+ print.each do |el|
128
+ if el.kind_of?(String)
129
+ el.each_line{|l| STDOUT << l}
130
+ else
131
+ PP.pp(el,STDOUT)
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ def load_command(command_name)
138
+ parser_adapter = DTK::Client::Config[:cli_parser] || "thor"
139
+
140
+ dtk_nested_require("parser/adapters",parser_adapter)
141
+ dtk_nested_require("commands/#{parser_adapter}",command_name)
142
+ end
143
+
144
+ # check if connection is set up properly
145
+ def validate_connection(connection)
146
+ if connection.connection_error?
147
+ connection.print_warning
148
+ puts "\nDTK will now exit. Please set up your connection properly and try again."
149
+ return true
150
+ end
151
+
152
+ false
153
+ end
154
+
155
+ # check if .add_direct_access file exists, if not then add direct access and create .add_direct_access file
156
+ def resolve_direct_access(params, config_exists=nil)
157
+ return if params[:username_exists]
158
+
159
+ puts "Processing ..." if config_exists
160
+ # check to see if catalog credentials are set
161
+ conn = DTK::Client::Session.get_connection
162
+ response = conn.post DTK::Client::CommandBase.class, conn.rest_url("account/check_catalog_credentials"), {}
163
+
164
+ # set catalog credentails
165
+ if response.ok? && !response.data['catalog_credentials_set']
166
+ # setting up catalog credentials
167
+ catalog_creds = DTK::Client::Configurator.ask_catalog_credentials
168
+ unless catalog_creds.empty?
169
+ response = conn.post DTK::Client::CommandBase.class, conn.rest_url("account/set_catalog_credentials"), { :username => catalog_creds[:username], :password => catalog_creds[:password], :validate => true}
170
+ if errors = response['errors']
171
+ DTK::Client::OsUtil.print("#{errors.first['message']} You will have to set catalog credentials manually ('dtk account set-catalog-credentials').", :yellow)
172
+ end
173
+ end
174
+ end
175
+
176
+ # response = DTK::Client::Account.add_access(params[:ssh_key_path])
177
+ response, matched_pub_key, matched_username = DTK::Client::Account.add_key(params[:ssh_key_path], true, "#{DTK::Client::Session.connection_username}-client")
178
+
179
+ if !response.ok?
180
+ DTK::Client::OsUtil.print("We were not able to add access for current user. #{response.error_message}. In order to properly use dtk-shell you will have to add access manually ('dtk account add-ssh-key').\n", :yellow)
181
+ elsif matched_pub_key
182
+ # message will be displayed by add key # TODO: Refactor this flow
183
+ DTK::Client::OsUtil.print("Provided SSH PUB key has already been added.", :yellow)
184
+ DTK::Client::Configurator.add_current_user_to_direct_access
185
+ elsif matched_username
186
+ DTK::Client::OsUtil.print("User with provided name already exists.", :yellow)
187
+ else
188
+ # commented out because 'add_key' method called above will also print the same message
189
+ # DTK::Client::OsUtil.print("Your SSH PUB key has been successfully added.", :yellow)
190
+ DTK::Client::Configurator.add_current_user_to_direct_access
191
+ end
192
+
193
+ response
194
+ end
195
+
196
+ module DTK
197
+ module Client
198
+ class ResponseErrorHandler
199
+ class << self
200
+
201
+ def check_for_session_expiried(response)
202
+ error_code = nil
203
+ if response && response['errors']
204
+ response['errors'].each do |err|
205
+ error_code = err["code"]||(err["errors"] && err["errors"].first["code"])
206
+ end
207
+ end
208
+
209
+ return (error_code == "forbidden")
210
+ end
211
+
212
+ def check(response)
213
+ DtkError.raise_if_error?(response)
214
+ end
215
+ end
216
+ end
217
+
218
+ class Log
219
+ #TODO Stubs
220
+ def self.info(msg)
221
+ pp "info: #{msg}"
222
+ end
223
+ def self.error(msg)
224
+ pp "error: #{msg}"
225
+ end
226
+ end
227
+
228
+ module ParseFile
229
+
230
+ def parse_key_value_file(file)
231
+ DTK::Client::Configurator.parse_key_value_file(file)
232
+ end
233
+
234
+ end
235
+ class Config < Hash
236
+ include Singleton
237
+ include ParseFile
238
+ dtk_require_from_base('configurator')
239
+
240
+ CONFIG_FILE = ::DTK::Client::Configurator::CONFIG_FILE
241
+ CRED_FILE = ::DTK::Client::Configurator::CRED_FILE
242
+
243
+ REQUIRED_KEYS = [:server_host]
244
+
245
+ def self.[](k)
246
+ Config.instance[k]
247
+ end
248
+ private
249
+ def initialize
250
+ set_defaults
251
+ load_config_file
252
+ validate
253
+ end
254
+ def set_defaults
255
+ self[:server_port] = 80
256
+ self[:assembly_module_base_location] = 'assemblies'
257
+ self[:secure_connection] = true
258
+ self[:secure_connection_server_port] = 443
259
+ end
260
+
261
+ def load_config_file
262
+ parse_key_value_file(CONFIG_FILE).each{|k,v|self[k]=v}
263
+ end
264
+
265
+ def validate
266
+ #TODO: need to check for legal values
267
+ missing_keys = REQUIRED_KEYS - keys
268
+ raise DTK::Client::DtkError, "Missing config keys (#{missing_keys.join(",")}). Please check your configuration file #{CONFIG_FILE} for required keys!" unless missing_keys.empty?
269
+ end
270
+
271
+ end
272
+
273
+
274
+ ##
275
+ # Session Singleton we will use to hold connection instance, just a singleton wrapper.
276
+ # During shell input it will be needed only once, so singleton was obvious solution.
277
+ #
278
+ class Session
279
+ include Singleton
280
+
281
+ attr_accessor :conn
282
+
283
+ def initialize
284
+ @conn = DTK::Client::Conn.new
285
+ end
286
+
287
+ def self.get_connection
288
+ Session.instance.conn
289
+ end
290
+
291
+ def self.connection_username
292
+ Session.instance.conn.get_username
293
+ end
294
+
295
+ def self.re_initialize
296
+ Session.instance.conn = nil
297
+ Session.instance.conn = DTK::Client::Conn.new
298
+ Session.instance.conn.cookies
299
+ end
300
+
301
+ def self.logout
302
+ # from this point @conn is not valid, since there are no cookies set
303
+ Session.instance.conn.logout
304
+ end
305
+
306
+ # opts can have key
307
+ # :command_class
308
+ def self.post(route, body, opts = {})
309
+ command_class = opts[:command_class] || Class
310
+ conn = Session.instance.conn
311
+ conn.post(command_class, conn.rest_url(route), body)
312
+ end
313
+ end
314
+
315
+ class Conn
316
+ def initialize
317
+ @cookies = Hash.new
318
+ @connection_error = nil
319
+ login
320
+ end
321
+
322
+ VERBOSE_MODE_ON = ::DTK::Configuration.get(:verbose_rest_calls)
323
+
324
+ attr_reader :connection_error, :cookies
325
+
326
+ if VERBOSE_MODE_ON
327
+ require 'ap'
328
+ end
329
+
330
+ def self.get_timeout
331
+ DefaultRestOpts[:timeout]
332
+ end
333
+
334
+ def self.set_timeout(timeout_sec)
335
+ DefaultRestOpts[:timeout] = timeout_sec
336
+ end
337
+
338
+ def get_username
339
+ get_credentials[:username]
340
+ end
341
+
342
+ def rest_url(route=nil)
343
+ protocol, port = "http", Config[:server_port].to_s
344
+ protocol, port = "https", Config[:secure_connection_server_port].to_s if Config[:secure_connection] == "true"
345
+
346
+ "#{protocol}://#{Config[:server_host]}:#{port}/rest/#{route}"
347
+ end
348
+
349
+ def get(command_class,url)
350
+ ap "GET #{url}" if VERBOSE_MODE_ON
351
+
352
+ check_and_wrap_response(command_class, Proc.new { json_parse_if_needed(get_raw(url)) })
353
+ end
354
+
355
+ def post(command_class,url,body=nil)
356
+ if VERBOSE_MODE_ON
357
+ ap "POST (REST) #{url}"
358
+ ap "params: "
359
+ ap body
360
+ end
361
+
362
+ check_and_wrap_response(command_class, Proc.new { json_parse_if_needed(post_raw(url,body)) })
363
+ end
364
+
365
+ def post_file(command_class,url,body=nil)
366
+ if VERBOSE_MODE_ON
367
+ ap "POST (FILE) #{url}"
368
+ ap "params: "
369
+ ap body
370
+ end
371
+
372
+ check_and_wrap_response(command_class, Proc.new { json_parse_if_needed(post_raw(url,body,{:content_type => 'avro/binary'})) })
373
+ end
374
+
375
+ # method will repeat request in case session has expired
376
+ def check_and_wrap_response(command_class, rest_method_func)
377
+ response = rest_method_func.call
378
+
379
+ if ResponseErrorHandler.check_for_session_expiried(response)
380
+ # re-logging user and repeating request
381
+ DTK::Client::OsUtil.print("Session expired: re-establishing session & re-trying request ...", :yellow)
382
+ @cookies = DTK::Client::Session.re_initialize
383
+ response = rest_method_func.call
384
+ end
385
+
386
+ response_obj = Response.new(command_class, response)
387
+
388
+ # queue messages from server to be displayed later
389
+ DTK::Shell::MessageQueue.process_response(response_obj)
390
+
391
+ response_obj
392
+ end
393
+
394
+
395
+
396
+ def connection_error?
397
+ return !@connection_error.nil?
398
+ end
399
+
400
+ def logout
401
+ response = get_raw rest_url("user/process_logout")
402
+
403
+ # save cookies - no need to persist them
404
+ # DiskCacher.new.save_cookie(@cookies)
405
+
406
+ raise DTK::Client::DtkError, "Failed to logout, and terminate session!" unless response
407
+ @cookies = nil
408
+ end
409
+
410
+ ##
411
+ # Method will warn user that connection could not be established. User should check configuration
412
+ # to make sure that connection is properly set.
413
+ #
414
+ def print_warning
415
+ creds = get_credentials
416
+ puts "[WARNING] Unable to connect to server, please check you configuration."
417
+ puts "========================== Configuration =========================="
418
+ printf "%15s %s\n", "REST endpoint:", rest_url
419
+ printf "%15s %s\n", "Username:", "#{creds[:username]}"
420
+ printf "%15s %s\n", "Password:", "#{creds[:password] ? creds[:password].gsub(/./,'*') : 'No password set'}"
421
+ puts "==================================================================="
422
+
423
+ if self.connection_error['errors'].first['errors']
424
+ error_code = self.connection_error['errors'].first['errors'].first['code']
425
+ print " Error code: "
426
+ DTK::Client::OsUtil.print(error_code, :red)
427
+ end
428
+ end
429
+
430
+ private
431
+
432
+ include ParseFile
433
+
434
+ def login
435
+ creds = get_credentials
436
+ response = post_raw rest_url("user/process_login"),creds
437
+ errors = response['errors']
438
+
439
+ if response.kind_of?(Common::Response) and not response.ok?
440
+ if (errors && errors.first['code']=="pg_error")
441
+ DTK::Client::OsUtil.print(errors.first['message'].gsub!("403 Forbidden", "[PG_ERROR]"), :red)
442
+ exit
443
+ end
444
+ @connection_error = response
445
+ else
446
+ @cookies = response.cookies
447
+ end
448
+ end
449
+
450
+ def set_credentials(username, password)
451
+ @parsed_credentials = { :username => username, :password => password}
452
+ end
453
+
454
+ def get_credentials
455
+ unless @parsed_credentials
456
+ cred_file = Config::CRED_FILE
457
+ raise DTK::Client::DtkError,"Authorization configuration file (#{cred_file}) does not exist" unless File.exists?(cred_file)
458
+ ret = parse_key_value_file(cred_file)
459
+ [:username,:password].each{ |k| raise DTK::Client::DtkError, "cannot find #{k}" unless ret[k] }
460
+ @parsed_credentials = ret
461
+ end
462
+
463
+ @parsed_credentials
464
+ end
465
+
466
+ ####
467
+ RestClientWrapper = Common::Response::RestClientWrapper
468
+
469
+ # In development mode we want bigger timeout allowing us to debbug on server while still
470
+ # keeping connection alive and receivinga response
471
+ if ::DTK::Configuration.get(:development_mode)
472
+ DefaultRestOpts = {:timeout => 2000, :open_timeout => 10, :error_response_class => Client::Response::Error}
473
+ # DefaultRestOpts = {:timeout => 50, :open_timeout => 2, :error_response_class => Client::Response::Error}
474
+ else
475
+ DefaultRestOpts = {:timeout => 300, :open_timeout => 10, :error_response_class => Client::Response::Error}
476
+ end
477
+
478
+ # enable SSL verification
479
+ DefaultRestOpts.merge!(:verify_ssl => OpenSSL::SSL::VERIFY_PEER)
480
+ # Net:HTTP from Ruby 1.8.7 doesn't verify SSL certs correctly
481
+ # this is a CA bundle downloaded from http://curl.haxx.se/docs/caextract.html,
482
+ # and it will only be used for 1.8.7, otherwise the default (system) CA will be used
483
+ DefaultRestOpts.merge!(:ssl_ca_file => File.expand_path('../lib/config/cacert.pem', File.dirname(__FILE__)))
484
+
485
+ def get_raw(url)
486
+ RestClientWrapper.get_raw(url, {}, DefaultRestOpts.merge(:cookies => @cookies))
487
+ end
488
+ def post_raw(url,body,params={})
489
+ RestClientWrapper.post_raw(url, body, DefaultRestOpts.merge(:cookies => @cookies).merge(params))
490
+ end
491
+
492
+ def json_parse_if_needed(item)
493
+ RestClientWrapper.json_parse_if_needed(item)
494
+ end
495
+ end
496
+ end
497
+ end