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,74 @@
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
+ module ActionResultHandler
21
+
22
+ def print_action_results(action_results_id, number_of_retries=8)
23
+ response = action_results(action_results_id, number_of_retries)
24
+
25
+ if response.ok? && response.data['results']
26
+ response.data['results'].each do |k,v|
27
+ if v['error']
28
+ OsUtil.print("#{v['error']} (#{k})", :red)
29
+ else
30
+ OsUtil.print("#{v['message']} (#{k})", :yellow)
31
+ end
32
+ end
33
+ else
34
+ OsUtil.print("Not able to process given request, we apologise for inconvenience", :red)
35
+ end
36
+
37
+ nil
38
+ end
39
+
40
+ def print_simple_results(action_results_id, number_of_retries=8)
41
+ response = action_results(action_results_id, number_of_retries)
42
+ pp response
43
+ end
44
+
45
+ def action_results(action_results_id, number_of_retries=8)
46
+ action_body = {
47
+ :action_results_id => action_results_id,
48
+ :return_only_if_complete => true,
49
+ :disable_post_processing => true
50
+ }
51
+ response = nil
52
+
53
+ number_of_retries.times do
54
+ response = post(rest_url("assembly/get_action_results"),action_body)
55
+
56
+ # server has found an error
57
+ unless response.data(:results).nil?
58
+ if response.data(:results)['error']
59
+ raise DTK::Client::DtkError, response.data(:results)['error']
60
+ end
61
+ end
62
+
63
+ break if response.data(:is_complete)
64
+
65
+ sleep(1.5)
66
+ end
67
+
68
+ response
69
+
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,92 @@
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::Client
19
+ module AssemblyTemplateMixin
20
+ def get_assembly_name(assembly_id)
21
+ name = nil
22
+ 3.times do
23
+ name = get_name_from_id_helper(assembly_id)
24
+ break if name
25
+ end
26
+
27
+ name
28
+ end
29
+
30
+ def get_assembly_stage_name(assembly_list,assembly_template_name)
31
+ name = nil
32
+ current_list = assembly_list.select{|e| e.include?(assembly_template_name)}
33
+
34
+ if current_list.empty?
35
+ name = assembly_template_name
36
+ else
37
+ numbers = []
38
+ base_name = nil
39
+
40
+ assembly_list.each do |assembly|
41
+ match = assembly.match(/#{assembly_template_name}(-)(\d*)/)
42
+ base_name = assembly_template_name if assembly_template_name.include?(assembly)
43
+ numbers << match[2].to_i if match
44
+ end
45
+
46
+ unless base_name
47
+ name = assembly_template_name
48
+ else
49
+ highest = numbers.max||1
50
+ new_highest = highest+1
51
+
52
+ all = (2..new_highest).to_a
53
+ nums = all - numbers
54
+ name = assembly_template_name + "-#{nums.first}"
55
+ end
56
+ end
57
+
58
+ name
59
+ end
60
+
61
+ # the form should be
62
+ # SETTINGS := SETTING[;...SETTING]
63
+ # SETTING := ATOM || ATOM(ATTR=VAL,...)
64
+ def parse_service_settings(settings)
65
+ settings && settings.split(';').map{|setting|ServiceSetting.parse(setting)}
66
+ end
67
+
68
+ module ServiceSetting
69
+ def self.parse(setting)
70
+ if setting =~ /(^[^\(]+)\((.+)\)$/
71
+ name = $1
72
+ param_string = $2
73
+ {:name => name, :parameters => parse_params(param_string)}
74
+ else
75
+ {:name => setting}
76
+ end
77
+ end
78
+ private
79
+ def self.parse_params(param_string)
80
+ param_string.split(',').inject(Hash.new) do |h,av_pair|
81
+ if av_pair =~ /(^[^=]+)=(.+$)/
82
+ attr = $1
83
+ val = $2
84
+ h.merge(attr => val)
85
+ else
86
+ raise DtkError,"[ERROR] Settings param string is ill-formed"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,1801 @@
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 'rest_client'
19
+ require 'json'
20
+ require 'colorize'
21
+ dtk_require_from_base('dtk_logger')
22
+ dtk_require_from_base('util/os_util')
23
+ dtk_require_from_base('command_helper')
24
+ dtk_require_from_base('task_status')
25
+ dtk_require_common_commands('thor/set_required_attributes')
26
+ dtk_require_common_commands('thor/edit')
27
+ dtk_require_common_commands('thor/purge_clone')
28
+ dtk_require_common_commands('thor/list_diffs')
29
+ dtk_require_common_commands('thor/action_result_handler')
30
+ dtk_require_common_commands('thor/assembly_template')
31
+
32
+ LOG_SLEEP_TIME_W = DTK::Configuration.get(:tail_log_frequency)
33
+
34
+ module DTK::Client
35
+ module AssemblyWorkspaceMixin
36
+ include ListDiffsMixin
37
+ include AssemblyTemplateMixin
38
+
39
+ REQ_ASSEMBLY_OR_WS_ID = [:service_id!, :workspace_id!]
40
+
41
+ def get_name(assembly_or_workspace_id)
42
+ get_name_from_id_helper(assembly_or_workspace_id)
43
+ end
44
+
45
+ def get_assembly_id(assembly_name)
46
+ assembly_id = nil
47
+ list = CommandBaseThor.get_cached_response(:service, "assembly/list", {})
48
+
49
+ list.data.each do |item|
50
+ if item["display_name"] == assembly_name
51
+ assembly_id = item["id"]
52
+ break
53
+ end
54
+ end
55
+
56
+ raise DtkError,"[ERROR] Illegal name (#{assembly_name}) for service." unless assembly_id
57
+ assembly_id
58
+ end
59
+
60
+ def start_aux(context_params)
61
+ if context_params.is_there_identifier?(:node)
62
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:node_id]
63
+ else
64
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1]
65
+ end
66
+
67
+ assembly_or_workspace_id, node_pattern = context_params.retrieve_arguments(mapping,method_argument_names)
68
+ assembly_start(assembly_or_workspace_id, node_pattern)
69
+ end
70
+
71
+ def stop_aux(context_params)
72
+ if context_params.is_there_identifier?(:node)
73
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:node_id]
74
+ else
75
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1]
76
+ end
77
+
78
+ assembly_or_workspace_id, node_pattern = context_params.retrieve_arguments(mapping,method_argument_names)
79
+ assembly_stop(assembly_or_workspace_id, node_pattern)
80
+ end
81
+
82
+ def cancel_task_aux(context_params)
83
+ assembly_or_workspace_id, task_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1],method_argument_names)
84
+ post_body = {
85
+ :assembly_id => assembly_or_workspace_id
86
+ }
87
+ post_body.merge!(:task_id => task_id) if task_id
88
+ post rest_url("assembly/cancel_task"), post_body
89
+ end
90
+
91
+ # mode will be :create or :update
92
+ # service_module_name_x can be name or fullname (NS:MOduleName)
93
+ def promote_assembly_aux(mode, assembly_or_workspace_id, service_module_name_x = nil, assembly_template_name = nil, opts = {})
94
+ namespace = nil
95
+ local_clone_dir_exists = nil
96
+
97
+ post_body = {
98
+ :assembly_id => assembly_or_workspace_id,
99
+ :mode => mode.to_s
100
+ }
101
+
102
+ if service_module_name_x
103
+ service_module_name = service_module_name_x
104
+ if service_module_name_x =~ /(^[^:]+):([^:]+$)/
105
+ namespace, service_module_name = [$1,$2]
106
+ end
107
+ post_body.merge!(:service_module_name => service_module_name)
108
+ end
109
+
110
+ namespace ||= opts[:default_namespace]
111
+ if namespace
112
+ local_clone_dir_exists = Helper(:git_repo).local_clone_dir_exists?(:service_module, service_module_name, :namespace => namespace)
113
+ post_body.merge!(:namespace => namespace)
114
+ post_body.merge!(:local_clone_dir_exists => true) if local_clone_dir_exists
115
+ end
116
+
117
+ post_body.merge!(:assembly_template_name => assembly_template_name) if assembly_template_name
118
+ post_body.merge!(:use_module_namespace => true) if opts[:use_module_namespace]
119
+ post_body.merge!(:description => opts[:description]) if opts[:description]
120
+ response = post rest_url('assembly/promote_to_template'), post_body
121
+ return response unless response.ok?()
122
+
123
+ # synchronize_clone will load new assembly template into service clone on workspace (if it exists)
124
+ commit_sha, workspace_branch, namespace, full_module_name, repo_url, version = response.data(:commit_sha, :workspace_branch, :module_namespace, :full_module_name, :repo_url, :version)
125
+ service_module_name ||= response.data(:module_name)
126
+ merge_warning_message = response.data(:merge_warning_message)
127
+ opts = { :local_branch => workspace_branch, :namespace => namespace }
128
+
129
+ if (mode == :update) || local_clone_dir_exists
130
+ response = Helper(:git_repo).synchronize_clone(:service_module, service_module_name, commit_sha, opts)
131
+ else
132
+ response = Helper(:git_repo).create_clone_with_branch(:service_module, service_module_name, repo_url, workspace_branch, version, namespace)
133
+ end
134
+ return response unless response.ok?
135
+
136
+ OsUtil.print("New assembly template '#{assembly_template_name}' created in service module '#{full_module_name}'.", :yellow) if mode == :create
137
+ OsUtil.print(merge_warning_message, :yellow) if merge_warning_message
138
+
139
+ response
140
+ end
141
+
142
+ def list_violations_aux(context_params)
143
+ assembly_or_workspace_id, action = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1],method_argument_names)
144
+ post_body = {
145
+ :assembly_id => assembly_or_workspace_id
146
+ }
147
+ post_body.merge!(action: action) if action
148
+ post_body.merge!(ret_objects: true) if options.fix?
149
+ response = post rest_url("assembly/find_violations"), post_body
150
+ violation_table_form = response.render_table(:violation)
151
+ unless options.fix? and !response.data.empty?
152
+ violation_table_form
153
+ else
154
+ OsUtil.print("The following violations were found:", :red)
155
+ violation_table_form.render_data
156
+ OsUtil.print("Answer the following prompts to correct the violations:", :yellow)
157
+ result = Violation.fix_violations(assembly_or_workspace_id, response.data)
158
+ result.rerun_violation_check? ? list_violations_aux(context_params) : Response::Ok.new
159
+ end
160
+ end
161
+
162
+ def print_includes_aux(context_params)
163
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
164
+ response = post rest_url("assembly/print_includes"),:assembly_id => assembly_or_workspace_id
165
+ end
166
+
167
+ def list_ad_hoc_actions_aux(context_params)
168
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
169
+
170
+ post_body = {
171
+ :assembly_id => assembly_or_workspace_id,
172
+ :type => options.summary? ? :component_type : :component_instance
173
+ }
174
+
175
+ response = post rest_url("assembly/ad_hoc_action_list"), post_body
176
+ response.render_table()
177
+ end
178
+
179
+ def list_actions_aux(context_params)
180
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
181
+
182
+ post_body = { :assembly_id => assembly_or_workspace_id }
183
+ post_body.merge!(:type => options.type) if options.type?
184
+
185
+ response = post rest_url("assembly/list_actions"), post_body
186
+ response.render_table('service_actions')
187
+ end
188
+
189
+ # desc "SERVICE-NAME/ID execute-action COMPONENT-INSTANCE [ACTION-NAME [ACTION-PARAMS]]"
190
+ def execute_ad_hoc_action_aux(context_params)
191
+ assembly_or_workspace_id,component_id,method_name,action_params_string = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2,:option_3],method_argument_names)
192
+
193
+ action_params = parse_params?(action_params_string)
194
+
195
+ post_body = {
196
+ :assembly_id => assembly_or_workspace_id,
197
+ :component_id => component_id
198
+ }
199
+ post_body.merge!(:method_name => method_name) if method_name
200
+ post_body.merge!(:action_params => action_params) if action_params
201
+
202
+ response = post rest_url("assembly/ad_hoc_action_execute"), post_body
203
+ return response unless response.ok?
204
+
205
+ task_status_stream(assembly_or_workspace_id, :ignore_stage_level_info => true)
206
+ nil
207
+ end
208
+
209
+ def exec_aux(context_params, opts = {})
210
+ assembly_or_workspace_id, task_action, task_params_string = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!, :option_2], method_argument_names)
211
+
212
+ # support 'converge' task action as synonym for 'create'
213
+ task_action = 'create' if task_action && task_action.eql?('converge')
214
+
215
+ # parse params and return format { 'p_name1' => 'p_value1' , 'p_name2' => 'p_value2' }
216
+ task_params = parse_params?(task_params_string)||{}
217
+
218
+ # match if sent node/component
219
+ if task_action_match = task_action.match(/(^[\w\-\:]*)\/(.*)/)
220
+ node, task_action = $1, $2
221
+ task_params.merge!("node" => node)
222
+ end
223
+
224
+ post_body = PostBody.new(
225
+ :assembly_id => assembly_or_workspace_id,
226
+ :commit_msg? => options.commit_msg,
227
+ :task_action? => task_action,
228
+ :task_params? => task_params
229
+ )
230
+ post_body.merge!(:noop_if_no_action => opts[:noop_if_no_action]) if opts[:noop_if_no_action]
231
+ response = post rest_url("assembly/exec"), post_body
232
+ return response unless response.ok?
233
+
234
+ response_data = response.data
235
+
236
+ if violations = response_data['violations']
237
+ OsUtil.print("The following violations were found; they must be corrected before workspace can be converged", :red)
238
+ resp = DTK::Client::Response.new(:assembly, { "status" => 'ok', "data" => violations })
239
+ return opts[:internal_trigger] ? { :violations => resp } : resp.render_table(:violation)
240
+ end
241
+
242
+ if confirmation_message = response_data["confirmation_message"]
243
+ message_text =
244
+ if confirmation_message_text = response_data["confirmation_message_text"]
245
+ confirmation_message_text
246
+ else
247
+ "Workspace service is stopped, do you want to start it"
248
+ end
249
+ return unless Console.confirmation_prompt("#{message_text}"+'?')
250
+
251
+ response = post rest_url("assembly/exec"), post_body.merge!(:start_assembly => true, :skip_violations => true)
252
+ return response unless response.ok?
253
+
254
+ response_data = response.data
255
+ end
256
+
257
+ if message = response_data["message"]
258
+ OsUtil.print(message, :yellow)
259
+ return
260
+ end
261
+
262
+ return Response::Ok.new()
263
+ end
264
+
265
+ def exec_sync_aux(context_params)
266
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID], method_argument_names)
267
+
268
+ response = exec_aux(context_params, {:internal_trigger => true})
269
+ return response if (response.is_a?(Response) && !response.ok?) || response.nil?
270
+
271
+ if violations_response = response[:violations]
272
+ return violations_response.render_table(:violation)
273
+ end
274
+
275
+ task_status_stream(assembly_or_workspace_id)
276
+ end
277
+
278
+ def converge_aux(context_params, opts = {})
279
+ assembly_or_workspace_id,task_action,task_params_string = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1,:option_2],method_argument_names)
280
+
281
+ task_params = parse_params?(task_params_string)
282
+
283
+ # check for violations
284
+ response = post rest_url("assembly/find_violations"), :assembly_id => assembly_or_workspace_id
285
+ return response unless response.ok?
286
+ if response.data and response.data.size > 0
287
+ error_message = "The following violations were found; they must be corrected before workspace can be converged"
288
+ OsUtil.print(error_message, :red)
289
+ if opts[:are_there_violations]
290
+ return response.render_table(:violation), true
291
+ else
292
+ return response.render_table(:violation)
293
+ end
294
+ end
295
+
296
+ post_body = PostBody.new(
297
+ :assembly_id => assembly_or_workspace_id,
298
+ :commit_msg? => options.commit_msg,
299
+ :task_action? => task_action,
300
+ :task_params? => task_params
301
+ )
302
+ response = post rest_url("assembly/create_task"), post_body
303
+ return response unless response.ok?
304
+
305
+ if response.data
306
+ if confirmation_message = response.data["confirmation_message"]
307
+ return unless Console.confirmation_prompt("Workspace service is stopped, do you want to start it"+'?')
308
+ post_body.merge!(:start_assembly=>true)
309
+ response = post rest_url("assembly/create_task"), post_body
310
+ return response unless response.ok?
311
+ end
312
+ end
313
+ unless task_id = response.data(:task_id)
314
+ if message = response.data(:message)
315
+ OsUtil.print(message, :yellow)
316
+ end
317
+ return Response::Ok.new()
318
+ end
319
+
320
+ # execute task
321
+ response = post rest_url("task/execute"), "task_id" => task_id
322
+ return response unless response.ok?
323
+
324
+ if opts[:mode] == :stream
325
+ task_status_stream(assembly_or_workspace_id)
326
+ end
327
+
328
+ Response::Ok.new()
329
+ end
330
+
331
+ def delete_and_destroy_aux(context_params)
332
+ assembly_name = context_params.retrieve_arguments([:option_1!],method_argument_names)
333
+
334
+ if assembly_name.to_s =~ /^[0-9]+$/
335
+ assembly_id = assembly_name
336
+ else
337
+ assembly_id = get_assembly_id(assembly_name)
338
+ end
339
+
340
+ if !options.force? && !options.y?
341
+ msg =
342
+ if options.recursive?
343
+ "Are you sure you want to delete and destroy target instance and its associated service instances"
344
+ else
345
+ "Are you sure you want to delete and destroy service '#{assembly_name}' and its nodes"
346
+ end
347
+
348
+ return unless Console.confirmation_prompt(msg+'?')
349
+ end
350
+
351
+ unsaved_modules = check_if_unsaved_cmp_module_changes(assembly_id)
352
+ unless unsaved_modules.empty?
353
+ return unless Console.confirmation_prompt("Deleting this service will cause unsaved changes in component module(s) '#{unsaved_modules.join(',')}' to be lost. Do you still want to proceed"+'?')
354
+ end
355
+
356
+ assembly_changed = check_if_unsaved_assembly_changes(assembly_id, assembly_name)
357
+ if assembly_changed == true
358
+ return unless Console.confirmation_prompt("You made some changes in assembly or it's workflow that will be lost if you delete this service. Do you still want to proceed"+'?')
359
+ end
360
+
361
+ # purge local clone
362
+ response = purge_clone_aux(:all,:assembly_module => {:assembly_name => assembly_name})
363
+ return response unless response.ok?
364
+
365
+ post_body = {
366
+ :assembly_id => assembly_id,
367
+ :subtype => :instance
368
+ }
369
+ post_body.merge!(:recursive => options.recursive) if options.recursive?
370
+
371
+ action = options.force? ? 'delete' : 'delete_using_workflow'
372
+ response = post rest_url("assembly/#{action}"), post_body
373
+
374
+ response
375
+ end
376
+
377
+ def parse_params?(params_string)
378
+ if params_string
379
+ params_string.split(',').inject(Hash.new) do |h,av|
380
+ av_split = av.split('=')
381
+ unless av_split.size == 2
382
+ raise DtkValidationError, "The parameter string (#{params_string}) is ill-formed"
383
+ end
384
+ h.merge(av_split[0] => av_split[1])
385
+ end
386
+ end
387
+ end
388
+ private :parse_params?
389
+
390
+ def edit_module_aux(context_params)
391
+ assembly_or_workspace_id, component_module_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
392
+
393
+ response = prepare_for_edit_module(assembly_or_workspace_id, component_module_name)
394
+ return response unless response.ok?
395
+
396
+ assembly_name,component_module_id,version,repo_url,branch,commit_sha,full_module_name = response.data(:assembly_name,:module_id,:version,:repo_url,:workspace_branch,:branch_head_sha,:full_module_name)
397
+ component_module_name = full_module_name if full_module_name
398
+
399
+ edit_opts = {
400
+ :automatically_clone => true,
401
+ :pull_if_needed => false,
402
+ :service_instance_module => true,
403
+ :skip_if_exist_check => true,
404
+ :assembly_module => {
405
+ :assembly_name => assembly_name,
406
+ :version => version
407
+ },
408
+ :workspace_branch_info => {
409
+ :repo_url => repo_url,
410
+ :branch => branch,
411
+ :module_name => component_module_name,
412
+ :commit_sha => commit_sha
413
+ }
414
+ }
415
+
416
+ version = nil #TODO: version associated with assembly is passed in edit_opts, which is a little confusing
417
+ edit_aux(:component_module,component_module_id,component_module_name,version,edit_opts)
418
+ end
419
+
420
+ def list_remote_module_diffs(context_params)
421
+ assembly_or_workspace_id, component_module_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
422
+ response = prepare_for_edit_module(assembly_or_workspace_id, component_module_name)
423
+ return response unless response.ok?
424
+
425
+ assembly_name,component_module_id,workspace_branch,commit_sha,module_branch_idh,repo_id = response.data(:assembly_name,:module_id,:workspace_branch,:branch_head_sha,:module_branch_idh,:repo_id)
426
+ list_component_module_diffs(component_module_id, assembly_name, workspace_branch, commit_sha, module_branch_idh['guid'], repo_id)
427
+ end
428
+
429
+ def prepare_for_edit_module(assembly_or_workspace_id, component_module_name)
430
+ post_body = {
431
+ :assembly_id => assembly_or_workspace_id,
432
+ :module_name => component_module_name,
433
+ :module_type => 'component_module'
434
+ }
435
+ response = post rest_url("assembly/prepare_for_edit_module"), post_body
436
+ end
437
+
438
+ def edit_or_create_workflow_aux(context_params,opts={})
439
+ option_1 = (opts[:create] ? :option_1! : :option_1)
440
+ assembly_or_workspace_id, workflow_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,option_1],method_argument_names)
441
+ post_body = {
442
+ :assembly_id => assembly_or_workspace_id,
443
+ :module_type => 'service_module',
444
+ :modification_type => 'workflow'
445
+ }
446
+ if workflow_name
447
+ post_body.merge!(:task_action => workflow_name)
448
+ end
449
+ if opts[:create]
450
+ post_body.merge!(:create => true)
451
+ post_body.merge!(:base_task_action => opts[:create_from]) if opts[:create_from]
452
+ end
453
+ response = post rest_url("assembly/prepare_for_edit_module"), post_body
454
+ return response unless response.ok?
455
+
456
+ assembly_name,service_module_id,service_module_name,version,repo_url,branch,branch_head_sha,edit_file = response.data(:assembly_name,:module_id,:full_module_name,:version,:repo_url,:workspace_branch,:branch_head_sha,:edit_file)
457
+ edit_opts = {
458
+ :command => 'edit-workflow',
459
+ :automatically_clone => true,
460
+ :assembly_module => {
461
+ :assembly_name => assembly_name,
462
+ :version => version
463
+ },
464
+ :workspace_branch_info => {
465
+ :repo_url => repo_url,
466
+ :branch => branch,
467
+ :module_name => service_module_name
468
+ },
469
+ :commit_sha => branch_head_sha,
470
+ :pull_if_needed => true,
471
+ :modification_type => :workflow,
472
+ :edit_file => edit_file
473
+ }
474
+ edit_opts.merge!(:task_action => workflow_name) if workflow_name
475
+ version = nil #TODO: version associated with assembly is passed in edit_opts, which is a little confusing
476
+ edit_aux(:service_module,service_module_id,service_module_name,version,edit_opts)
477
+ end
478
+
479
+ def edit_attributes_aux(context_params)
480
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
481
+ context_params.forward_options(:format => 'yaml')
482
+
483
+ response = list_attributes_aux(context_params,:attribute_type=>:editable)
484
+ return response unless response.ok?
485
+
486
+ yaml_input = response.data
487
+ edited_yaml = attributes_editor(yaml_input)
488
+ # sending params in yaml format because marshalling fouls with some data types like nil and Booleans
489
+ post_body = {
490
+ :assembly_id => assembly_or_workspace_id,
491
+ :settings_yaml_content => edited_yaml
492
+ }
493
+
494
+ post rest_url("assembly/apply_attribute_settings"), post_body
495
+ end
496
+
497
+ def push_module_updates_aux(context_params)
498
+ assembly_or_workspace_id, component_module_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!], method_argument_names)
499
+ post_body = {
500
+ :assembly_id => assembly_or_workspace_id,
501
+ :module_name => component_module_name,
502
+ :module_type => 'component_module'
503
+ }
504
+ post_body.merge!(:force => true) if options.force?
505
+ response = post(rest_url('assembly/promote_module_updates'), post_body)
506
+ return response unless response.ok?
507
+ return Response::Ok.new() unless response.data(:any_updates)
508
+ if dsl_parsing_errors = response.data(:dsl_parsing_errors)
509
+ error_message = "Module '#{component_module_name}' parsing errors found:\n#{dsl_parsing_errors}\nYou can fix errors using 'edit' command from referenced service modules and then invoke 'push-component-module-updates' again from this context.\n"
510
+ OsUtil.print(error_message, :red)
511
+ return Response::NoOp.new()
512
+ end
513
+ module_name, namespace, branch, ff_change = response.data(:module_name, :module_namespace, :workspace_branch, :fast_forward_change)
514
+ ff_change ||= true
515
+ opts = { :local_branch => branch, :namespace => namespace }
516
+ opts.merge!(:hard_reset => true) unless ff_change
517
+ opts.merge!(:force => true) if options.force?
518
+ response = Helper(:git_repo).pull_changes?(:component_module, module_name, opts)
519
+ return response unless response.ok?()
520
+ Response::Ok.new()
521
+ end
522
+
523
+ def pull_base_component_module_aux(context_params)
524
+ assembly_or_workspace_id, component_module_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
525
+ post_body = {
526
+ :assembly_id => assembly_or_workspace_id,
527
+ :module_name => component_module_name,
528
+ :module_type => 'component_module'
529
+ }
530
+ post_body.merge!(:force => true) if options.force?
531
+ response = post(rest_url("assembly/prepare_for_pull_from_base"),post_body)
532
+ return response unless response.ok?
533
+
534
+ if dsl_parsing_errors = response.data(:dsl_parsing_errors)
535
+ # TODO: DTK-2206; think error message below is incorrect
536
+ error_message = "Module '#{component_module_name}' parsing errors found:\n#{dsl_parsing_errors}\nYou can fix errors using 'edit' command from module context and invoke promote-module-updates again.\n"
537
+ OsUtil.print(error_message, :red)
538
+ return Response::Error.new()
539
+ end
540
+
541
+ assembly_name, module_id, module_name, version, base_module_branch, branch_head_sha, local_branch, namespace, repo_url, current_branch_sha = response.data(:assembly_name, :module_id, :full_module_name, :version, :workspace_branch, :branch_head_sha, :local_branch, :module_namespace, :repo_url, :current_branch_sha)
542
+ edit_opts = {
543
+ :assembly_module => {
544
+ :assembly_name => assembly_name,
545
+ :version => version
546
+ },
547
+ :workspace_branch_info => {
548
+ :repo_url => repo_url,
549
+ :branch => local_branch,
550
+ :module_name => module_name,
551
+ :commit_sha => branch_head_sha
552
+ },
553
+ :remote_branch => base_module_branch,
554
+ :commit_sha => branch_head_sha,
555
+ :current_branch_sha => current_branch_sha,
556
+ :full_module_name => module_name,
557
+ :skip_if_exist_check => true
558
+ }
559
+ opts = {:local_branch => local_branch, :namespace => namespace}
560
+
561
+ opts.merge!(:hard_reset => true) if options.revert?
562
+ opts.merge!(:force => true) if options.force?
563
+
564
+ response = Helper(:git_repo).pull_changes?(:component_module, module_name, edit_opts.merge!(opts))
565
+ return response unless response.ok?()
566
+
567
+ edit_opts.merge!(:force_parse => true, :update_from_includes => true, :print_dependencies => true, :remote_branch => local_branch, :force_clone => true)
568
+ response = push_clone_changes_aux(:component_module, module_id, nil, "Pull base module updates", true, edit_opts)
569
+
570
+ unless response.ok?()
571
+ # if parsing error on assembly module (components/attributes/link_defs integrity violations) do git reset --hard
572
+ Helper(:git_repo).hard_reset_branch_to_sha(:component_module, module_name, edit_opts)
573
+ return response
574
+ end
575
+
576
+ Response::Ok.new()
577
+ end
578
+
579
+ def action_info_aux(context_params)
580
+ assembly_or_workspace_id,workflow_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1],method_argument_names)
581
+ post_body = {
582
+ :assembly_id => assembly_or_workspace_id,
583
+ :subtype => 'instance'
584
+ }
585
+ post_body.merge!(:task_action => workflow_name) if workflow_name
586
+ post(rest_url("assembly/info_about_task"),post_body)
587
+ end
588
+
589
+ def workflow_list_aux(context_params)
590
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
591
+ post_body = {
592
+ :assembly_id => assembly_or_workspace_id
593
+ }
594
+ response = post(rest_url("assembly/task_action_list"),post_body)
595
+ data_type = 'task_action'
596
+ response.render_table(data_type)
597
+ end
598
+
599
+ def task_status_aw_aux(context_params)
600
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
601
+ mode =
602
+ if options.wait?
603
+ :refresh
604
+ else
605
+ if options.has_key?('mode') and options.mode.nil?
606
+ raise DtkError::Usage.new("option --mode needs an argument")
607
+ end
608
+ (options.mode || :snapshot).to_sym
609
+ end
610
+
611
+ response = task_status_aux(mode, assembly_or_workspace_id, :assembly, :summarize => options.summarize?)
612
+
613
+ # when executing delete-and-destroy <service_instance> and delete successfully switch to base service context
614
+ if response.is_a?(Response) && response.ok? && response.data && response.data.first['change_context']
615
+ MainContext.get_context.change_context(["/service/"])
616
+ return Response::Ok.new()
617
+ end
618
+
619
+ if mode == :stream
620
+ #no response if ok
621
+ response unless response.ok?
622
+ else
623
+ # TODO: Hack which is necessery for the specific problem (DTK-725),
624
+ # we don't get proper error message when there is a timeout doing converge
625
+
626
+ unless response == true
627
+ return response.merge("data" => [{ "errors" => {"message" => "Task does not exist for workspace."}}]) unless response["data"]
628
+ response["data"].each do |data|
629
+ if data["errors"]
630
+ data["errors"]["message"] = "[TIMEOUT ERROR] Server is taking too long to respond." if data["errors"]["message"] == "error"
631
+ end
632
+ end
633
+ end
634
+ response
635
+ end
636
+ end
637
+
638
+ def task_action_detail_aw_aux(context_params)
639
+ assembly_or_workspace_id, message_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!], method_argument_names)
640
+ post_body = {
641
+ :assembly_id => assembly_or_workspace_id,
642
+ :message_id => message_id
643
+ }
644
+ post rest_url("assembly/task_action_detail"), post_body
645
+ end
646
+
647
+ def link_attributes_aux(context_params)
648
+ assembly_id, target_attr_term, source_attr_term = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2!],method_argument_names)
649
+ post_body = {
650
+ :assembly_id => assembly_id,
651
+ :target_attribute_term => target_attr_term,
652
+ :source_attribute_term => source_attr_term
653
+ }
654
+ post rest_url("assembly/add_ad_hoc_attribute_links"), post_body
655
+ end
656
+
657
+ def list_nodes_aux(context_params)
658
+ context_params.method_arguments = ["nodes"]
659
+ list_aux(context_params)
660
+ end
661
+
662
+ def list_components_aux(context_params)
663
+ context_params.method_arguments = ["components"]
664
+ list_aux(context_params)
665
+ # list_assemblies(context_params)
666
+ end
667
+
668
+ def list_modules_aux(context_params)
669
+ context_params.method_arguments = ["modules"]
670
+ list_aux(context_params)
671
+ # list_assemblies(context_params)
672
+ end
673
+
674
+ def list_attributes_aux(context_params,opts={})
675
+ context_params.method_arguments = ["attributes"]
676
+ list_aux(context_params,opts)
677
+ end
678
+
679
+ def list_tasks_aux(context_params)
680
+ context_params.method_arguments = ["tasks"]
681
+ list_aux(context_params)
682
+ end
683
+
684
+ def link_attribute_aux(context_params)
685
+ assembly_or_workspace_id, target_attr_term, source_attr_term = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2!],method_argument_names)
686
+ post_body = {
687
+ :assembly_id => assembly_or_workspace_id,
688
+ :target_attribute_term => target_attr_term,
689
+ :source_attribute_term => source_attr_term
690
+ }
691
+ post rest_url("assembly/add_ad_hoc_attribute_links"), post_body
692
+ end
693
+
694
+ def create_component_aux(context_params)
695
+ # If method is invoked from 'assembly/node' level retrieve node_id argument
696
+ # directly from active context
697
+ if context_params.is_there_identifier?(:node)
698
+ mapping = [REQ_ASSEMBLY_OR_WS_ID, :node_id!, :option_1!]
699
+ assembly_id, node_id, component_template_id = context_params.retrieve_arguments(mapping, method_argument_names)
700
+ else
701
+ # otherwise retrieve node_id from command options
702
+ mapping = [REQ_ASSEMBLY_OR_WS_ID, :option_1!]
703
+ assembly_id, component_template_id = context_params.retrieve_arguments(mapping, method_argument_names)
704
+ node_id = nil
705
+ end
706
+
707
+ # assembly_id,node_id,component_template_id = context_params.retrieve_arguments(mapping,method_argument_names)
708
+ namespace, component_template_id = get_namespace_and_name_for_component(component_template_id)
709
+
710
+ post_body = {
711
+ :assembly_id => assembly_id,
712
+ :node_id => node_id,
713
+ :component_template_id => component_template_id
714
+ }
715
+
716
+ post_body.merge!(:namespace => namespace) if namespace
717
+ post_body.merge!(:auto_complete_links => options.auto_complete) if options.auto_complete?
718
+ post rest_url("assembly/add_component"), post_body
719
+ end
720
+
721
+ def unlink_components_aux(context_params)
722
+ post_body = link_unlink_components__ret_post_body(context_params)
723
+ post rest_url("assembly/delete_service_link"), post_body
724
+ end
725
+
726
+ def link_components_aux(context_params)
727
+ post_body = link_unlink_components__ret_post_body(context_params)
728
+ post rest_url('assembly/add_service_link'), post_body
729
+ end
730
+
731
+ def link_unlink_components__ret_post_body(context_params)
732
+ if context_params.is_last_command_eql_to?(:component)
733
+ assembly_or_workspace_id, dep_cmp, antec_cmp, dependency_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :component_id!, :option_1!, :option_2], method_argument_names)
734
+ else
735
+ assembly_or_workspace_id, dep_cmp, antec_cmp, dependency_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!, :option_2!, :option_3], method_argument_names)
736
+ end
737
+
738
+ post_body = {
739
+ :assembly_id => assembly_or_workspace_id,
740
+ :input_component_id => dep_cmp,
741
+ :output_component_id => antec_cmp
742
+ }
743
+ post_body.merge!(:dependency_name => dependency_name) if dependency_name
744
+
745
+ post_body
746
+ end
747
+
748
+ def list_component_links_aux(context_params)
749
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
750
+ post_body = {
751
+ :assembly_id => assembly_or_workspace_id
752
+ }
753
+ data_type = :service_link
754
+ if context_params.is_last_command_eql_to?(:component)
755
+ component_id = context_params.retrieve_arguments([:component_id!],method_argument_names)
756
+ post_body.merge!(:component_id => component_id, :context => "component")
757
+ data_type = :service_link_from_component
758
+ end
759
+ response = post rest_url("assembly/list_service_links"), post_body
760
+ response.render_table(data_type)
761
+ end
762
+
763
+ def list_connections_aux(context_params)
764
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
765
+
766
+ post_body = {
767
+ :assembly_id => assembly_or_workspace_id,
768
+ :find_possible => true
769
+ }
770
+ response = post rest_url("assembly/list_connections"), post_body
771
+ response.render_table(:possible_service_connection)
772
+ end
773
+
774
+ def info_aux(context_params)
775
+ assembly_or_workspace_id, node_id, component_id, attribute_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :node_id, :component_id, :attribute_id],method_argument_names)
776
+ is_json_return = context_params.get_forwarded_options[:json_return] || false
777
+
778
+ # return only node group info if triggered from node group
779
+ is_node_group = true if context_params.shadow_entity_name == 'node_group'
780
+
781
+ post_body = {
782
+ :assembly_id => assembly_or_workspace_id,
783
+ :node_id => node_id,
784
+ :component_id => component_id,
785
+ :attribute_id => attribute_id,
786
+ :subtype => :instance,
787
+ :json_return => is_json_return
788
+ }
789
+
790
+ post_body.merge!(:only_node_group_info => true) if is_node_group
791
+ resp = post rest_url("assembly/info"), post_body
792
+
793
+ # if waiting for json response we do not need to render rest of data
794
+ return resp if is_json_return
795
+
796
+ if (component_id.nil? && !node_id.nil?)
797
+ resp.render_workspace_node_info("node")
798
+ elsif (component_id && node_id)
799
+ resp.render_workspace_node_info("component")
800
+ else
801
+ return resp
802
+ end
803
+ end
804
+
805
+ def delete_and_destroy(context_params)
806
+ assembly_or_workspace_id = context_params.retrieve_arguments([:option_1!],method_argument_names)
807
+ assembly_name = get_name(assembly_or_workspace_id)
808
+
809
+ unless options.force?
810
+ # Ask user if really want to delete assembly, if not then return to dtk-shell without deleting
811
+ #used form "+'?' because ?" confused emacs ruby rendering
812
+ what = "service"
813
+ return unless Console.confirmation_prompt("Are you sure you want to delete and destroy #{what} '#{assembly_name}' and its nodes"+'?')
814
+ end
815
+
816
+ #purge local clone
817
+ response = purge_clone_aux(:all,:assembly_module => {:assembly_name => assembly_name})
818
+ return response unless response.ok?
819
+
820
+ post_body = {
821
+ :assembly_id => assembly_or_workspace_id,
822
+ :subtype => :instance
823
+ }
824
+
825
+ response = post rest_url("assembly/delete"), post_body
826
+
827
+ # when changing context send request for getting latest assemblies instead of getting from cache
828
+ # @@invalidate_map << :assembly
829
+ response
830
+ end
831
+
832
+ def grant_access_aux(context_params)
833
+ service_id, system_user, rsa_key_name, path_to_rsa_pub_key = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!, :option_2!, :option_3],method_argument_names)
834
+
835
+ path_to_rsa_pub_key ||= SSHUtil.default_rsa_pub_key_path()
836
+ rsa_pub_key_content = SSHUtil.read_and_validate_pub_key(path_to_rsa_pub_key)
837
+
838
+ response = post_file rest_url("assembly/initiate_ssh_pub_access"), {
839
+ :agent_action => :grant_access,
840
+ :system_user => system_user,
841
+ :rsa_pub_name => rsa_key_name,
842
+ :rsa_pub_key => rsa_pub_key_content,
843
+ :assembly_id => service_id,
844
+ :target_nodes => options.nodes
845
+ }
846
+
847
+ return response unless response.ok?
848
+
849
+ action_results_id = response.data(:action_results_id)
850
+
851
+ print_action_results(action_results_id)
852
+
853
+ nil
854
+ end
855
+
856
+ def revoke_access_aux(context_params)
857
+ service_id, system_user, rsa_key_name = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID, :option_1!, :option_2!],method_argument_names)
858
+
859
+ response = post_file rest_url("assembly/initiate_ssh_pub_access"), {
860
+ :agent_action => :revoke_access,
861
+ :system_user => system_user,
862
+ :rsa_pub_name => rsa_key_name,
863
+ :assembly_id => service_id,
864
+ :target_nodes => options.nodes
865
+ }
866
+
867
+ return response unless response.ok?
868
+
869
+ action_results_id = response.data(:action_results_id)
870
+
871
+ print_action_results(action_results_id)
872
+
873
+ nil
874
+ end
875
+
876
+ def list_ssh_access_aux(context_params)
877
+ service_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
878
+
879
+ response = post_file rest_url("assembly/list_ssh_access"), {
880
+ :assembly_id => service_id
881
+ }
882
+
883
+ response.render_table(:ssh_access)
884
+ response
885
+ end
886
+
887
+ def set_target_aux(context_params)
888
+ assembly_or_workspace_id, target_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
889
+ post_body = {
890
+ :assembly_id => assembly_or_workspace_id,
891
+ :target_id => target_id
892
+ }
893
+ post rest_url("assembly/set_target"), post_body
894
+ end
895
+
896
+ def set_attribute_aux(context_params)
897
+ if context_params.is_there_identifier?(:attribute)
898
+ mapping = (options.unset? ? [REQ_ASSEMBLY_OR_WS_ID, :attribute_id!] : [REQ_ASSEMBLY_OR_WS_ID, :attribute_id!, :option_1!])
899
+ else
900
+ mapping = (options.unset? ? [REQ_ASSEMBLY_OR_WS_ID, :option_1!] : [REQ_ASSEMBLY_OR_WS_ID, :option_1!, :option_2!])
901
+ end
902
+
903
+ assembly_or_workspace_id, pattern, value = context_params.retrieve_arguments(mapping, method_argument_names)
904
+ post_body = {
905
+ :assembly_id => assembly_or_workspace_id,
906
+ :pattern => pattern
907
+ }
908
+
909
+ raise DtkValidationError, 'Please use only component-attribute (-c) or node-attribute (-n) option' if options.component_attribute? && options.node_attribute?
910
+
911
+ # if try to set service instance attribute but using -n option to sepicify it is node attribute, say that node attribute does not exist
912
+ raise DtkError, "[ERROR] Node attribute '#{pattern}' does not exist" if options.node_attribute? && !pattern.include?('/')
913
+
914
+ # make sure -c and -n are used only with node or cmp attributes directly on service instance
915
+ validate_service_instance_node_or_cmp_attrs(pattern, options) if options.component_attribute? || options.node_attribute?
916
+
917
+ post_body.merge!(:component_attribute => true) if options.component_attribute?
918
+ post_body.merge!(:node_attribute => true) if options.node_attribute? || context_params.is_there_identifier?(:node)
919
+ post_body.merge!(:value => value) unless options.unset?
920
+
921
+ response = post rest_url('assembly/set_attributes'), post_body
922
+ return response unless response.ok?
923
+
924
+ if r_data = response.data
925
+ if r_data.is_a?(Hash)
926
+ if ambiguous = r_data['ambiguous']
927
+ unless ambiguous.empty?
928
+ msg = "It is ambiguous whether '#{ambiguous.join(', ')}' #{ambiguous.size == 1 ? 'is' : 'are'} node or component attribute(s). Run set-attribute again with one of options -c [--component-attribute] or -n [--node-attribute]."
929
+ raise DtkError, msg
930
+ end
931
+ end
932
+ end
933
+ end
934
+
935
+ Response::Ok.new()
936
+ end
937
+
938
+ def create_attribute_aux(context_params)
939
+ if context_params.is_there_identifier?(:attribute)
940
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:attribute_id!, :option_1]
941
+ else
942
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2]
943
+ end
944
+ assembly_id, pattern, value = context_params.retrieve_arguments(mapping,method_argument_names)
945
+ post_body = {
946
+ :assembly_id => assembly_id,
947
+ :pattern => pattern,
948
+ :create => true,
949
+ }
950
+ post_body.merge!(:value => value) if value
951
+ post_body.merge!(:required => true) if options.required?
952
+ post_body.merge!(:dynamic => true) if options.dynamic?
953
+ if datatype = options['type']
954
+ post_body.merge!(:datatype => datatype)
955
+ end
956
+ post rest_url("assembly/set_attributes"), post_body
957
+ end
958
+
959
+ def unset(context_params)
960
+ if context_params.is_there_identifier?(:attribute)
961
+ mapping = [[:service_id, :workspace_id!],:attribute_id!]
962
+ else
963
+ mapping = [[:service_id, :workspace_id!],:option_1!]
964
+ end
965
+
966
+ assembly_or_workspace_id, pattern, value = context_params.retrieve_arguments(mapping,method_argument_names)
967
+
968
+ post_body = {
969
+ :assembly_id => assembly_or_workspace_id,
970
+ :pattern => pattern,
971
+ :value => nil
972
+ }
973
+ #TODO: have this return format like assembly show attributes with subset of rows that gt changed
974
+ post rest_url("assembly/set_attributes"), post_body
975
+ end
976
+
977
+ def add_assembly(context_params)
978
+ assembly_or_workspace_id,assembly_template_id = context_params.retrieve_arguments([[:service_id, :workspace_id!],:option_1!],method_argument_names)
979
+ post_body = {
980
+ :assembly_id => assembly_or_workspace_id,
981
+ :assembly_template_id => assembly_template_id
982
+ }
983
+ post_body.merge!(:auto_add_connections => true) if options.auto_complete?
984
+ post rest_url("assembly/add_assembly_template"), post_body
985
+ end
986
+
987
+ def create_node_aux(context_params)
988
+ assembly_or_workspace_id, assembly_node_name = context_params.retrieve_arguments([[:service_id, :workspace_id!],:option_1!], method_argument_names)
989
+
990
+ if assembly_node_name.match("/") || assembly_node_name.match(" ")
991
+ raise DtkError, "Node name is ill-formed (contains empty or / characters)"
992
+ end
993
+
994
+ post_body = {
995
+ :assembly_id => assembly_or_workspace_id,
996
+ :assembly_node_name => assembly_node_name
997
+ }
998
+ post_body.merge!(:image => options.image) if options.image?
999
+ post_body.merge!(:instance_size => options.instance_size) if options.instance_size?
1000
+
1001
+ post rest_url("assembly/add_node"), post_body
1002
+ end
1003
+
1004
+ def create_node_group_aux(context_params)
1005
+ assembly_or_workspace_id, node_group_name = context_params.retrieve_arguments([[:service_id, :workspace_id!],:option_1!], method_argument_names)
1006
+ cardinality = options.cardinality
1007
+
1008
+ # default value for cardinality is 1 (if user does not specify otherwise)
1009
+ # invalid values for cardinality are 0 and any string
1010
+ if cardinality.eql?('0') || !cardinality.to_s.match(/^[0-9]+$/)
1011
+ fail DtkError.new("Invalid cardinality value '#{cardinality}'!")
1012
+ end
1013
+
1014
+ post_body = {
1015
+ :assembly_id => assembly_or_workspace_id,
1016
+ :cardinality => options.cardinality,
1017
+ :node_group_name => node_group_name
1018
+ }
1019
+ post_body.merge!(:image => options.image) if options.image?
1020
+ post_body.merge!(:instance_size => options.instance_size) if options.instance_size?
1021
+
1022
+ post rest_url("assembly/add_node_group"), post_body
1023
+ end
1024
+
1025
+ def purge_aux(context_params)
1026
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
1027
+ unless options.force?
1028
+ return unless Console.confirmation_prompt("Are you sure you want to delete and destroy all nodes in the workspace"+'?')
1029
+ end
1030
+
1031
+ unsaved_modules = check_if_unsaved_cmp_module_changes(assembly_or_workspace_id)
1032
+ unless unsaved_modules.empty?
1033
+ return unless Console.confirmation_prompt("Purging the workspace will cause unsaved changes in component module(s) '#{unsaved_modules.join(',')}' to be lost. Do you still want to proceed"+'?')
1034
+ end
1035
+
1036
+ # purge local clone
1037
+ response = purge_clone_aux(:all,:assembly_module => {:assembly_name => 'workspace'})
1038
+ return response unless response.ok?
1039
+
1040
+ post_body = {
1041
+ :assembly_id => assembly_or_workspace_id
1042
+ }
1043
+ response = post(rest_url("assembly/purge"),post_body)
1044
+ end
1045
+
1046
+ def destroy_and_reset_nodes_aux(context_params)
1047
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
1048
+ unless options.force?
1049
+ return unless Console.confirmation_prompt("Are you sure you want to destroy and reset all nodes in the workspace"+'?')
1050
+ end
1051
+
1052
+ post_body = {
1053
+ :assembly_id => assembly_or_workspace_id
1054
+ }
1055
+ response = post(rest_url("assembly/destroy_and_reset_nodes"),post_body)
1056
+ end
1057
+
1058
+ def delete_aux(context_params)
1059
+ if context_params.is_last_command_eql_to?(:node)
1060
+ delete_node_aux(context_params)
1061
+ elsif context_params.is_last_command_eql_to?(:component)
1062
+ delete_component_aux(context_params)
1063
+ end
1064
+ end
1065
+
1066
+ def delete_node_aux(context_params)
1067
+ assembly_or_workspace_id, node_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
1068
+ if !options.force? && !options.y?
1069
+ what = "node"
1070
+ return unless Console.confirmation_prompt("Are you sure you want to delete and destroy #{what} '#{node_id}'"+'?')
1071
+ end
1072
+
1073
+ post_body = {
1074
+ :assembly_id => assembly_or_workspace_id,
1075
+ :node_id => node_id
1076
+ }
1077
+
1078
+ action = options.force? ? 'delete_node' : 'delete_node_using_workflow'
1079
+ response = post(rest_url("assembly/#{action}"),post_body)
1080
+ response
1081
+ end
1082
+
1083
+ def delete_node_group_aux(context_params)
1084
+ assembly_or_workspace_id, node_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:option_1!],method_argument_names)
1085
+
1086
+ if !options.force? && !options.y?
1087
+ what = "node"
1088
+ return unless Console.confirmation_prompt("Are you sure you want to delete and destroy #{what} '#{node_id}'"+'?')
1089
+ end
1090
+
1091
+ post_body = {
1092
+ :assembly_id => assembly_or_workspace_id,
1093
+ :node_id => node_id
1094
+ }
1095
+ action = options.force? ? 'delete_node_group' : 'delete_node_group_using_workflow'
1096
+ response = post(rest_url("assembly/#{action}"),post_body)
1097
+ response
1098
+ end
1099
+
1100
+ def delete_component_aux(context_params, opts = {})
1101
+ assembly_or_workspace_id, node_id, node_name, component_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:node_id, :node_name, :option_1!],method_argument_names)
1102
+
1103
+ if !options.force? && !options.y?
1104
+ what = "component"
1105
+ return unless Console.confirmation_prompt("Are you sure you want to delete #{what} '#{component_id}'"+'?')
1106
+ end
1107
+
1108
+ full_path = component_id.clone
1109
+ if node_id.nil? && !(component_id.to_s =~ /^[0-9]+$/)
1110
+ if component_id.to_s.include?('/')
1111
+ cmp_match = component_id.match(/([\w-]*)\/(.*)/)
1112
+ node_id, component_id = cmp_match[1], cmp_match[2]
1113
+ node_name = node_id
1114
+ else
1115
+ # TODO: update server so dont have to pass in 'assembly_wide'
1116
+ node_id = node_name = 'assembly_wide'
1117
+ end
1118
+ end
1119
+
1120
+ task_action = "#{full_path}.delete"
1121
+ task_params_string = nil
1122
+ # support 'converge' task action as synonym for 'create'
1123
+ task_action = 'create' if task_action && task_action.eql?('converge')
1124
+
1125
+ # parse params and return format { 'p_name1' => 'p_value1' , 'p_name2' => 'p_value2' }
1126
+ task_params = parse_params?(task_params_string)||{}
1127
+
1128
+ # match if sent node/component
1129
+ if task_action_match = task_action.match(/(^[\w\-\:]*)\/(.*)/)
1130
+ node, task_action = $1, $2
1131
+ task_params.merge!("node" => node)
1132
+ end
1133
+
1134
+ task_params['node'] ||= node_name if node_name
1135
+
1136
+ post_body = PostBody.new(
1137
+ :assembly_id => assembly_or_workspace_id,
1138
+ :commit_msg? => options.commit_msg,
1139
+ :task_action? => task_action,
1140
+ :task_params? => task_params,
1141
+ :component_id => component_id
1142
+ )
1143
+ post_body.merge!(:noop_if_no_action => opts[:noop_if_no_action])# if opts[:noop_if_no_action]
1144
+ post_body.merge!(:cmp_full_name => "#{node_name}/#{component_id}") if (node_name && !(component_id.to_s =~ /^[0-9]+$/))
1145
+ post_body.merge!(:node_id => node_id) if node_id
1146
+
1147
+ # response = post rest_url("assembly/exec"), post_body
1148
+ action = options.force? ? 'delete_component' : 'delete_component_using_workflow'
1149
+ response = post(rest_url("assembly/#{action}"), post_body)
1150
+ return response unless response.ok?
1151
+
1152
+ response_data = response.data
1153
+
1154
+ if violations = response_data['violations']
1155
+ OsUtil.print("The following violations were found; they must be corrected before workspace can be converged", :red)
1156
+ resp = DTK::Client::Response.new(:assembly, { "status" => 'ok', "data" => violations })
1157
+ return opts[:internal_trigger] ? { :violations => resp } : resp.render_table(:violation)
1158
+ end
1159
+
1160
+ if confirmation_message = response_data["confirmation_message"]
1161
+ return unless Console.confirmation_prompt("Workspace service is stopped, do you want to start it"+'?')
1162
+
1163
+ response = post rest_url("assembly/exec"), post_body.merge!(:start_assembly => true, :skip_violations => true)
1164
+ return response unless response.ok?
1165
+
1166
+ response_data = response.data
1167
+ end
1168
+
1169
+ if message = response_data["message"]
1170
+ OsUtil.print(message, :yellow)
1171
+ return
1172
+ end
1173
+
1174
+ return Response::Ok.new()
1175
+ end
1176
+
1177
+ def get_netstats_aux(context_params)
1178
+ netstat_tries = 6
1179
+ netstat_sleep = 0.5
1180
+
1181
+ assembly_or_workspace_id,node_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:node_id],method_argument_names)
1182
+
1183
+ post_body = {
1184
+ :assembly_id => assembly_or_workspace_id,
1185
+ :node_id => node_id
1186
+ }
1187
+
1188
+ response = post(rest_url("assembly/initiate_get_netstats"),post_body)
1189
+ raise DtkValidationError, response.data(:errors) if response.data(:errors)
1190
+ return response unless response.ok?
1191
+
1192
+ action_results_id = response.data(:action_results_id)
1193
+ end_loop, response, count, ret_only_if_complete = false, nil, 0, true
1194
+
1195
+ until end_loop do
1196
+ post_body = {
1197
+ :action_results_id => action_results_id,
1198
+ :return_only_if_complete => ret_only_if_complete,
1199
+ :disable_post_processing => false,
1200
+ :sort_key => "port"
1201
+ }
1202
+ response = post(rest_url("assembly/get_action_results"),post_body)
1203
+ count += 1
1204
+ if count > netstat_tries or response.data(:is_complete)
1205
+ end_loop = true
1206
+ else
1207
+ #last time in loop return whetever is teher
1208
+ if count == netstat_tries
1209
+ ret_only_if_complete = false
1210
+ end
1211
+ sleep netstat_sleep
1212
+ end
1213
+ end
1214
+
1215
+ #TODO: needed better way to render what is one of the fields which is any array (:results in this case)
1216
+ response.set_data(*response.data(:results))
1217
+ response.render_table(:netstat_data)
1218
+ end
1219
+
1220
+ def execute_tests_aux(context_params)
1221
+ assembly_or_workspace_id,node_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:node_id],method_argument_names)
1222
+
1223
+ execute_test_tries = 30
1224
+ execute_test_sleep = 1
1225
+
1226
+ if !options['timeout'].nil?
1227
+ begin
1228
+ execute_test_tries = Integer(options['timeout'])
1229
+ rescue
1230
+ raise DtkValidationError, "Timeout value is not valid"
1231
+ end
1232
+ end
1233
+
1234
+ post_body = {
1235
+ :assembly_id => assembly_or_workspace_id,
1236
+ :components => options["component"]
1237
+ }
1238
+ post_body[:node_id] = node_id unless node_id.nil?
1239
+
1240
+ response = post(rest_url("assembly/initiate_execute_tests"),post_body)
1241
+
1242
+ raise DtkValidationError, response.data(:errors) if response.data(:errors)
1243
+ return response unless response.ok?
1244
+
1245
+ action_results_id = response.data(:action_results_id)
1246
+ end_loop, response, count, ret_only_if_complete = false, nil, 0, true
1247
+
1248
+ until end_loop do
1249
+ post_body = {
1250
+ :action_results_id => action_results_id,
1251
+ :return_only_if_complete => ret_only_if_complete,
1252
+ :disable_post_processing => false,
1253
+ :sort_key => "module_name"
1254
+ }
1255
+
1256
+ response = post(rest_url("assembly/get_action_results"),post_body)
1257
+ count += 1
1258
+
1259
+ if count > execute_test_tries or response.data(:is_complete)
1260
+ response.data(:results).each do |res|
1261
+ if res.key?('test_error')
1262
+ test_error = res.delete('test_error')
1263
+ res['errors'] = { "message" => test_error, "type" => "test_error" }
1264
+ end
1265
+ end
1266
+ end_loop = true
1267
+ else
1268
+ #last time in loop return whetever is there
1269
+ if count == execute_test_tries
1270
+ ret_only_if_complete = false
1271
+ end
1272
+ sleep execute_test_sleep
1273
+ end
1274
+ end
1275
+
1276
+ if (response.data(:results).empty? && options['timeout'].nil?)
1277
+ raise DtkValidationError, "Could not finish execution of tests in default timeframe (#{execute_test_tries} seconds). Try again with passing --timeout TIMEOUT parameter"
1278
+ elsif (response.data(:results).empty? && !options['timeout'].nil?)
1279
+ raise DtkValidationError, "Could not finish execution of tests in set timeframe (#{execute_test_tries} seconds). Try again with increasing --timeout TIMEOUT parameter"
1280
+ else
1281
+ response.print_error_table = true
1282
+ response.set_data(*response.data(:results))
1283
+ response.render_table(:execute_tests_data_v2)
1284
+ end
1285
+ end
1286
+
1287
+ def get_ps_aux(context_params)
1288
+ get_ps_tries = 6
1289
+ get_ps_sleep = 0.5
1290
+
1291
+ assembly_or_workspace_id,node_id,filter_pattern = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID,:node_id, :option_1],method_argument_names)
1292
+
1293
+ post_body = {
1294
+ :assembly_id => assembly_or_workspace_id,
1295
+ :node_id => node_id
1296
+ }
1297
+
1298
+ response = post(rest_url("assembly/initiate_get_ps"),post_body)
1299
+ raise DtkValidationError, response.data(:errors) if response.data(:errors)
1300
+ return response unless response.ok?
1301
+
1302
+ action_results_id = response.data(:action_results_id)
1303
+ end_loop, response, count, ret_only_if_complete = false, nil, 0, true
1304
+
1305
+ until end_loop do
1306
+ post_body = {
1307
+ :action_results_id => action_results_id,
1308
+ :return_only_if_complete => ret_only_if_complete,
1309
+ :disable_post_processing => false,
1310
+ :sort_key => "pid"
1311
+ }
1312
+ response = post(rest_url("assembly/get_action_results"),post_body)
1313
+
1314
+ count += 1
1315
+ if count > get_ps_tries or response.data(:is_complete)
1316
+ end_loop = true
1317
+ else
1318
+ #last time in loop return whetever is teher
1319
+ if count == get_ps_tries
1320
+ ret_only_if_complete = false
1321
+ end
1322
+ sleep get_ps_sleep
1323
+ end
1324
+ end
1325
+ filtered = response.data(:results).flatten
1326
+
1327
+ # Amar: had to add more complex filtering in order to print node id and node name in output,
1328
+ # as these two values are sent only in the first element of node's processes list
1329
+ unless (filter_pattern.nil? || !options["filter"])
1330
+ node_id = ""
1331
+ node_name = ""
1332
+ filtered.reject! do |r|
1333
+ match = r.to_s.include?(filter_pattern)
1334
+ if r["node_id"] && r["node_id"] != node_id
1335
+ node_id = (r["node_id"] && r["node_id"].to_s)
1336
+ node_name = r["node_name"]
1337
+ end
1338
+
1339
+ if match && !node_id.empty?
1340
+ r["node_id"] = node_id
1341
+ r["node_name"] = node_name
1342
+ node_id = ""
1343
+ node_name = ""
1344
+ end
1345
+ !match
1346
+ end
1347
+ end
1348
+
1349
+ response.set_data(*filtered)
1350
+ response.render_table(:ps_data)
1351
+ end
1352
+
1353
+ def set_required_attributes(context_params)
1354
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
1355
+ set_required_attributes_aux(assembly_or_workspace_id,:assembly,:instance)
1356
+ end
1357
+
1358
+ def tail_aux(context_params)
1359
+ if context_params.is_there_identifier?(:node)
1360
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:node_id!,:option_1!,:option_2]
1361
+ else
1362
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2!,:option_3]
1363
+ end
1364
+
1365
+ assembly_or_workspace_id,log_path,node_identifier,grep_option = context_params.retrieve_arguments(mapping,method_argument_names)
1366
+
1367
+ last_line = nil
1368
+ begin
1369
+
1370
+ file_path = File.join('/tmp',"dtk_tail_#{Time.now.to_i}.tmp")
1371
+ tail_temp_file = File.open(file_path,"a")
1372
+
1373
+ file_ready = false
1374
+
1375
+ t1 = Thread.new do
1376
+ while true
1377
+ post_body = {
1378
+ :assembly_id => assembly_or_workspace_id,
1379
+ :subtype => 'instance',
1380
+ :start_line => last_line,
1381
+ :node_identifier => node_identifier,
1382
+ :log_path => log_path,
1383
+ :grep_option => grep_option
1384
+ }
1385
+
1386
+ response = post rest_url("assembly/initiate_get_log"), post_body
1387
+ raise DtkValidationError, response.data(:errors) if response.data(:errors)
1388
+
1389
+ unless response.ok?
1390
+ raise DtkError, "Error while getting log from server, there was no successful response."
1391
+ end
1392
+
1393
+ action_results_id = response.data(:action_results_id)
1394
+ action_body = {
1395
+ :action_results_id => action_results_id,
1396
+ :return_only_if_complete => true,
1397
+ :disable_post_processing => true
1398
+ }
1399
+
1400
+ # number of re-tries
1401
+ 3.times do
1402
+ response = post(rest_url("assembly/get_action_results"),action_body)
1403
+
1404
+ # server has found an error
1405
+ unless response.data(:results).nil?
1406
+ if response.data(:results)['error']
1407
+ raise DtkError, response.data(:results)['error']
1408
+ end
1409
+ end
1410
+
1411
+ break if response.data(:is_complete)
1412
+
1413
+ sleep(1)
1414
+ end
1415
+
1416
+ if response.data(:is_complete)
1417
+ # due to complicated response we change its formating
1418
+ response = response.data(:results).first[1]
1419
+
1420
+ unless response["error"].nil?
1421
+ raise DtkError, response["error"]
1422
+ end
1423
+
1424
+ # removing invalid chars from log
1425
+ output = response["output"].gsub(/`/,'\'')
1426
+
1427
+ unless output.empty?
1428
+ file_ready = true
1429
+ tail_temp_file << output
1430
+ tail_temp_file.flush
1431
+ end
1432
+
1433
+ last_line = response["last_line"]
1434
+ sleep(LOG_SLEEP_TIME_W)
1435
+ else
1436
+ file_ready = true
1437
+ tail_temp_file << "\n\nError while logging there was no successful response after 3 tries, (^C, Q) to exit. \n\n"
1438
+ tail_temp_file.flush
1439
+ tail_temp_file.close
1440
+ Thread.current.exit
1441
+ end
1442
+ end
1443
+ end
1444
+
1445
+ t2 = Thread.new do
1446
+ # ramp up time
1447
+ begin
1448
+ if options.more?
1449
+ system("tail -f #{file_path} | more")
1450
+ else
1451
+ # needed ramp up time for t1 to start writting to file
1452
+ while not file_ready
1453
+ sleep(0.5)
1454
+ end
1455
+ system("less +F #{file_path}")
1456
+ end
1457
+ ensure
1458
+ # wheter application resolves normaly or is interrupted
1459
+ # t1 will be killed
1460
+ t1.exit()
1461
+ end
1462
+ end
1463
+
1464
+ t1.join()
1465
+ t2.join()
1466
+ rescue Interrupt
1467
+ t2.exit()
1468
+ rescue DtkError => e
1469
+ t2.exit()
1470
+ raise e
1471
+ end
1472
+ end
1473
+
1474
+ def grep_aux(context_params)
1475
+ if context_params.is_there_identifier?(:node)
1476
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1!,:node_id!,:option_2!]
1477
+ is_node = true
1478
+ else
1479
+ mapping = [REQ_ASSEMBLY_OR_WS_ID,:option_1!,:option_2!,:option_3!]
1480
+ end
1481
+
1482
+ assembly_or_workspace_id,log_path,node_pattern,grep_pattern = context_params.retrieve_arguments(mapping,method_argument_names)
1483
+
1484
+ begin
1485
+ post_body = {
1486
+ :assembly_id => assembly_or_workspace_id,
1487
+ :subtype => 'instance',
1488
+ :log_path => log_path,
1489
+ :node_pattern => node_pattern,
1490
+ :grep_pattern => grep_pattern,
1491
+ :stop_on_first_match => options.first?
1492
+ }
1493
+
1494
+ response = post rest_url("assembly/initiate_grep"), post_body
1495
+ raise DtkValidationError, response.data(:errors) if response.data(:errors)
1496
+
1497
+ unless response.ok?
1498
+ raise DtkError, "Error while getting log from server. Message: #{response['errors'][0]['message'].nil? ? 'There was no successful response.' : response['errors'].first['message']}"
1499
+ end
1500
+
1501
+ action_results_id = response.data(:action_results_id)
1502
+ action_body = {
1503
+ :action_results_id => action_results_id,
1504
+ :return_only_if_complete => true,
1505
+ :disable_post_processing => true
1506
+ }
1507
+
1508
+ # number of re-tries
1509
+ 3.downto(1) do
1510
+ response = post(rest_url("assembly/get_action_results"),action_body)
1511
+
1512
+ # server has found an error
1513
+ unless response.data(:results).nil?
1514
+ if response.data(:results)['error']
1515
+ raise DtkError, response.data(:results)['error']
1516
+ end
1517
+ end
1518
+
1519
+ break if response.data(:is_complete)
1520
+
1521
+ sleep(1)
1522
+ end
1523
+
1524
+ raise DtkError, "Error while logging there was no successful response after 3 tries." unless response.data(:is_complete)
1525
+
1526
+ console_width = ENV["COLUMNS"].to_i
1527
+
1528
+ response.data(:results).each do |r|
1529
+ raise DtkError, r[1]["error"] if r[1]["error"]
1530
+
1531
+ message_colorized = OsUtil.colorize(r[0].inspect, :green)
1532
+
1533
+ if r[1]["output"].empty?
1534
+ puts "NODE-ID #{message_colorized} - Log does not contain data that matches you pattern #{grep_pattern}!"
1535
+ else
1536
+ puts "\n"
1537
+ console_width.times do
1538
+ print "="
1539
+ end
1540
+ puts "NODE-ID: #{message_colorized}\n" unless is_node
1541
+ puts "Log output:\n"
1542
+ puts r[1]["output"].gsub(/`/,'\'')
1543
+ end
1544
+ end
1545
+ rescue DtkError => e
1546
+ raise e
1547
+ end
1548
+ end
1549
+
1550
+ def assembly_start(workspace_id, node_pattern_filter)
1551
+ post_body = {
1552
+ :assembly_id => workspace_id,
1553
+ :node_pattern => node_pattern_filter
1554
+ }
1555
+
1556
+ # we expect action result ID
1557
+ response = post rest_url("assembly/start"), post_body
1558
+ return response unless response.ok?()
1559
+ raise DtkValidationError, response.data(:errors).first if response.data(:errors)
1560
+
1561
+ task_id = response.data(:task_id)
1562
+ post rest_url("task/execute"), "task_id" => task_id
1563
+ end
1564
+
1565
+ def assembly_stop(workspace_id, node_pattern_filter)
1566
+ post_body = {
1567
+ :assembly_id => workspace_id,
1568
+ :node_pattern => node_pattern_filter
1569
+ }
1570
+ action = options.legacy? ? 'stop' : 'stop_using_workflow'
1571
+ response = post rest_url("assembly/#{action}"), post_body
1572
+ return response unless response.ok?()
1573
+ raise DtkValidationError, response.data(:errors).first if response.data(:errors)
1574
+
1575
+ response
1576
+ end
1577
+
1578
+ def list_aux(context_params,opts={})
1579
+ assembly_or_workspace_id, node_id, component_id, attribute_id, about = context_params.retrieve_arguments([[:service_id!, :workspace_id],:node_id,:component_id,:attribute_id,:option_1],method_argument_names)
1580
+ detail_to_include = nil
1581
+ format = nil
1582
+ post_options = Hash.new
1583
+
1584
+ # use_default is used if we want to use provided data_type and not data_type returned from server
1585
+ use_default = false
1586
+
1587
+ # if list method is called outside of dtk-shell and called for workspace context (dtk workspace list-nodes)
1588
+ # without workspace identifier, we will set 'workspace' as identifier (dtk workspace workspace list-nodes)
1589
+ assembly_or_workspace_id = 'workspace' if (context_params.is_last_command_eql_to?(:workspace) && assembly_or_workspace_id.nil?)
1590
+
1591
+ #TODO: looking for cleaner way of showing which ones are using the default datatype passed back from server;
1592
+ #might use data_type = DynamicDatatype
1593
+ if about
1594
+ case about
1595
+ when "nodes"
1596
+ data_type = :node
1597
+ when "components"
1598
+ data_type = :component
1599
+ if options.deps?
1600
+ detail_to_include = [:component_dependencies]
1601
+ end
1602
+ when "attributes"
1603
+ node_id = options.node unless node_id
1604
+ component_id = options.component unless component_id
1605
+ attribute_id = options.attribute unless attribute_id
1606
+
1607
+ data_type = (options.links? ? :workspace_attribute_w_link : :workspace_attribute)
1608
+ edit_attr_format = context_params.get_forwarded_options()[:format] if context_params.get_forwarded_options()
1609
+ if tags = options.tags
1610
+ post_options.merge!(:tags => tags.split(','))
1611
+ end
1612
+ if format = (options.format || edit_attr_format)
1613
+ post_options.merge!(:format => format)
1614
+ #dont need to compute links if using a format
1615
+ elsif options.links?
1616
+ detail_to_include = [:attribute_links]
1617
+ end
1618
+ if opts[:attribute_type]
1619
+ post_options.merge!(:attribute_type => opts[:attribute_type])
1620
+ end
1621
+ when "modules"
1622
+ detail_to_include = [:version_info]
1623
+ data_type = nil #TODO: DynamicDatatype
1624
+ when "tasks"
1625
+ data_type = :task
1626
+ else
1627
+ raise_validation_error_method_usage('list')
1628
+ end
1629
+ end
1630
+
1631
+ post_body = {
1632
+ :assembly_id => assembly_or_workspace_id,
1633
+ :node_id => node_id,
1634
+ :component_id => component_id,
1635
+ :attribute_id => attribute_id,
1636
+ :subtype => 'instance',
1637
+ }.merge(post_options)
1638
+
1639
+ post_body.merge!(:detail_to_include => detail_to_include) if detail_to_include
1640
+ rest_endpoint = "assembly/info_about"
1641
+
1642
+ if context_params.is_last_command_eql_to?(:attribute)
1643
+ raise DtkError, "Not supported command for current context level." if attribute_id
1644
+ about, data_type = get_type_and_raise_error_if_invalid(about, "attributes", ["attributes"])
1645
+ elsif context_params.is_last_command_eql_to?(:component)
1646
+ if component_id
1647
+ about, data_type = get_type_and_raise_error_if_invalid(about, "attributes", ["attributes"])
1648
+ else
1649
+ about, data_type = get_type_and_raise_error_if_invalid(about, "components", ["attributes", "components"])
1650
+ end
1651
+ elsif context_params.is_last_command_eql_to?(:node)
1652
+ if node_id
1653
+ about, data_type = get_type_and_raise_error_if_invalid(about, "components", ["attributes", "components"])
1654
+ else
1655
+ about, data_type = get_type_and_raise_error_if_invalid(about, "nodes", ["attributes", "components", "nodes"])
1656
+ end
1657
+ else
1658
+ if assembly_or_workspace_id
1659
+ about, data_type = get_type_and_raise_error_if_invalid(about, "nodes", ["attributes", "components", "nodes", "modules","tasks"])
1660
+
1661
+ if data_type.to_s.eql?("component")
1662
+ data_type = nil #DynamicDatatype
1663
+ end
1664
+ #TODO: need to cleanup that data_type set in multiple places
1665
+ if about == "attributes"
1666
+ data_type = (options.links? ? :workspace_attribute_w_link : :workspace_attribute)
1667
+ end
1668
+ else
1669
+ data_type = :assembly
1670
+ post_body = { :subtype => 'instance', :detail_level => 'nodes' }
1671
+ rest_endpoint = "assembly/list"
1672
+ end
1673
+ end
1674
+
1675
+ post_body[:about] = about
1676
+ response = post rest_url(rest_endpoint), post_body
1677
+
1678
+ # set render view to be used
1679
+ unless format
1680
+ response.render_table(data_type, use_default)
1681
+ end
1682
+
1683
+ response
1684
+ end
1685
+
1686
+ def clear_tasks_aux(context_params)
1687
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID],method_argument_names)
1688
+ post_body = {
1689
+ :assembly_id => assembly_or_workspace_id
1690
+ }
1691
+ post rest_url("assembly/clear_tasks"), post_body
1692
+ end
1693
+
1694
+ def validate_service_instance_node_or_cmp_attrs(pattern, options)
1695
+ split_pattern = pattern.split('/')
1696
+ return if split_pattern.size == 2
1697
+ if options.node_attribute?
1698
+ raise DtkError, 'Please use -n option only with service instance node attributes (node_name/attribute_name)'
1699
+ elsif options.component_attribute?
1700
+ raise DtkError, 'Please use -c option only with service instance component attributes (cmp_name/attribute_name)'
1701
+ end
1702
+ end
1703
+
1704
+ def stage_aux(context_params)
1705
+ new_context_params = get_deploy_or_stage_context(context_params, options)
1706
+ ContextRouter.routeTask(:service_module, "stage", new_context_params, @conn)
1707
+ end
1708
+
1709
+ def deploy_aux(context_params)
1710
+ new_context_params = get_deploy_or_stage_context(context_params, options)
1711
+ ContextRouter.routeTask(:service_module, "deploy", new_context_params, @conn)
1712
+ end
1713
+
1714
+ def get_deploy_or_stage_context(context_params, options)
1715
+ assembly_template_name, instance_name = context_params.retrieve_arguments([:option_1!, :option_2], method_argument_names)
1716
+
1717
+ service_module_name, assembly, assembly_name = assembly_template_name.split('/')
1718
+ raise DtkValidationError, "Service module name is ill-formed! Should contain <namespace>:<name>" unless service_module_name =~ /(^[^:]+):([^:]+$)/
1719
+
1720
+ unless assembly_name
1721
+ assembly_name = assembly
1722
+ assembly = nil
1723
+ end
1724
+ raise DtkValidationError, "ASSEMBLY-NAME parameter is ill-formed! Should contain <namespace>:<service_name>/assembly/<assembly_name> or <namespace>:<service_name>/<assembly_name>" if assembly && !assembly.eql?('assembly')
1725
+
1726
+ new_context_params = DTK::Shell::ContextParams.new
1727
+ new_context_params.add_context_to_params(:service_module, :service_module)
1728
+ new_context_params.add_context_name_to_params(:service_module, :service_module, service_module_name)
1729
+ new_context_params.method_arguments = [assembly_name]
1730
+ new_context_params.method_arguments << instance_name if instance_name
1731
+
1732
+ fwd_opts = {}
1733
+ node_size = options.node_size
1734
+ os_type = options.os_type
1735
+ version = options.version
1736
+ no_auto_complete = options.no_auto_complete
1737
+ is_target = options.is_target?
1738
+ parent_service = options.parent_service
1739
+ do_not_encode = options.do_not_encode
1740
+ stream_results = options['stream-results']
1741
+
1742
+ fwd_opts.merge!(:node_size => node_size) if node_size
1743
+ fwd_opts.merge!(:os_type => os_type) if os_type
1744
+ fwd_opts.merge!(:version => version) if version
1745
+ fwd_opts.merge!(:no_auto_complete => no_auto_complete) if no_auto_complete
1746
+ fwd_opts.merge!(:is_target => is_target) if is_target
1747
+ fwd_opts.merge!(:parent_service => parent_service) if parent_service
1748
+ fwd_opts.merge!(:do_not_encode => do_not_encode) if do_not_encode
1749
+ fwd_opts.merge!('stream-results' => stream_results) if stream_results
1750
+ new_context_params.forward_options(fwd_opts)
1751
+
1752
+ new_context_params
1753
+ end
1754
+
1755
+ def set_default_target_aux(context_params)
1756
+ target_instance_name = context_params.retrieve_arguments([:option_1!], method_argument_names)
1757
+ post_body = {
1758
+ :assembly_id => target_instance_name
1759
+ }
1760
+ post rest_url("assembly/set_default_target"), post_body
1761
+ end
1762
+
1763
+ def set_required_attributes_converge_aux(context_params, opts = {})
1764
+ assembly_or_workspace_id = context_params.retrieve_arguments([REQ_ASSEMBLY_OR_WS_ID], method_argument_names)
1765
+
1766
+ message = " You will have to converge service instance manually!"
1767
+ attributes_response = set_required_attributes_aux(assembly_or_workspace_id, :assembly, :instance, message)
1768
+ return attributes_response if attributes_response.is_a?(Response) && !attributes_response.ok?
1769
+
1770
+ response, violations = converge_aux(context_params, { :are_there_violations => true })
1771
+ return response unless response.ok?
1772
+
1773
+ if violations
1774
+ forwarded_options = context_params.get_forwarded_options()
1775
+ context_params.forward_options(forwarded_options.merge!(:violations => true))
1776
+ else
1777
+ instance_name = "/service/#{context_params.get_forwarded_options[:instance_name]}"
1778
+ opts[:instance_name] = instance_name
1779
+ DTK::Client::OsUtil.print("Service instance '#{instance_name}' deployment has been started. Changing context to '#{instance_name}'.", :green)
1780
+ end
1781
+
1782
+ response
1783
+ end
1784
+
1785
+ def create_workspace_aux(context_params)
1786
+ workspace_name = context_params.retrieve_arguments([:option_1], method_argument_names)
1787
+ parent_service = options.parent_service
1788
+
1789
+ post_body = {}
1790
+ post_body.merge!(:parent_service => parent_service) if parent_service
1791
+ if workspace_name
1792
+ # TODO: DTK-2551: Aldin put the check to see if name conflicts on server side
1793
+ assembly_list = Assembly.assembly_list()
1794
+ raise DTK::Client::DtkValidationError, "Unable to create workspace with name '#{workspace_name}'. Service or workspace with specified name exists already!" if assembly_list.include?(workspace_name)
1795
+ post_body.merge!(:workspace_name => workspace_name)
1796
+ end
1797
+
1798
+ post rest_url("assembly/create_workspace"), post_body
1799
+ end
1800
+ end
1801
+ end