dtk-client 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/dtk-client.gemspec +1 -1
  3. data/lib/cli/command/module/install.rb +9 -2
  4. data/lib/cli/command/options.rb +13 -1
  5. data/lib/cli/command/service.rb +1 -1
  6. data/lib/cli/command/service/add.rb +2 -1
  7. data/lib/cli/command/service/add_link.rb +2 -2
  8. data/lib/cli/command/service/delete.rb +2 -2
  9. data/lib/cli/command/service/describe.rb +2 -2
  10. data/lib/cli/command/service/exec.rb +1 -1
  11. data/lib/cli/command/service/exec_sync.rb +1 -1
  12. data/lib/cli/command/service/set_attribute.rb +101 -15
  13. data/lib/cli/command/service/set_default_target.rb +6 -3
  14. data/lib/cli/command/service/task_status.rb +1 -3
  15. data/lib/cli/command/token.rb +4 -1
  16. data/lib/cli/version.rb +1 -1
  17. data/lib/client/operation/module/install_from_catalog.rb +5 -3
  18. data/lib/client/operation/service/add.rb +19 -6
  19. data/lib/client/operation/service/add_link.rb +1 -1
  20. data/lib/client/operation/service/describe.rb +3 -4
  21. data/lib/client/operation/service/exec.rb +37 -11
  22. data/lib/client/operation/service/task_status.rb +4 -0
  23. data/lib/client/operation/service/task_status/stream_mode/element/hierarchical_task/result.rb +56 -3
  24. data/lib/client/operation/service/task_status/stream_mode/element/hierarchical_task/result/action.rb +5 -1
  25. data/lib/client/operation/service/task_status/stream_mode/element/hierarchical_task/result/components.rb +1 -0
  26. data/lib/client/operation/service/task_status/stream_mode/element/hierarchical_task/result/node_level.rb +10 -0
  27. data/lib/client/operation/service/uninstall.rb +6 -5
  28. metadata +5 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd3532222d39184fd4e4b3dabe6089082d66997065b60710dac9315669f0bdb1
4
- data.tar.gz: 1a596bb53b1fa93c2dfc24a792836a5377fac27947acbaeea54bf069a45dce5b
3
+ metadata.gz: 42bebff35a619d489e4ad704b1782e3d6cf17c9ffa3750f4461ab0da5125efa3
4
+ data.tar.gz: 8dd31d44f79e12576c85f32535c6f62b008a78f92e58a8e79bad3795e4535143
5
5
  SHA512:
6
- metadata.gz: 6be78d166a7b90eddd422a3e39fc2f5cc12ac382a896c5bf6813bc9c85ddfbb8aaac111a6e963eb4bcad14c0d7c2ff569122d204194d8721ef17bcaf9b56a5e1
7
- data.tar.gz: 1fad3c04de2c251f96f84a3ba729e1713024d9bdb0891c6ab2b6c8bc0eb25ae3247c0aee258933c4b9ba4aa0daf72d35e026b94db5b949427a804c640cc37c17
6
+ metadata.gz: a0ea576d32dfeeb527c87dc7b863bcc8f44a6d56998994349943643dd05b570a3a62dac340b9168f77b7ab1d8912e6fc76f23a38092e6f6f4a1d85a50cf1058f
7
+ data.tar.gz: 730004649953bdf45399fd1b7a14a5f47208904fe8ea920ce4ee1fc9ee21efe1dc0069ccbb2ec2da6c98f629698cf7db10a3010af52ba4eb19a0c9b44bb29d0f
@@ -25,5 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.add_dependency 'hirb', '0.7.3'
26
26
  spec.add_dependency 'mime-types', '~> 2.99.3'
27
27
  spec.add_dependency 'dtk-dsl', '~> 1.1.4'
28
- spec.add_dependency 'dtk-network-client', '1.0.3'
28
+ spec.add_dependency 'dtk-network-client', '1.0.4'
29
29
  end
@@ -30,6 +30,7 @@ module DTK::Client
30
30
  end
31
31
  sc.switch Token.update_deps
32
32
  sc.switch Token.update_lock
33
+ sc.switch Token.download_if_fail
33
34
 
34
35
  sc.action do |_global_options, options, args|
35
36
  module_name = args[0]
@@ -42,7 +43,8 @@ module DTK::Client
42
43
  version: options[:version],
43
44
  update_deps: options[:update_deps],
44
45
  has_directory_param: has_directory_param,
45
- update_lock_file: options['update-lock']
46
+ update_lock_file: options['update-lock'],
47
+ download_if_fail: options[:download_if_fail]
46
48
  }
