dtk-shell 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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