dtk-shell 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile_dev +13 -0
  4. data/README.md +121 -0
  5. data/bin/dtk-execute +32 -0
  6. data/bin/dtk-run +92 -0
  7. data/bin/dtk-shell +31 -0
  8. data/dtk-shell.gemspec +50 -0
  9. data/lib/auxiliary.rb +61 -0
  10. data/lib/bundler_monkey_patch.rb +26 -0
  11. data/lib/client.rb +58 -0
  12. data/lib/command_helper.rb +33 -0
  13. data/lib/command_helpers/git_repo.rb +589 -0
  14. data/lib/command_helpers/git_repo/merge.rb +153 -0
  15. data/lib/command_helpers/jenkins_client.rb +106 -0
  16. data/lib/command_helpers/jenkins_client/config_xml.rb +288 -0
  17. data/lib/command_helpers/service_importer.rb +251 -0
  18. data/lib/command_helpers/service_link.rb +33 -0
  19. data/lib/command_helpers/test_module_creator.rb +69 -0
  20. data/lib/command_helpers/test_module_templates/dtk.model.yaml.eruby +10 -0
  21. data/lib/command_helpers/test_module_templates/spec_helper.rb.eruby +10 -0
  22. data/lib/command_helpers/test_module_templates/temp_component_spec.rb.eruby +5 -0
  23. data/lib/commands.rb +57 -0
  24. data/lib/commands/common/thor/access_control.rb +133 -0
  25. data/lib/commands/common/thor/action_result_handler.rb +74 -0
  26. data/lib/commands/common/thor/assembly_template.rb +92 -0
  27. data/lib/commands/common/thor/assembly_workspace.rb +1801 -0
  28. data/lib/commands/common/thor/base_command_helper.rb +59 -0
  29. data/lib/commands/common/thor/clone.rb +82 -0
  30. data/lib/commands/common/thor/common.rb +88 -0
  31. data/lib/commands/common/thor/common_base.rb +49 -0
  32. data/lib/commands/common/thor/create_target.rb +70 -0
  33. data/lib/commands/common/thor/edit.rb +255 -0
  34. data/lib/commands/common/thor/inventory_parser.rb +98 -0
  35. data/lib/commands/common/thor/list_diffs.rb +128 -0
  36. data/lib/commands/common/thor/module.rb +1011 -0
  37. data/lib/commands/common/thor/module/import.rb +210 -0
  38. data/lib/commands/common/thor/node.rb +53 -0
  39. data/lib/commands/common/thor/poller.rb +65 -0
  40. data/lib/commands/common/thor/pull_clone_changes.rb +28 -0
  41. data/lib/commands/common/thor/pull_from_remote.rb +152 -0
  42. data/lib/commands/common/thor/puppet_forge.rb +72 -0
  43. data/lib/commands/common/thor/purge_clone.rb +101 -0
  44. data/lib/commands/common/thor/push_clone_changes.rb +162 -0
  45. data/lib/commands/common/thor/push_to_remote.rb +94 -0
  46. data/lib/commands/common/thor/remotes.rb +71 -0
  47. data/lib/commands/common/thor/reparse.rb +40 -0
  48. data/lib/commands/common/thor/set_required_attributes.rb +46 -0
  49. data/lib/commands/thor/account.rb +239 -0
  50. data/lib/commands/thor/assembly.rb +356 -0
  51. data/lib/commands/thor/attribute.rb +79 -0
  52. data/lib/commands/thor/component.rb +70 -0
  53. data/lib/commands/thor/component_module.rb +501 -0
  54. data/lib/commands/thor/component_template.rb +174 -0
  55. data/lib/commands/thor/dependency.rb +34 -0
  56. data/lib/commands/thor/developer.rb +144 -0
  57. data/lib/commands/thor/dtk.rb +152 -0
  58. data/lib/commands/thor/library.rb +125 -0
  59. data/lib/commands/thor/node.rb +504 -0
  60. data/lib/commands/thor/node_template.rb +94 -0
  61. data/lib/commands/thor/project.rb +34 -0
  62. data/lib/commands/thor/provider.rb +233 -0
  63. data/lib/commands/thor/remotes.rb +49 -0
  64. data/lib/commands/thor/service.rb +941 -0
  65. data/lib/commands/thor/service_module.rb +914 -0
  66. data/lib/commands/thor/state_change.rb +25 -0
  67. data/lib/commands/thor/target.rb +250 -0
  68. data/lib/commands/thor/task.rb +116 -0
  69. data/lib/commands/thor/test_module.rb +310 -0
  70. data/lib/commands/thor/utils.rb +21 -0
  71. data/lib/commands/thor/workspace.rb +685 -0
  72. data/lib/config/cacert.pem +3785 -0
  73. data/lib/config/client.conf.header +20 -0
  74. data/lib/config/configuration.rb +99 -0
  75. data/lib/config/default.conf +16 -0
  76. data/lib/config/disk_cacher.rb +80 -0
  77. data/lib/configurator.rb +176 -0
  78. data/lib/context_router.rb +44 -0
  79. data/lib/core.rb +497 -0
  80. data/lib/domain/git_adapter.rb +412 -0
  81. data/lib/domain/git_error_handler.rb +64 -0
  82. data/lib/domain/response.rb +285 -0
  83. data/lib/domain/response/error_handler.rb +86 -0
  84. data/lib/dtk-shell/version.rb +20 -0
  85. data/lib/dtk_constants.rb +40 -0
  86. data/lib/dtk_error.rb +114 -0
  87. data/lib/dtk_logger.rb +126 -0
  88. data/lib/dtk_shell.rb +31 -0
  89. data/lib/error.rb +85 -0
  90. data/lib/execute.rb +29 -0
  91. data/lib/execute/cli_pure/cli_rerouter.rb +102 -0
  92. data/lib/execute/command.rb +40 -0
  93. data/lib/execute/command/api_call.rb +60 -0
  94. data/lib/execute/command/api_call/map.rb +60 -0
  95. data/lib/execute/command/api_call/service.rb +91 -0
  96. data/lib/execute/command/api_call/translation_term.rb +119 -0
  97. data/lib/execute/command/rest_call.rb +37 -0
  98. data/lib/execute/command_processor.rb +30 -0
  99. data/lib/execute/command_processor/rest_call.rb +59 -0
  100. data/lib/execute/error_usage.rb +21 -0
  101. data/lib/execute/execute_context.rb +86 -0
  102. data/lib/execute/execute_context/result_store.rb +37 -0
  103. data/lib/execute/script.rb +64 -0
  104. data/lib/execute/script/add_tenant.rb +121 -0
  105. data/lib/git-logs/git.log +0 -0
  106. data/lib/parser/adapters/option_parser.rb +70 -0
  107. data/lib/parser/adapters/thor.rb +555 -0
  108. data/lib/parser/adapters/thor/common_option_defs.rb +40 -0
  109. data/lib/require_first.rb +104 -0
  110. data/lib/search_hash.rb +44 -0
  111. data/lib/shell.rb +261 -0
  112. data/lib/shell/context.rb +1065 -0
  113. data/lib/shell/context_aux.rb +46 -0
  114. data/lib/shell/domain/active_context.rb +186 -0
  115. data/lib/shell/domain/context_entity.rb +89 -0
  116. data/lib/shell/domain/context_params.rb +223 -0
  117. data/lib/shell/domain/override_tasks.rb +88 -0
  118. data/lib/shell/domain/shadow_entity.rb +76 -0
  119. data/lib/shell/header_shell.rb +44 -0
  120. data/lib/shell/help_monkey_patch.rb +283 -0
  121. data/lib/shell/interactive_wizard.rb +225 -0
  122. data/lib/shell/message_queue.rb +63 -0
  123. data/lib/shell/parse_monkey_patch.rb +39 -0
  124. data/lib/shell/status_monitor.rb +124 -0
  125. data/lib/task_status.rb +83 -0
  126. data/lib/task_status/refresh_mode.rb +77 -0
  127. data/lib/task_status/snapshot_mode.rb +28 -0
  128. data/lib/task_status/stream_mode.rb +48 -0
  129. data/lib/task_status/stream_mode/element.rb +101 -0
  130. data/lib/task_status/stream_mode/element/format.rb +101 -0
  131. data/lib/task_status/stream_mode/element/hierarchical_task.rb +100 -0
  132. data/lib/task_status/stream_mode/element/hierarchical_task/result.rb +72 -0
  133. data/lib/task_status/stream_mode/element/hierarchical_task/result/action.rb +93 -0
  134. data/lib/task_status/stream_mode/element/hierarchical_task/result/components.rb +26 -0
  135. data/lib/task_status/stream_mode/element/hierarchical_task/result/node_level.rb +26 -0
  136. data/lib/task_status/stream_mode/element/hierarchical_task/steps.rb +34 -0
  137. data/lib/task_status/stream_mode/element/hierarchical_task/steps/action.rb +53 -0
  138. data/lib/task_status/stream_mode/element/hierarchical_task/steps/components.rb +53 -0
  139. data/lib/task_status/stream_mode/element/hierarchical_task/steps/node_level.rb +42 -0
  140. data/lib/task_status/stream_mode/element/no_results.rb +26 -0
  141. data/lib/task_status/stream_mode/element/render.rb +59 -0
  142. data/lib/task_status/stream_mode/element/stage.rb +84 -0
  143. data/lib/task_status/stream_mode/element/stage/render.rb +76 -0
  144. data/lib/task_status/stream_mode/element/task_end.rb +35 -0
  145. data/lib/task_status/stream_mode/element/task_start.rb +37 -0
  146. data/lib/util/common_util.rb +37 -0
  147. data/lib/util/console.rb +235 -0
  148. data/lib/util/dtk_puppet.rb +65 -0
  149. data/lib/util/module_util.rb +66 -0
  150. data/lib/util/os_util.rb +385 -0
  151. data/lib/util/permission_util.rb +31 -0
  152. data/lib/util/remote_dependency_util.rb +84 -0
  153. data/lib/util/ssh_util.rb +94 -0
  154. data/lib/view_processor.rb +129 -0
  155. data/lib/view_processor/augmented_simple_list.rb +44 -0
  156. data/lib/view_processor/hash_pretty_print.rb +123 -0
  157. data/lib/view_processor/simple_list.rb +156 -0
  158. data/lib/view_processor/table_print.rb +309 -0
  159. data/lib/violation.rb +86 -0
  160. data/lib/violation/attribute.rb +76 -0
  161. data/lib/violation/fix.rb +26 -0
  162. data/lib/violation/fix/result.rb +73 -0
  163. data/lib/violation/fix/result/error.rb +34 -0
  164. data/lib/violation/fix/set_attribute.rb +41 -0
  165. data/lib/violation/sub_classes.rb +60 -0
  166. data/puppet/manifests/init.pp +72 -0
  167. data/puppet/manifests/params.pp +16 -0
  168. data/puppet/r8meta.puppet.yml +35 -0
  169. data/puppet/templates/bash_profile.erb +2 -0
  170. data/puppet/templates/client.conf.erb +1 -0
  171. data/puppet/templates/dtkclient.erb +2 -0
  172. data/spec/component_module_spec.rb +34 -0
  173. data/spec/dependency_spec.rb +6 -0
  174. data/spec/dtk_shell_spec.rb +13 -0
  175. data/spec/dtk_spec.rb +33 -0
  176. data/spec/lib/spec_helper.rb +10 -0
  177. data/spec/lib/spec_thor.rb +108 -0
  178. data/spec/node_template_spec.rb +24 -0
  179. data/spec/project_spec.rb +6 -0
  180. data/spec/repo_spec.rb +7 -0
  181. data/spec/response_spec.rb +52 -0
  182. data/spec/service_module_spec.rb +38 -0
  183. data/spec/service_spec.rb +50 -0
  184. data/spec/state_change_spec.rb +7 -0
  185. data/spec/table_print_spec.rb +48 -0
  186. data/spec/target_spec.rb +57 -0
  187. data/spec/task_spec.rb +28 -0
  188. data/views/assembly/augmented_simple_list.rb +12 -0
  189. data/views/assembly_template/augmented_simple_list.rb +12 -0
  190. data/views/list_task/augmented_simple_list.rb +12 -0
  191. metadata +421 -0
@@ -0,0 +1,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