47
49
  Install.execute(self, opts_hash)
48
50
  nil
@@ -59,6 +61,7 @@ module DTK::Client
59
61
  @directory_path = opts[:directory_path]
60
62
  @has_directory_param = opts[:has_directory_param]
61
63
  @update_lock_file = opts[:update_lock_file]
64
+ @download_if_fail = opts[:download_if_fail]
62
65
  end
63
66
 
64
67
  def self.execute(context, opts = {})
@@ -81,6 +84,10 @@ module DTK::Client
81
84
 
82
85
  attr_reader :context
83
86
 
87
+ def download_if_fail
88
+ @download_if_fail ||= false
89
+ end
90
+
84
91
  def module_ref
85
92
  @module_ref ||= ret_module_ref
86
93
  end
@@ -104,7 +111,7 @@ module DTK::Client
104
111
  # server (the later step Operation::Module.install does this)
105
112
 
106
113
  # TODO: 3070: handle sitution where response is not ok
107
- install_response = Operation::Module.install_from_catalog(module_ref: self.module_ref, version: self.version, directory_path: self.directory_path?)
114
+ install_response = Operation::Module.install_from_catalog(module_ref: self.module_ref, version: self.version, directory_path: self.directory_path?, download_if_fail: self.download_if_fail)
108
115
 
109
116
  if client_installed_modules = (install_response && install_response.data[:installed_modules])
110
117
  opts_server_install = {
@@ -27,8 +27,20 @@ module DTK::Client
27
27
 
28
28
  def [](canonical_name_or_opt)
29
29
  key = Token.opt?(canonical_name_or_opt) || canonical_name_or_opt
30
- @opts_hash[key]
30
+ # TODO: check why this switch to below was needed was needed
31
+ #@opts_hash[key]
32
+ case key
33
+ when ::String, ::Symbol
34
+ @opts_hash[key]
35
+ when ::Array
36
+ if matching_key = key.find { |k| @opts_hash.has_key?(k) }
37
+ @opts_hash[matching_key]
38
+ end
39
+ else
40
+ raise Eroor, "Unexpected value of key.class: #{key.class}"
41
+ end
31
42
  end
43
+
32
44
  end
33
45
  end
34
46
  end
@@ -53,7 +53,7 @@ module DTK::Client
53
53
  'task-status',
54
54
  'uninstall',
55
55
  'describe',
56
- # 'add',
56
+ 'add',
57
57
  'add-component'
58
58
  ]
59
59
 
@@ -26,7 +26,8 @@ module DTK::Client; module CLI
26
26
  args = {
27
27
  service_instance: service_instance_in_options_or_context(options),
28
28
  path: options[:path],
29
- relative_path: options[:relative_path]
29
+ relative_path: options[:relative_path],
30
+ service_instance_dir: @base_dsl_file_obj.parent_dir
30
31
  }
31
32
  Operation::Service.add(args)
32
33
  end
@@ -44,10 +44,10 @@ module DTK::Client; module CLI
44
44
  :service_instance_dir => service_instance_dir
45
45
  }
46
46
 
47
- Operation::Service.link(args)
47
+ Operation::Service.add_link(args)
48
48
  end
49
49
  end
50
50
  end
51
51
  end
52
52
  end
53
- end; end
53
+ end; end
@@ -22,7 +22,7 @@ module DTK::Client; module CLI
22
22
  command_body c, :delete, 'Destroys the running infrastructure associated with the service instance' do |sc|
23
23
  sc.flag Token.delete_service_name
24
24
  sc.flag Token.directory_path, :desc => 'Absolute or relative path to service instance directory associated; not needed if executed in service instance directory'
25
- # sc.flag Token.path, :desc => "Delete specific part of service instance. Supported paths are 'dependencies/[name]', 'components/[name]', 'actions/[name]'"
25
+ sc.flag Token.path, :desc => "Delete specific part of service instance. Supported paths are 'dependencies/[name]', 'components/[name]', 'actions/[name]'"
26
26
 
27
27
  sc.switch Token.skip_prompt, :desc => 'Skip prompt that checks if user wants to delete the service instance'
28
28
  sc.switch Token.recursive, :desc => 'Delete all service instances staged into specified target'
@@ -40,7 +40,7 @@ module DTK::Client; module CLI
40
40
  :skip_prompt => options[:skip_prompt],
41
41
  :recursive => recursive,
42
42
  :force => force,
43
- # :path => options[:path]
43
+ :path => options[:path]
44
44
  }
45
45
  args[:directory_path] = directory_path || base_dsl_file_obj.parent_dir unless name
46
46
  Operation::Service.delete(args)
@@ -19,13 +19,13 @@ module DTK::Client; module CLI
19
19
  module Command
20
20
  module Service
21
21
  subcommand_def 'describe' do |c|
22
+ c.arg Token::Arg.path
22
23
  command_body c, 'describe', 'Describe service instance content' do |sc|
23
- sc.flag Token.path, :desc => "supported paths are 'dependencies', 'components/[name]', 'actions/[name]' "
24
24
  sc.switch Token.show_steps, :desc => 'Show steps that will be executed when action is executed'
25
25
  sc.action do |_global_options, options, _args|
26
26
  args = {
27
27
  service_instance: service_instance_in_options_or_context(options),
28
- path: options[:path],
28
+ path: _args[0],
29
29
  show_steps: options['show-steps']
30
30
  }
31
31
  Operation::Service.describe(args)
@@ -21,7 +21,7 @@ module DTK::Client
21
21
  subcommand_def 'exec' do |c|
22
22
  c.arg Token::Arg.action
23
23
  c.arg Token::Arg.action_params, :optional => true
24
- command_body c, :exec, 'Execute action asynchronously' do |sc|
24
+ command_body c, :exec, 'Execute action asynchronously. Parameters need to be within quotes (\'\' or "").' do |sc|
25
25
  sc.flag Token.directory_path, :desc => 'Absolute or relative path to service instance directory containing updates to pull; not need if in the service instance directory'
26
26
  sc.flag Token.attempts, :desc => "Number of attempts"
27
27
  sc.flag Token.sleep, :desc => "Number of sleep in seconds"
@@ -21,7 +21,7 @@ module DTK::Client
21
21
  subcommand_def 'exec-sync' do |c|
22
22
  c.arg Token::Arg.action
23
23
  c.arg Token::Arg.action_params, :optional => true
24
- command_body c, 'exec-sync', 'Execute action synchronously' do |sc|
24
+ command_body c, 'exec-sync', 'Execute action synchronously. Parameters need to be within quotes (\'\' or "").' do |sc|
25
25
  sc.flag Token.directory_path, :desc => 'Absolute or relative path to service instance directory containing updates to pull; not need if in the service instance directory'
26
26
  sc.flag Token.attempts, :desc => "Number of attempts"
27
27
  sc.flag Token.sleep, :desc => "Number of sleep in seconds"
@@ -19,31 +19,117 @@ module DTK::Client; module CLI
19
19
  module Command
20
20
  module Service
21
21
  subcommand_def 'set-attribute' do |c|
22
- c.arg Token::Arg.attribute_name
22
+ c.arg Token::Arg.attribute_name, :optional => true
23
23
  c.arg Token::Arg.attribute_value, :optional => true
24
- command_body c, 'set-attribute', 'Edit specific attribute.' do |sc|
24
+ command_body c, 'set-attribute', 'Set attribute value(s).' do |sc|
25
25
  sc.switch Token.u
26
26
  sc.flag Token.directory_path
27
- sc.action do |_global_options, options, _args|
27
+ sc.flag Token.param_file
28
+ sc.action do |_global_options, options, args|
29
+ service_instance = service_instance_in_options_or_context(options)
30
+ service_instance_dir = options[:d] || @base_dsl_file_obj.parent_dir
28
31
 
29
- service_instance = service_instance_in_options_or_context(options)
32
+ helper = SetAttributeHelper.new(service_instance, service_instance_dir)
30
33
 
31
- attribute_name = _args[0]
32
- options[:u] ? attribute_value = nil : attribute_value = _args[1]
34
+ attribute_name = args[0]
35
+ # if attribute_name not given then expected that a YAML file is given that has attribute values
36
+ unless attribute_name
37
+ name_value_pairs = helper.get_name_value_pairs_from_yaml_file(options)
38
+ # TODO: should extend the server-side to take list of attributes to set; hack to return a value ret
39
+ name_value_pairs.each_pair do |attribute_name, attribute_value|
40
+ begin
41
+ helper.set_single_attribute(attribute_name, attribute_value)
42
+ rescue Error
43
+ raise Error::Usage, "Error trying to set attribute '#{attribute_name}' from YAML file"
44
+ end
45
+ end
46
+ nil
47
+ else
48
+ attribute_value =
49
+ unless options[:u]
50
+ if ruby_obj_value = helper.get_yaml_from_file?(options)
51
+ ::JSON.generate(ruby_obj_value)
52
+ else
53
+ args[1] || raise(Error::Usage, "Either argument VALUE or -f option must be given to specify a value")
54
+ end
55
+ end
56
+ helper.set_single_attribute(attribute_name, attribute_value)
57
+ end
58
+ end
59
+ end
60
+ end
33
61
 
34
- options[:d].nil? ? service_instance_dir = @base_dsl_file_obj.parent_dir : service_instance_dir = options[:d]
62
+ class SetAttributeHelper
63
+ def initialize(service_instance, service_instance_dir)
64
+ @service_instance = service_instance
65
+ @service_instance_dir = service_instance_dir
66
+ end
35
67
 
36
- args = {
37
- :attribute_name => attribute_name,
38
- :service_instance => service_instance,
39
- :attribute_value => attribute_value,
40
- :service_instance_dir => @base_dsl_file_obj.parent_dir
41
- }
68
+ def set_single_attribute(attribute_name, attribute_value)
69
+ Operation::Service.set_attribute(
70
+ :attribute_name => attribute_name,
71
+ :attribute_value => attribute_value,
72
+ :service_instance => self.service_instance,
73
+ :service_instance_dir => self.service_instance_dir
74
+ )
75
+ end
42
76
 
43
- Operation::Service.set_attribute(args)
77
+ def get_yaml_from_file?(cli_options)
78
+ if param_file_path = cli_options[:f]
79
+ param_file = check_and_return_file_content(param_file_path)
80
+ yaml_to_ruby_obj(param_file, param_file_path)
44
81
  end
45
82
  end
83
+
84
+ def get_name_value_pairs_from_yaml_file(options)
85
+ unless ruby_obj = get_yaml_from_file?(options)
86
+ raise Error::Usage, "If NAME argument is not given then -f option must be given to specify a value"
87
+ end
88
+
89
+ # check that gile is form
90
+ #attributes:
91
+ # name1: val1
92
+ # ...
93
+ unless ruby_obj.kind_of?(::Hash) and ruby_obj.size == 1 and ruby_obj.keys.first == 'attributes'
94
+ raise Error::Usage, "If NAME argument is not given, the parameter file content must be YAML hash starting with key 'attributes'"
95
+ end
96
+ name_value_pairs = ruby_obj['attributes']
97
+ unless name_value_pairs.kind_of?(::Hash)
98
+ raise Error::Usage, "If NAME argument is not given, the parameter file content must be YAML hash with name/attribute values"
99
+ end
100
+ name_value_pairs.inject({}) do |h, (k, v)|
101
+ value =
102
+ case v
103
+ when ::Hash, ::Array
104
+ ::JSON.generate(v)
105
+ else
106
+ v
107
+ end
108
+ h.merge(k => value)
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def check_and_return_file_content(path)
115
+ raise Error::Usage, "The file at path '#{path}' does not exist" unless File.file?(path)
116
+ File.open(path).read
117
+ end
118
+
119
+ def yaml_to_ruby_obj(text, path)
120
+ begin
121
+ ::YAML.load(text)
122
+ rescue
123
+ raise Error::Usage, "Content in file '#{path}' is ill-formed YAML"
124
+ end
125
+ end
126
+
127
+ protected
128
+
129
+ attr_reader :service_instance, :service_instance_dir
130
+
46
131
  end
132
+
47
133
  end
48
134
  end
49
- end; end
135
+ end; end
@@ -19,10 +19,13 @@ module DTK::Client
19
19
  module CLI::Command
20
20
  module Service
21
21
  subcommand_def 'set-default-target' do |c|
22
- c.arg Token::Arg.service_name
22
+ c.arg Token::Arg.service_name, optional: true
23
23
  command_body c, 'set-default-context', 'Create a new service instance to refer to staged infrastructure that then can be deployed' do |sc|
24
- sc.action do |_global_options, options, args|
25
- Operation::Service.set_default_target(:service_instance => args[0])
24
+ sc.flag Token.directory_path, :desc => 'Absolute or relative path to service instance directory containing updates to pull; not need if in the service instance directory'
25
+ sc.action do |_global_options, options, args|
26
+ service_instance = args[0]
27
+ service_instance ||= service_instance_in_options_or_context(options)
28
+ Operation::Service.set_default_target(:service_instance => service_instance)
26
29
  end
27
30
  end
28
31
  end
@@ -21,11 +21,9 @@ module DTK::Client; module CLI
21
21
  subcommand_def 'task-status' do |c|
22
22
  command_body c, 'task-status', "Get task status of the running or last running service instance task." do |sc|
23
23
  sc.flag Token.directory_path, :desc => 'Absolute or relative path to service instance directory; not needed if executed in the service instance directory'
24
- sc.flag Token.mode, :desc => 'Task status mode.'
25
-
24
+ sc.flag Token.mode, :desc => 'Task status mode (snapshot, refresh, stream).'
26
25
  sc.action do |_global_options, options, _args|
27
26
  service_instance = service_instance_in_options_or_context(options)
28
-
29
27
  args = {
30
28
  :service_instance => service_instance,
31
29
  :mode => options[:mode]
@@ -37,6 +37,7 @@ module DTK::Client
37
37
  :comma_seperated_contexts => Flag.new(:context, 'CONTEXT1,CONTEXT2,...' ,'Comma-seperated context service instance(s); if not specified, the default service instance serves as the context'),
38
38
  :module_ref => Flag.new(:m, ModuleRef::NamespaceModuleName.legal_form, 'Module name with namespace; not needed if command is executed from within the module directory'),
39
39
  :relative_path => Flag.new(:f, 'RELATIVE-FILE-PATH', 'Relative file path'),
40
+ :param_file => Flag.new(:f, 'PARAM-FILE', 'YAML file with command argument value'),
40
41
  :service_instance => Flag.new(:s, 'SERVICE-INSTANCE', 'Service instance name'),
41
42
  :service_name => Flag.new(:n, 'SERVICE-NAME', 'Service name'),
42
43
  :version => Flag.new(:v, 'VERSION', 'Version'),
@@ -76,7 +77,8 @@ module DTK::Client
76
77
  :update_deps => Switch.new('update-deps', "Skip prompt and update all dependencies or skip prompt and don't update all dependencies (on master)", :negatable => true, :default_value => 'prompt'),
77
78
  :skip_server => Switch.new('skip-server', 'Do not install module on server'),
78
79
  :update_lock => Switch.new([:u, 'update-lock'], 'Update lock file with new dependencies'),
79
- :show_steps => Switch.new('show-steps', 'Show steps')
80
+ :show_steps => Switch.new('show-steps', 'Show steps'),
81
+ :download_if_fail => Switch.new('download-if-fail', 'Download module content from dtkn if there is a runtime error.')
80
82
  }
81
83
 
82
84
  ARG_TOKENS = {
@@ -102,6 +104,7 @@ module DTK::Client
102
104
  :user => 'USER',
103
105
  :permissions => 'PERMISSIONS',
104
106
  :group => 'GROUP',
107
+ :path => 'PATH',
105
108
  }
106
109
 
107
110
  end
@@ -18,7 +18,7 @@
18
18
  module DTK
19
19
  module Client
20
20
  module CLI
21
- VERSION="0.12.1"
21
+ VERSION="0.12.2"
22
22
  end
23
23
  end
24
24
  end
@@ -19,7 +19,7 @@ module DTK::Client
19
19
  class Operation::Module
20
20
  class InstallFromCatalog < self
21
21
  attr_reader :version, :module_ref, :target_repo_dir
22
- def initialize(catalog, module_ref, directory_path, version, remote_module_info, type)
22
+ def initialize(catalog, module_ref, directory_path, version, remote_module_info, type, download_if_fail)
23
23
  @type = type
24
24
  @catalog = catalog
25
25
  @module_ref = module_ref
@@ -27,6 +27,7 @@ module DTK::Client
27
27
  @target_repo_dir = OsUtil.current_dir unless type == :dependency #ClientModuleDir.create_module_dir_from_path(directory_path || OsUtil.current_dir)
28
28
  @version = version # if nil wil be dynamically updated along with version attribute of @module_ref
29
29
  @remote_module_info = remote_module_info
30
+ @download_if_fail = download_if_fail
30
31
  end
31
32
  private :initialize
32
33
 
@@ -37,8 +38,9 @@ module DTK::Client
37
38
  directory_path = args[:directory_path]
38
39
  remote_module_info = args[:remote_module_info]
39
40
  type = args[:type]
41
+ download_if_fail = args[:download_if_fail]
40
42
  # will create different classes for different catalog types when we add support for them
41
- new('dtkn', module_ref, directory_path, version, remote_module_info, type).install_from_catalog
43
+ new('dtkn', module_ref, directory_path, version, remote_module_info, type, download_if_fail).install_from_catalog
42
44
  end
43
45
  end
44
46
 
@@ -50,7 +52,7 @@ module DTK::Client
50
52
  explicit_path: @directory_path,
51
53
  repo_dir: @directory_path || @target_repo_dir
52
54
  }
53
- installed_modules = DtkNetworkClient::Install.run(module_info, type: @type)
55
+ installed_modules = DtkNetworkClient::Install.run(module_info, type: @type, download_if_fail: @download_if_fail )
54
56
 
55
57
  { :installed_modules => installed_modules }
56
58
  end
@@ -20,14 +20,27 @@ module DTK::Client
20
20
  class Add < self
21
21
  def self.execute(args = Args.new)
22
22
  wrap_operation(args) do |args|
23
- service_instance = args.required(:service_instance)
24
- path = args.required(:path)
25
- relative_path = args.required(:relative_path)
26
-
27
- content = yaml_to_hash(FileHelper.get_content?(relative_path))
23
+ service_instance = args.required(:service_instance)
24
+ path = args.required(:path)
25
+ relative_path = args.required(:relative_path)
26
+ service_instance_dir = args[:service_instance_dir]
27
+ content = FileHelper.get_content?(relative_path)
28
28
 
29
29
  query_string_hash = QueryStringHash.new(:service_instance => service_instance, path: path, content: content)
30
- rest_post "#{BaseRoute}/add_by_path", query_string_hash
30
+ response = rest_post "#{BaseRoute}/add_by_path", query_string_hash
31
+
32
+ if path.include?('actions/')
33
+ repo_info_args = Args.new(
34
+ :service_instance => service_instance,
35
+ :commit_message => "Updating changes to service instance '#{service_instance}'",
36
+ :branch => response.required(:base_module, :branch, :name),
37
+ :repo_url => response.required(:base_module, :repo, :url),
38
+ :service_instance_dir => service_instance_dir
39
+ )
40
+ ClientModuleDir::GitRepo.pull_from_service_repo(repo_info_args)
41
+ end
42
+
43
+ response
31
44
  end
32
45
  end
33
46
  end
@@ -17,7 +17,7 @@
17
17
  #
18
18
  module DTK::Client
19
19
  class Operation::Service
20
- class Link < self
20
+ class AddLink < self
21
21
  def self.execute(args = Args.new)
22
22
  wrap_operation(args) do |args|
23
23
  service_instance = args.required(:service_instance)
@@ -25,20 +25,19 @@ module DTK::Client
25
25
  show_steps = args[:show_steps]
26
26
  query_string_hash = QueryStringHash.new
27
27
 
28
- raise Error, 'Option --show-steps can only be used with actions path' if show_steps && !actions_path_valid?(path)
28
+ error_msg = 'Option --show-steps can only be used with actions path. The pattern must have form actions/ACTION-NAME.'
29
+ raise Error, error_msg if show_steps && !actions_path_valid?(path)
29
30
 
30
31
  query_string_hash.merge!(path: path) if path
31
32
  query_string_hash.merge!(show_steps: show_steps) if show_steps
32
33
  response = rest_get "#{BaseRoute}/#{service_instance}/describe", query_string_hash
33
-
34
34
  response.set_render_as_table! if show_steps
35
35
  response
36
36
  end
37
37
  end
38
-
39
38
  def self.actions_path_valid?(path)
40
39
  prefix, suffix = (path||'').split('/')
41
- prefix.eql? 'actions'
40
+ prefix.eql?('actions') && suffix && !suffix.empty?
42
41
  end
43
42
 
44
43
  end
@@ -26,9 +26,10 @@ module DTK::Client
26
26
  directory_path = args[:directory_path]
27
27
  breakpoint = args[:breakpoint]
28
28
  attempts = args[:attempts] || ""
29
- sleep = args[:sleep] || ""
30
- # parse params and return format { 'p_name1' => 'p_value1' , 'p_name2' => 'p_value2' }
31
- task_params = parse_params?(action_params)||{}
29
+ sleep = args[:sleep] || ""
30
+
31
+ task_params = {}
32
+ process_action_params(action_params, task_params) unless action_params.eql? nil
32
33
 
33
34
  # this is temporary fix to handle new node as component format ec2::node[node_name]/action
34
35
  # will transform ec2::node[node_name]/action to node_name/action
@@ -80,17 +81,42 @@ module DTK::Client
80
81
 
81
82
  private
82
83
 
83
- def self.parse_params?(params_string)
84
- if params_string
85
- params_string.split(',').inject(Hash.new) do |h,av|
86
- av_split = av.split('=')
87
- unless av_split.size == 2
88
- raise Error::Usage, "The parameter string (#{params_string}) is ill-formed"
89
- end
90
- h.merge(av_split[0] => av_split[1])
84
+ def self.process_action_params(action_params, params)
85
+ if match = action_params.match(/([^=]+)=(.+)/)
86
+ extracted_value, new_params = extract_action_value(match[2])
87
+ params.merge!(match[1] => extracted_value)
88
+ process_action_params(new_params, params) unless new_params.empty?
89
+ end
90
+ end
91
+
92
+ def self.extract_action_value(ac_params)
93
+ if ac_params.start_with?('[')
94
+ match_and_return(ac_params, :array)
95
+ elsif ac_params.start_with?('{')
96
+ match_and_return(ac_params, :hash)
97
+ else
98
+ if match = ac_params.match(/([^,]+),(.*)/)
99
+ return [match[1], match[2]]
100
+ else
101
+ return [ac_params, ""]
91
102
  end
92
103
  end
93
104
  end
105
+
106
+ def self.match_and_return(ac_params, type)
107
+ match = ac_params.match(RegexTypes[type])
108
+ return [match[1], prettify(match[2])]
109
+ end
110
+
111
+ RegexTypes = {
112
+ array: Regexp.new(/([^\]]+\])(.*)/),
113
+ hash: Regexp.new(/([^\}]+\})(.*)/)
114
+ }
115
+
116
+ def self.prettify(remaining)
117
+ remaining.sub!(",", "") unless remaining.empty?
118
+ remaining
119
+ end
94
120
  end
95
121
  end
96
122
  end
@@ -59,7 +59,11 @@ module DTK::Client
59
59
  when :snapshot
60
60
  SnapshotMode.new(mode, service_instance).task_status(opts)
61
61
  when :stream
62
+ begin
62
63
  StreamMode.new(mode, service_instance).get_and_render(opts)
64
+ rescue Interrupt => e
65
+ puts "Exiting ..."
66
+ end
63
67
  else
64
68
  raise Error::Usage.new("Illegal mode '#{mode}'; legal modes are: #{LEGAL_MODES.join(', ')}")
65
69
  end
@@ -26,6 +26,7 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element
26
26
  super
27
27
  @errors = hash['errors'] || []
28
28
  @info = hash['info'] || []
29
+ @action_results = hash['action_results'] || []
29
30
  end
30
31
 
31
32
  # This can be over-written
@@ -44,9 +45,12 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element
44
45
 
45
46
  attr_reader :errors
46
47
  attr_reader :info
48
+ attr_reader :action_results
47
49
 
48
50
  def render_errors(results_per_node)
49
- return unless results_per_node.find { |result| not result.errors.empty?}
51
+ return unless results_per_node.find do |result|
52
+ not result.errors.empty?
53
+ end
50
54
  first_time = true
51
55
  results_per_node.each do |result|
52
56
  if first_time
@@ -72,6 +76,20 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element
72
76
  end
73
77
  end
74
78
 
79
+ def render_output(results_per_node)
80
+ return unless results_per_node.find do |result|
81
+ not result.action_results.empty?
82
+ end
83
+ first_time = true
84
+ results_per_node.each do |result|
85
+ if first_time
86
+ render_line 'OUTPUT:'
87
+ first_time = false
88
+ end
89
+ result.render_node_output
90
+ end
91
+ end
92
+
75
93
  def render_node_errors
76
94
  return if @errors.empty?
77
95
  render_node_term
@@ -94,6 +112,34 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element
94
112
  end
95
113
  end
96
114
 
115
+ def render_node_output
116
+ return if @action_results.empty?
117
+ @action_results.each do |output|
118
+ if dynamic_attrs = output['dynamic_attributes']
119
+ render_dynamic_attrs(dynamic_attrs)
120
+ end
121
+ end
122
+ end
123
+
124
+ def render_dynamic_attrs(dynamic_attrs)
125
+ dynamic_attrs.each do |name, opts|
126
+ next unless opts['value']
127
+ out = opts['value']
128
+
129
+ if disp_form = opts['display_format']
130
+ out =
131
+ case disp_form
132
+ when 'yaml'
133
+ out.to_yaml
134
+ when 'json'
135
+ out.to_json
136
+ end
137
+ end
138
+ render_output_line(name + ':', out)
139
+ render_empty_line
140
+ end
141
+ end
142
+
97
143
  def render_error_line(line, opts = {})
98
144
  render_line(line, ErrorRenderOpts.merge(opts))
99
145
  end
@@ -101,8 +147,15 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element
101
147
  def render_info_line(line, opts = {})
102
148
  render_line(line)
103
149
  end
104
- ErrorRenderOpts = { :tabs => 1}
105
-
150
+
151
+ def render_output_line(attr_name, attr_value)
152
+ render_line attr_name, RenderAttrNameOpts
153
+ render_line attr_value, RenderAttrValOpts
154
+ end
155
+ ErrorRenderOpts = { :tabs => 1 }
156
+ RenderAttrNameOpts = { :tabs => 1 }
157
+ RenderAttrValOpts = { :tabs => 2 }
158
+
106
159
  end
107
160
  end
108
161
  end; end
@@ -26,12 +26,12 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element::H
26
26
  attr_reader :action_results
27
27
 
28
28
  def render_results(results_per_node)
29
+ render_info(results_per_node)
29
30
  if any_results?(results_per_node)
30
31
  render_line 'RESULTS:'
31
32
  render_empty_line
32
33
  results_per_node.each { |result| result.render }
33
34
  else
34
- render_info(results_per_node)
35
35
  render_errors(results_per_node)
36
36
  end
37
37
  end
@@ -72,6 +72,10 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element::H
72
72
  render_line 'STDERR:'
73
73
  render_action_output stderr
74
74
  end
75
+ if dynamic_attrs = action_result['dynamic_attributes']
76
+ render_line 'OUTPUT:'
77
+ render_dynamic_attrs(dynamic_attrs)
78
+ end
75
79
  end
76
80
 
77
81
  def render_action_output(line)
@@ -21,6 +21,7 @@ module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element::H
21
21
  def render_results(results_per_node)
22
22
  render_errors(results_per_node)
23
23
  render_info(results_per_node)
24
+ render_output(results_per_node)
24
25
  end
25
26
  end
26
27
  end
@@ -18,6 +18,16 @@
18
18
  module DTK::Client; class Operation::Service::TaskStatus::StreamMode::Element::HierarchicalTask
19
19
  class Results
20
20
  class NodeLevel < self
21
+ def render
22
+ not_first_time = nil
23
+ render_node_term
24
+ @action_results.each do |action_result|
25
+ render_action_result_lines(action_result, :first_time => not_first_time.nil?)
26
+ not_first_time ||= true
27
+ end
28
+ render_empty_line
29
+ end
30
+
21
31
  def render_results(results_per_node)
22
32
  render_errors(results_per_node)
23
33
  end
@@ -51,14 +51,15 @@ module DTK::Client
51
51
  :force => force
52
52
  )
53
53
  response = rest_post("#{BaseRoute}/uninstall", post_body)
54
-
54
+ path = ClientModuleDir.ret_base_path(:service, service_instance) unless path
55
55
  ClientModuleDir.rm_f(path) if args[:purge]
56
-
57
56
  if message = response.data(:message) || "DTK service '#{service_instance}' has been uninstalled successfully."
58
- Dir.glob("*", File::FNM_DOTMATCH).each do |f|
59
- ClientModuleDir.rm_f(f) if f.include? '.task_id_'
57
+ if Dir.exists?(path) && !args[:purge]
58
+ Dir.entries(path).each do |f|
59
+ ClientModuleDir.rm_f("#{path}/#{f}") if f.include? '.task_id_'
60
+ end
61
+ ClientModuleDir.create_file_with_content("#{path}/.task_id_#{response.data(:task_id)}", '') if response.data(:task_id)
60
62
  end
61
- ClientModuleDir.create_file_with_content(".task_id_#{response.data(:task_id)}", '') if response.data(:task_id)
62
63
  OsUtil.print_info(message)
63
64
  end
64
65
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dtk-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reactor8
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-18 00:00:00.000000000 Z
11
+ date: 2019-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dtk-common-core
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - '='
130
130
  - !ruby/object:Gem::Version
131
- version: 1.0.3
131
+ version: 1.0.4
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - '='
137
137
  - !ruby/object:Gem::Version
138
- version: 1.0.3
138
+ version: 1.0.4
139
139
  description: Command line tool to interact with a DTK Server and DTK Service Catalog.
140
140
  email: support@reactor8.com
141
141
  executables:
@@ -429,8 +429,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
429
429
  - !ruby/object:Gem::Version
430
430
  version: '0'
431
431
  requirements: []
432
- rubyforge_project:
433
- rubygems_version: 2.7.8
432
+ rubygems_version: 3.0.2
434
433
  signing_key:
435
434
  specification_version: 4
436
435
  summary: DTK CLI client for DTK server interaction.