morpheus-cli 6.0.0 → 6.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd7f59f72f0bc788526827effe2023844d0a99eb3485b27f276b296d604b00e0
4
- data.tar.gz: f10d8bd99db70dc0399475e5df17d93eab19b6ed45748a6edefcfb9fd5f5b945
3
+ metadata.gz: eb39926e3f31b77cdca9175335ca0260b720641e469a240618fc98816b2b98ee
4
+ data.tar.gz: ef40d39ffa3f4a6d51139524fee83dd990b082c326b528ad66a6a8e6629c43e0
5
5
  SHA512:
6
- metadata.gz: fd82a4e9ff23ba92dd577667e28258b4cf04d1ee147210b6553cbda7e56c1aea5313a8f2c25a4703f7e67d3dfdeefcb3ca811fd9cd9037c6980062f8ee40475e
7
- data.tar.gz: c0ffcee9b0a774ffcb0df995b1fbd5247ea6fcc4dad3f1d2fa7ab3ceff6e9a4e89faf29e87a65c335a3eab6db2bce1368b60ef0453ed8fbe1e18f77186767154
6
+ metadata.gz: 32d58f65d940360fdfb48ff00f88d7f2221dbe4ad1d50adbd441ee68ae79cf7fb5e1314b7d1644808a8795fa362b0e0698e0d89ef8f57187442880fc1a0fec40
7
+ data.tar.gz: 19f7a173551371d306edbbbde91ad910f96c5c77fe8c70ef09200ba85e50885e4533cfb36c1f6c26b3cacacb629d7459aabb569f03e71d07e0a5720e3134fc9c
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 6.0.0
3
+ RUN gem install morpheus-cli -v 6.0.2
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -43,10 +43,10 @@ class Morpheus::JobsInterface < Morpheus::APIClient
43
43
  execute(method: :delete, url: url, headers: headers)
44
44
  end
45
45
 
46
- def execute_job(id, params={})
46
+ def execute_job(id, payload={}, params={})
47
47
  url = "#{base_path}/#{id}/execute"
48
48
  headers = { params: params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
49
- execute(method: :put, url: url, headers: headers)
49
+ execute(method: :put, url: url, headers: headers, payload: payload.to_json)
50
50
  end
51
51
 
52
52
  =begin
@@ -23,6 +23,22 @@ class Morpheus::NetworkServicesInterface < Morpheus::APIClient
23
23
  execute(method: :get, url: url, headers: headers)
24
24
  end
25
25
 
26
+ def get_server(server_id)
27
+ execute(method: :get, url: "#{@base_url}/api/networks/servers/#{server_id}", params: {}, headers: {})
28
+ end
29
+
30
+ def list_servers()
31
+ execute(method: :get, url: "#{@base_url}/api/networks/servers", params: {}, headers: {})
32
+ end
33
+
34
+ def refresh(server_id)
35
+ url = "#{@base_url}/api/networks/servers/#{server_id}/refresh"
36
+
37
+ headers = { :params => {}, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
38
+ opts = {method: :post, url: url, headers: headers}
39
+ execute(opts)
40
+ end
41
+
26
42
  # def create(payload)
27
43
  # url = "#{@base_url}/api/networks/services"
28
44
  # headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
@@ -1020,7 +1020,7 @@ EOT
1020
1020
  end
1021
1021
 
1022
1022
  def apply(args)
1023
- default_refresh_interval = 10
1023
+ default_refresh_interval = 5
1024
1024
  params, payload, options = {}, {}, {}
1025
1025
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1026
1026
  opts.banner = subcommand_usage("[app] [options]")
@@ -716,6 +716,7 @@ EOT
716
716
  # "Content" => lambda {|it| it['content'] },
717
717
  "Enabled" => lambda {|it| format_boolean(it['enabled']) },
718
718
  "Featured" => lambda {|it| format_boolean(it['featured']) },
719
+ "Allow Quantity" => lambda {|it| format_boolean(it['allowQuantity']) },
719
720
  #"Config" => lambda {|it| it['config'] },
720
721
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
721
722
  "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
@@ -757,19 +758,20 @@ EOT
757
758
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 4},
758
759
  {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true, 'displayOrder' => 5},
759
760
  {'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 6},
760
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true, 'displayOrder' => 7},
761
- {'fieldName' => 'layoutCode', 'fieldLabel' => 'Layout Code', 'type' => 'text', 'required' => false, 'displayOrder' => 8},
762
- {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList', 'displayOrder' => 9},
761
+ {'fieldName' => 'allowQuantity', 'fieldLabel' => 'Allow Quantity', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 7},
762
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true, 'displayOrder' => 8},
763
+ {'fieldName' => 'layoutCode', 'fieldLabel' => 'Layout Code', 'type' => 'text', 'required' => false, 'displayOrder' => 9},
764
+ {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList', 'displayOrder' => 10},
763
765
  #{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.', 'displayOrder' => 8},
764
- {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true, 'displayOrder' => 10},
765
- {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflowConfig', 'fieldLabel' => 'Config', 'type' => 'textarea', 'description' => 'Enter configuration for the Workflow', 'required' => false, 'noParse' => true, 'displayOrder' => 10},
766
- {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true, 'displayOrder' => 11},
767
- {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'displayOrder' => 12},
768
- {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'noParams' => true, 'displayOrder' => 13},
766
+ {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true, 'displayOrder' => 11},
767
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflowConfig', 'fieldLabel' => 'Config', 'type' => 'textarea', 'description' => 'Enter configuration for the Workflow', 'required' => false, 'noParse' => true, 'displayOrder' => 11},
768
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true, 'displayOrder' => 12},
769
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'displayOrder' => 13},
770
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'noParams' => true, 'displayOrder' => 14},
769
771
  {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
770
772
  [{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
771
773
  }, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
772
- {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item', 'displayOrder' => 14}
774
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item', 'displayOrder' => 15}
773
775
  ]
774
776
  end
775
777
 
@@ -27,7 +27,11 @@ class Morpheus::Cli::CurlCommand
27
27
  curl_method = "DELETE"
28
28
  end
29
29
  opts.on( '--data DATA', String, "HTTP request body for use with POST and PUT, typically JSON." ) do |val|
30
- curl_data = val
30
+ begin
31
+ options[:payload] = JSON.parse(val.to_s)
32
+ rescue => ex
33
+ raise ::OptionParser::InvalidOption.new("Failed to parse payload as JSON. Error: #{ex.message}")
34
+ end
31
35
  end
32
36
  opts.on('--absolute', "Absolute path, value can be used to prevent automatic using the automatic /api/ path prefix to the path by default.") do
33
37
  options[:absolute_path] = true
@@ -4946,7 +4946,7 @@ EOT
4946
4946
  end
4947
4947
 
4948
4948
  def apply(args)
4949
- default_refresh_interval = 10
4949
+ default_refresh_interval = 5
4950
4950
  params, payload, options = {}, {}, {}
4951
4951
  optparse = Morpheus::Cli::OptionParser.new do |opts|
4952
4952
  opts.banner = subcommand_usage("[instance] [options]")
@@ -350,7 +350,7 @@ class Morpheus::Cli::InvoicesCommand
350
350
  if cost_rows.sum { |it| it[:extra].to_f } == 0
351
351
  cost_columns.delete("Extra".upcase)
352
352
  end
353
- print as_pretty_table(cost_rows, cost_columns, options)
353
+ print as_pretty_table(cost_rows, cost_columns, options.merge(include_fields: nil))
354
354
  else
355
355
  print "\n"
356
356
  print yellow, "No invoice totals data", reset, "\n"
@@ -280,17 +280,37 @@ class Morpheus::Cli::JobsCommand
280
280
  end
281
281
  options[:type] = 'morpheus.securityScan'
282
282
  end
283
- opts.on('--context-type [TYPE]', String, "Context type (instance|server|none). Default is none") do |val|
283
+ opts.on('--context-type [TYPE]', String, "Context type (instance|instance-label|server|server-label|none). Default is none") do |val|
284
+ val = val.to_s.downcase
284
285
  params['targetType'] = (val == 'none' ? 'appliance' : val)
285
286
  end
287
+ opts.on('--target-type [TYPE]', String, "alias for --context-type") do |val|
288
+ val = val.to_s.downcase
289
+ params['targetType'] = (val == 'none' ? 'appliance' : val)
290
+ end
291
+ opts.add_hidden_option('--target-type')
286
292
  opts.on('--instances [LIST]', Array, "Context instances(s), comma separated list of instance IDs. Incompatible with --servers") do |list|
287
293
  params['targetType'] = 'instance'
288
294
  params['targets'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq.collect {|it| {'refId' => it.to_i}}
289
295
  end
296
+ opts.on('--instance-label LABEL', String, "Instance Label") do |val|
297
+ if params['targetType'] && params['targetType'] != 'instance-label'
298
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{params['targetType']})")
299
+ end
300
+ params['targetType'] = 'instance-label'
301
+ params['instanceLabel'] = val
302
+ end
290
303
  opts.on('--servers [LIST]', Array, "Context server(s), comma separated list of server IDs. Incompatible with --instances") do |list|
291
304
  params['targetType'] = 'server'
292
305
  params['targets'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq.collect {|it| {'refId' => it.to_i}}
293
306
  end
307
+ opts.on('--server-label LABEL', String, "Server Label") do |val|
308
+ if params['targetType'] && params['targetType'] != 'server-label'
309
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{params['targetType']})")
310
+ end
311
+ params['targetType'] = 'server-label'
312
+ params['serverLabel'] = val
313
+ end
294
314
  opts.on('-S', '--schedule [SCHEDULE]', String, "Job execution schedule type name or ID") do |val|
295
315
  options[:schedule] = val
296
316
  end
@@ -465,8 +485,15 @@ class Morpheus::Cli::JobsCommand
465
485
  end
466
486
  end
467
487
  params['targets'] = targets.collect {|it| {'refId' => it}}
488
+ elsif params['targetType'] == 'instance-label'
489
+ if params['instanceLabel'].nil?
490
+ params['instanceLabel'] = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instance-label', 'fieldName' => 'instanceLabel', 'fieldLabel' => 'Instance Label', 'type' => 'text', 'required' => true, 'description' => 'Instance Label'}], options[:options], @api_client)['instanceLabel']
491
+ end
492
+ elsif params['targetType'] == 'server-label'
493
+ if params['serverLabel'].nil?
494
+ params['serverLabel'] = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'server-label', 'fieldName' => 'serverLabel', 'fieldLabel' => 'Server Label', 'type' => 'text', 'required' => true, 'description' => 'Server Label'}], options[:options], @api_client)['serverLabel']
495
+ end
468
496
  end
469
-
470
497
  # schedule
471
498
  if options[:schedule].nil?
472
499
  options[:schedule] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'scheduleMode', 'fieldLabel' => "Schedule", 'type' => 'select', 'required' => true, 'selectOptions' => job_options['schedules'], 'defaultValue' => job_options['schedules'].first['name']}], options[:options], @api_client, {})['scheduleMode']
@@ -554,17 +581,37 @@ class Morpheus::Cli::JobsCommand
554
581
  options[:security_package] = val
555
582
  end
556
583
  end
557
- opts.on('--context-type [TYPE]', String, "Context type (instance|server|none). Default is none") do |val|
584
+ opts.on('--context-type [TYPE]', String, "Context type (instance|instance-label|server|server-label|none). Default is none") do |val|
585
+ val = val.to_s.downcase
586
+ params['targetType'] = (val == 'none' ? 'appliance' : val)
587
+ end
588
+ opts.on('--target-type [TYPE]', String, "alias for --context-type") do |val|
589
+ val = val.to_s.downcase
558
590
  params['targetType'] = (val == 'none' ? 'appliance' : val)
559
591
  end
592
+ opts.add_hidden_option('--target-type')
560
593
  opts.on('--instances [LIST]', Array, "Context instances(s), comma separated list of instance IDs. Incompatible with --servers") do |list|
561
594
  params['targetType'] = 'instance'
562
595
  options[:targets] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip.to_i }.compact.uniq.collect {|it| {'refId' => it.to_i}}
563
596
  end
597
+ opts.on('--instance-label LABEL', String, "Instance Label") do |val|
598
+ if params['targetType'] && params['targetType'] != 'instance-label'
599
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{params['targetType']})")
600
+ end
601
+ params['targetType'] = 'instance-label'
602
+ params['instanceLabel'] = val
603
+ end
564
604
  opts.on('--servers [LIST]', Array, "Context server(s), comma separated list of server IDs. Incompatible with --instances") do |list|
565
605
  params['targetType'] = 'server'
566
606
  options[:targets] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip.to_i }.compact.uniq.collect {|it| {'refId' => it.to_i}}
567
607
  end
608
+ opts.on('--server-label LABEL', String, "Server Label") do |val|
609
+ if params['targetType'] && params['targetType'] != 'server-label'
610
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{params['targetType']})")
611
+ end
612
+ params['targetType'] = 'server-label'
613
+ params['serverLabel'] = val
614
+ end
568
615
  opts.on('--schedule [SCHEDULE]', String, "Job execution schedule type name or ID") do |val|
569
616
  options[:schedule] = val
570
617
  end
@@ -24,6 +24,9 @@ class Morpheus::Cli::LoadBalancers
24
24
  render_response(json_response, options, rest_object_key) do
25
25
  record = json_response[rest_object_key]
26
26
  options[:exclude_username] = record['username'].nil?
27
+ options[:exclude_owner] = record['owner'].nil?
28
+ options[:exclude_tenants] = record['tenants'].nil? || record['tenants'].empty?
29
+ options[:exclude_permissions] = record['resourcePermission'].nil?
27
30
  print_h1 rest_label, [], options
28
31
  print cyan
29
32
  print_description_list(rest_column_definitions(options), record, options)
@@ -125,6 +128,8 @@ EOT
125
128
  "Provider ID" => 'externalId'
126
129
  }
127
130
  columns.merge!({"Username" => 'username'}) if !options[:exclude_username]
131
+ columns.merge!({"Owner" => lambda { |it| it['owner']['name'] rescue '' }}) if !options[:exclude_owner]
132
+ columns.merge!({"Tenants" => lambda { |it| it['tenants'].collect {|tenant| tenant['name']}.join(', ') rescue '' }}) if !options[:exclude_tenants]
128
133
  columns.merge({
129
134
  "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
130
135
  "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
@@ -7,7 +7,7 @@ class Morpheus::Cli::NetworkServicesCommand
7
7
  set_command_name :'network-services'
8
8
 
9
9
  # register_subcommands :list, :get, :add, :update, :remove
10
- register_subcommands :list
10
+ register_subcommands :list, :refresh
11
11
 
12
12
  # set_default_subcommand :list
13
13
 
@@ -90,6 +90,43 @@ class Morpheus::Cli::NetworkServicesCommand
90
90
  exit 1
91
91
  end
92
92
  end
93
+
94
+ def refresh(args)
95
+ options = {}
96
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
97
+ opts.banner = subcommand_usage("[name]")
98
+ build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
99
+ opts.footer = "Refresh a network integration/server.\n" +
100
+ "[name] is required. This is the name or id of a network server/integration."
101
+ end
102
+ optparse.parse!(args)
103
+ if args.count < 1
104
+ puts optparse
105
+ exit 1
106
+ end
107
+ connect(options)
108
+ begin
109
+ server = find_network_server_by_name_or_id(args[0])
110
+ if !server
111
+ exit 1
112
+ end
113
+ @network_services_interface.setopts(options)
114
+ if options[:dry_run]
115
+ print_dry_run @network_services_interface.dry.refresh(server['id'])
116
+ return
117
+ end
118
+ json_response = @network_services_interface.refresh(server['id'])
119
+ if options[:json]
120
+ print JSON.pretty_generate(json_response)
121
+ print "\n"
122
+ elsif !options[:quiet]
123
+ print_green_success "Refreshing #{server["name"]}"
124
+ end
125
+ rescue RestClient::Exception => e
126
+ print_rest_exception(e, options)
127
+ exit 1
128
+ end
129
+ end
93
130
 
94
131
 
95
132
  private
@@ -136,4 +173,26 @@ class Morpheus::Cli::NetworkServicesCommand
136
173
  end
137
174
  end
138
175
 
176
+ def find_network_server_by_name_or_id(val)
177
+ if val.to_s =~ /\A\d{1,}\Z/
178
+ return find_network_server_by_id(val)
179
+ else
180
+ return find_network_service_by_name(val)
181
+ end
182
+ end
183
+
184
+ def find_network_server_by_id(id)
185
+ begin
186
+ json_response = @network_services_interface.get_server(id.to_i)
187
+ return json_response['networkServer']
188
+ rescue RestClient::Exception => e
189
+ if e.response && e.response.code == 404
190
+ print_red_alert "Network Service not found by id #{id}"
191
+ return nil
192
+ else
193
+ raise e
194
+ end
195
+ end
196
+ end
197
+
139
198
  end
@@ -594,11 +594,15 @@ EOT
594
594
  type_id = nil
595
595
  workflow_context = nil
596
596
  workflow_target = nil
597
+ quantity = nil
597
598
  optparse = Morpheus::Cli::OptionParser.new do |opts|
598
599
  opts.banner = subcommand_usage("[type] [options]")
599
600
  opts.on('-t', '--type TYPE', String, "Catalog Item Type Name or ID") do |val|
600
601
  type_id = val.to_s
601
602
  end
603
+ opts.on('--quantity QUANTITY', String, "Quantity for this catalog item. Will be overridden to 1 if quantity not allowed.") do |val|
604
+ quantity = val.to_s
605
+ end
602
606
  opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips adding the item.") do
603
607
  options[:validate_only] = true
604
608
  end
@@ -648,6 +652,16 @@ EOT
648
652
  payload[add_item_object_key]['type'] = {'name' => catalog_item_type['name']}
649
653
  #payload[add_item_object_key]['type'] = {'id' => catalog_item_type['id']}
650
654
 
655
+ if quantity
656
+ payload[add_item_object_key].deep_merge!({'quantity' => quantity})
657
+ else
658
+ if catalog_item_type['allowQuantity']
659
+ quantity_option_type = {'fieldName' => 'quantity', 'fieldLabel' => 'Quantity', 'type' => 'number', 'defaultValue' => 1, 'required' => true, 'displayOrder' => 1}
660
+ quantity_prompt = Morpheus::Cli::OptionTypes.prompt( [quantity_option_type], options[:options], @api_client, options[:params])['quantity']
661
+ payload[add_item_object_key].deep_merge!({'quantity' => quantity_prompt})
662
+ end
663
+ end
664
+
651
665
  # this is silly, need to load by id to get optionTypes
652
666
  # maybe do ?name=foo&includeOptionTypes=true
653
667
  if catalog_item_type['optionTypes'].nil?
@@ -926,11 +940,15 @@ EOT
926
940
  type_id = nil
927
941
  workflow_context = nil
928
942
  workflow_target = nil
943
+ quantity = nil
929
944
  optparse = Morpheus::Cli::OptionParser.new do |opts|
930
945
  opts.banner = subcommand_usage("[type] [options]")
931
946
  opts.on('-t', '--type TYPE', String, "Catalog Item Type Name or ID") do |val|
932
947
  type_id = val.to_s
933
948
  end
949
+ opts.on('--quantity QUANTITY', String, "Quantity for this catalog item. Will be overridden to 1 if quantity not allowed.") do |val|
950
+ quantity = val.to_s
951
+ end
934
952
  opts.on('--validate','--validate', "Validate Only. Validates the configuration and skips creating the order.") do
935
953
  options[:validate_only] = true
936
954
  end
@@ -991,6 +1009,17 @@ EOT
991
1009
  item_payload['type'] = {'name' => catalog_item_type['name']}
992
1010
  #payload[add_item_object_key]['type'] = {'id' => catalog_item_type['id']}
993
1011
 
1012
+ if quantity
1013
+ item_payload.deep_merge!({'quantity' => quantity})
1014
+ else
1015
+ if catalog_item_type['allowQuantity']
1016
+ quantity_option_type = {'fieldName' => 'quantity', 'fieldLabel' => 'Quantity', 'type' => 'number', 'defaultValue' => 1, 'required' => true, 'displayOrder' => 1}
1017
+ quantity_prompt = Morpheus::Cli::OptionTypes.prompt( [quantity_option_type], options[:options], @api_client, options[:params])['quantity']
1018
+ item_payload.deep_merge!({'quantity' => quantity_prompt})
1019
+ end
1020
+ end
1021
+
1022
+
994
1023
  # this is silly, need to load by id to get optionTypes
995
1024
  # maybe do ?name=foo&includeOptionTypes=true
996
1025
  if catalog_item_type['optionTypes'].nil?
@@ -1200,6 +1229,7 @@ EOT
1200
1229
  # "Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
1201
1230
  # "Enabled" => lambda {|it| format_boolean(it['enabled']) },
1202
1231
  "Featured" => lambda {|it| format_boolean(it['featured']) },
1232
+ "Allow Quantity" => lambda {|it| format_boolean(it['allowQuantity']) },
1203
1233
  #"Config" => lambda {|it| it['config'] },
1204
1234
  # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1205
1235
  # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
@@ -1408,7 +1438,7 @@ EOT
1408
1438
  {"ID" => lambda {|it| it['id'] } },
1409
1439
  #{"NAME" => lambda {|it| it['name'] } },
1410
1440
  {"Type" => lambda {|it| it['type']['name'] rescue '' } },
1411
- #{"Qty" => lambda {|it| it['quantity'] } },
1441
+ {"Qty" => lambda {|it| it['quantity'] } },
1412
1442
  {"Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
1413
1443
  {"Status" => lambda {|it|
1414
1444
  status_string = format_catalog_item_status(it)
@@ -1438,7 +1468,7 @@ EOT
1438
1468
  {"ID" => lambda {|it| it['id'] } },
1439
1469
  #{"NAME" => lambda {|it| it['name'] } },
1440
1470
  {"TYPE" => lambda {|it| it['type']['name'] rescue '' } },
1441
- #{"QTY" => lambda {|it| it['quantity'] } },
1471
+ {"QTY" => lambda {|it| it['quantity'] } },
1442
1472
  {"PRICE" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" } },
1443
1473
  {"STATUS" => lambda {|it|
1444
1474
  status_string = format_catalog_item_status(it)
@@ -171,13 +171,21 @@ class Morpheus::Cli::ServicePlanCommand
171
171
  ranges = (service_plan['config'] ? service_plan['config']['ranges'] : nil) || {}
172
172
 
173
173
  if (ranges['minStorage'] && ranges['minStorage'] != '') || (ranges['maxStorage'] && ranges['maxStorage'] != '')
174
- description_cols['Custom Storage Range'] = lambda {|it|
174
+ description_cols['Custom Total Storage Range'] = lambda {|it|
175
175
  get_range(
176
176
  ranges['minStorage'] && ranges['minStorage'] != '' ? "#{ranges['minStorage']} #{(it['config'] && it['config']['storageSizeType'] ? it['config']['storageSizeType'] : 'GB').upcase}" : nil,
177
177
  ranges['maxStorage'] && ranges['maxStorage'] != '' ? "#{ranges['maxStorage']} #{(it['config'] && it['config']['storageSizeType'] ? it['config']['storageSizeType'] : 'GB').upcase}" : nil,
178
178
  )
179
179
  }
180
180
  end
181
+ if (ranges['minPerDiskSize'] && ranges['minPerDiskSize'] != '') || (ranges['maxPerDiskSize'] && ranges['maxPerDiskSize'] != '')
182
+ description_cols['Custom Per Disk Range'] = lambda {|it|
183
+ get_range(
184
+ ranges['minPerDiskSize'] && ranges['minPerDiskSize'] != '' ? "#{ranges['minPerDiskSize']} GB" : nil,
185
+ ranges['maxPerDiskSize'] && ranges['maxPerDiskSize'] != '' ? "#{ranges['maxPerDiskSize']} GB" : nil
186
+ )
187
+ }
188
+ end
181
189
  if (ranges['minMemory'] && ranges['minMemory'] != '') || (ranges['maxMemory'] && ranges['maxMemory'] != '')
182
190
  description_cols['Custom Memory Range'] = lambda {|it|
183
191
  get_range(
@@ -264,6 +272,9 @@ class Morpheus::Cli::ServicePlanCommand
264
272
  opts.on('--disks [NUMBER]', Integer, "Max disks allowed" ) do |val|
265
273
  params['maxDisks'] = val.to_i || 1
266
274
  end
275
+ opts.on('--cores-per-socket [NUMBER]', Integer, "Cores Per Socket") do |val|
276
+ params['coresPerSocket'] = val.to_i || 1
277
+ end
267
278
  opts.on('--custom-cores [on|off]', String, "Can be used to enable / disable customizable cores. Default is on") do |val|
268
279
  params['customCores'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
269
280
  end
@@ -285,17 +296,17 @@ class Morpheus::Cli::ServicePlanCommand
285
296
  opts.on('--price-sets [LIST]', Array, 'Price set(s), comma separated list of price set IDs') do |list|
286
297
  params['priceSets'] = list.collect {|it| it.to_s.strip.empty? || !it.to_i ? nil : it.to_s.strip}.compact.uniq.collect {|it| {'id' => it.to_i}}
287
298
  end
288
- opts.on('--min-storage NUMBER', String, "Min storage. Assumes GB unless optional modifier specified, ex: 512MB") do |val|
289
- # Storage doesn't get converted to bytes
290
- bytes = parse_bytes_param(val, '--min-storage', 'GB', true)
291
- ((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = bytes[:number]
292
- (params['config'] ||= {})['storageSizeType'] = bytes[:unit].downcase
299
+ opts.on('--min-storage NUMBER', String, "Min total storage in GB.") do |val|
300
+ ((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = val.to_i
293
301
  end
294
- opts.on('--max-storage NUMBER', String, "Max storage. Assumes GB unless optional modifier specified, ex: 512MB") do |val|
295
- # Storage doesn't get converted to bytes
296
- bytes = parse_bytes_param(val.to_s, '--max-storage', 'GB', true)
297
- ((params['config'] ||= {})['ranges'] ||= {})['maxStorage'] = bytes[:number]
298
- (params['config'] ||= {})['storageSizeType'] = bytes[:unit].downcase
302
+ opts.on('--max-storage NUMBER', String, "Max total storage in GB.") do |val|
303
+ ((params['config'] ||= {})['ranges'] ||= {})['maxStorage'] = val.to_i
304
+ end
305
+ opts.on('--min-per-disk-size NUMBER', String, "Min per disk size in GB.") do |val|
306
+ ((params['config'] ||= {})['ranges'] ||= {})['minPerDiskSize'] = val.to_i
307
+ end
308
+ opts.on('--max-per-disk-size NUMBER', String, "Max per disk size in GB.") do |val|
309
+ ((params['config'] ||= {})['ranges'] ||= {})['maxPerDiskSize'] = val.to_i
299
310
  end
300
311
  opts.on('--min-memory NUMBER', String, "Min memory. Assumes MB unless optional modifier specified, ex: 1GB") do |val|
301
312
  # Memory does get converted to bytes
@@ -315,6 +326,18 @@ class Morpheus::Cli::ServicePlanCommand
315
326
  opts.on('--max-cores NUMBER', String, "Max cores") do |val|
316
327
  ((params['config'] ||= {})['ranges'] ||= {})['maxCores'] = val.to_i
317
328
  end
329
+ opts.on('--min-sockets NUMBER', String, "Min sockets") do |val|
330
+ ((params['config'] ||= {})['ranges'] ||= {})['minSockets'] = val.to_i
331
+ end
332
+ opts.on('--max-sockets NUMBER', String, "Max sockets") do |val|
333
+ ((params['config'] ||= {})['ranges'] ||= {})['maxSockets'] = val.to_i
334
+ end
335
+ opts.on('--min-cores-per-socket NUMBER', String, "Min cores per socket") do |val|
336
+ ((params['config'] ||= {})['ranges'] ||= {})['minCoresPerSocket'] = val.to_i
337
+ end
338
+ opts.on('--max-cores-per-socket NUMBER', String, "Max cores per socket") do |val|
339
+ ((params['config'] ||= {})['ranges'] ||= {})['maxCoresPerSocket'] = val.to_i
340
+ end
318
341
  add_perms_options(opts, options, ['plans', 'groupDefaults'])
319
342
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
320
343
  opts.footer = "Create service plan"
@@ -396,13 +419,41 @@ class Morpheus::Cli::ServicePlanCommand
396
419
  true
397
420
  )
398
421
  params['maxMemory'] = bytes[:bytes]
399
- # (params['config'] ||= {})['memorySizeType'] = bytes[:unit].downcase
400
422
  rescue
401
423
  print "Invalid Value... Please try again.\n"
402
424
  end
425
+ params['customMaxMemory'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'customMaxMemory', 'type' => 'checkbox', 'fieldLabel' => 'Custom Max Memory', 'required' => false, 'description' => 'Custom Max Memory', 'defaultValue' => false}],options[:options],@api_client,{}, options[:no_prompt])['customMaxMemory']
403
426
  end
404
427
  end
405
428
 
429
+ # add'n options
430
+ addn_options = [
431
+ {'fieldName' => 'maxCores', 'fieldLabel' => 'Core Count', 'type' => 'number', 'required' => true, 'defaultValue' => 1, 'displayOrder' => 1},
432
+ {'fieldName' => 'customCores', 'fieldLabel' => 'Custom Cores', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 2},
433
+ {'fieldName' => 'coresPerSocket', 'fieldLabel' => 'Cores Per Socket', 'type' => 'number', 'required' => true, 'defaultValue' => 1, 'displayOrder' => 3},
434
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minStorage', 'fieldLabel' => 'Min Total Storage (GB)', 'type' => 'number', 'displayOrder' => 1},
435
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxStorage', 'fieldLabel' => 'Max Total Storage (GB)', 'type' => 'number', 'displayOrder' => 2},
436
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minPerDiskSize', 'fieldLabel' => 'Min Per Disk Size (GB)', 'type' => 'number', 'displayOrder' => 3},
437
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxPerDiskSize', 'fieldLabel' => 'Max Per Disk Size (GB)', 'type' => 'number', 'displayOrder' => 4},
438
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minMemory', 'fieldLabel' => 'Min Memory (GB)', 'type' => 'number', 'displayOrder' => 5},
439
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxMemory', 'fieldLabel' => 'Max Memory (GB)', 'type' => 'number', 'displayOrder' => 6},
440
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minCores', 'fieldLabel' => 'Min Cores', 'type' => 'number', 'displayOrder' => 7},
441
+ {'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxCores', 'fieldLabel' => 'Max Cores', 'type' => 'number', 'displayOrder' => 8}
442
+ ]
443
+
444
+ if provision_type['hasSocketRange']
445
+ addn_options.push({'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minSockets', 'fieldLabel' => 'Min Sockets', 'type' => 'number', 'displayOrder' => 9})
446
+ addn_options.push({'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxSockets', 'fieldLabel' => 'Max Sockets', 'type' => 'number', 'displayOrder' => 10})
447
+ end
448
+
449
+ if provision_type['hasCoresPerSocketRange']
450
+ addn_options.push({'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minCoresPerSocket', 'fieldLabel' => 'Min Cores Per Socket', 'type' => 'number', 'displayOrder' => 11})
451
+ addn_options.push({'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxCoresPerSocket', 'fieldLabel' => 'Max Cores Per Socket', 'type' => 'number', 'displayOrder' => 12})
452
+ end
453
+
454
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(addn_options, options[:options], @api_client, params)
455
+ params.deep_merge!(v_prompt)
456
+
406
457
  # price sets
407
458
  if params['priceSets'].nil? && !options[:no_prompt]
408
459
  price_sets = []
@@ -517,17 +568,17 @@ class Morpheus::Cli::ServicePlanCommand
517
568
  opts.on('--price-sets [LIST]', Array, 'Price set(s), comma separated list of price set IDs') do |list|
518
569
  params['priceSets'] = list.collect {|it| it.to_s.strip.empty? || !it.to_i ? nil : it.to_s.strip}.compact.uniq.collect {|it| {'id' => it.to_i}}
519
570
  end
520
- opts.on('--min-storage NUMBER', String, "Min storage. Assumes GB unless optional modifier specified, ex: 512MB") do |val|
521
- # Storage doesn't get converted to bytes
522
- bytes = parse_bytes_param(val, '--min-storage', 'GB')
523
- ((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = bytes[:number]
524
- (params['config'] ||= {})['storageSizeType'] = bytes[:unit].downcase
571
+ opts.on('--min-storage NUMBER', String, "Min total storage in GB.") do |val|
572
+ ((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = val.to_i
525
573
  end
526
- opts.on('--max-storage NUMBER', String, "Max storage. Assumes GB unless optional modifier specified, ex: 512MB") do |val|
527
- # Storage doesn't get converted to bytes
528
- bytes = parse_bytes_param(val, '--max-storage', 'GB', true)
529
- ((params['config'] ||= {})['ranges'] ||= {})['maxStorage'] = bytes[:number]
530
- (params['config'] ||= {})['storageSizeType'] = bytes[:unit].downcase
574
+ opts.on('--max-storage NUMBER', String, "Max total storage in GB.") do |val|
575
+ ((params['config'] ||= {})['ranges'] ||= {})['maxStorage'] = val.to_i
576
+ end
577
+ opts.on('--min-per-disk-size NUMBER', String, "Min per disk size in GB.") do |val|
578
+ ((params['config'] ||= {})['ranges'] ||= {})['minPerDiskSize'] = val.to_i
579
+ end
580
+ opts.on('--max-per-disk-size NUMBER', String, "Max per disk size in GB.") do |val|
581
+ ((params['config'] ||= {})['ranges'] ||= {})['maxPerDiskSize'] = val.to_i
531
582
  end
532
583
  opts.on('--min-memory NUMBER', String, "Min memory. Assumes MB unless optional modifier specified, ex: 1GB") do |val|
533
584
  # Memory does get converted to bytes
@@ -546,6 +597,18 @@ class Morpheus::Cli::ServicePlanCommand
546
597
  end
547
598
  opts.on('--max-cores NUMBER', String, "Max cores") do |val|
548
599
  ((params['config'] ||= {})['ranges'] ||= {})['maxCores'] = val.to_i
600
+ end
601
+ opts.on('--min-sockets NUMBER', String, "Min sockets") do |val|
602
+ ((params['config'] ||= {})['ranges'] ||= {})['minSockets'] = val.to_i
603
+ end
604
+ opts.on('--max-sockets NUMBER', String, "Max sockets") do |val|
605
+ ((params['config'] ||= {})['ranges'] ||= {})['maxSockets'] = val.to_i
606
+ end
607
+ opts.on('--min-cores-per-socket NUMBER', String, "Min cores per socket") do |val|
608
+ ((params['config'] ||= {})['ranges'] ||= {})['minCoresPerSocket'] = val.to_i
609
+ end
610
+ opts.on('--max-cores-per-socket NUMBER', String, "Max cores per socket") do |val|
611
+ ((params['config'] ||= {})['ranges'] ||= {})['maxCoresPerSocket'] = val.to_i
549
612
  end
550
613
  add_perms_options(opts, options, ['plans', 'groupDefaults'])
551
614
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
@@ -359,7 +359,7 @@ class Morpheus::Cli::Shell
359
359
  end
360
360
  out << "See the available commands below.\n"
361
361
 
362
- out << "\nCommands:"
362
+ out << "\nCommands:\n"
363
363
  # commands = @morpheus_commands + @shell_commands
364
364
  # @morpheus_commands.sort.each {|cmd|
365
365
  # out << "\t#{cmd.to_s}\n"
@@ -442,7 +442,7 @@ class Morpheus::Cli::Tasks
442
442
  # Result Type
443
443
  if options[:options]['resultType']
444
444
  payload['task']['resultType'] = options[:options]['resultType']
445
- else
445
+ elsif task_type['hasResults']
446
446
  result_types_dropdown = [{"name" => "Value", "value" => "value"}, {"name" => "Exit Code", "value" => "exitCode"}, {"name" => "Key Value", "value" => "keyValue"}, {"name" => "JSON", "value" => "json"}]
447
447
  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'resultType', 'fieldLabel' => 'Result Type', 'type' => 'select', 'selectOptions' => result_types_dropdown}], options[:options], @api_client)
448
448
  payload['task']['resultType'] = v_prompt['resultType'] unless v_prompt['resultType'].to_s.empty?
@@ -471,6 +471,7 @@ class Morpheus::Cli::Tasks
471
471
  end
472
472
  end
473
473
  end
474
+ process_special_task_option_typeaheads(task_option_types)
474
475
  # inject file_params into options for file-content prompt
475
476
  # or into taskOptions.script for types not yet using file-content
476
477
  unless file_params.empty?
@@ -859,38 +860,99 @@ class Morpheus::Cli::Tasks
859
860
  target_type = nil
860
861
  instance_ids = []
861
862
  instances = []
863
+ instance_label = nil
862
864
  server_ids = []
863
865
  servers = []
864
- default_refresh_interval = 10
866
+ server_label = nil
867
+ default_refresh_interval = 5
868
+ all_target_types = ['appliance', 'instance', 'instance-label', 'server', 'server-label']
865
869
  optparse = Morpheus::Cli::OptionParser.new do |opts|
866
- opts.banner = subcommand_usage("[task] --instance [instance] [options]")
867
- opts.on('--instance INSTANCE', String, "Instance name or id to execute the task on. This option can be passed more than once.") do |val|
870
+ opts.banner = subcommand_usage("[task] [options]")
871
+ opts.on('--context-type VALUE', String, "Context Type, #{ored_list(all_target_types)}") do |val|
872
+ val = val.downcase
873
+ val = 'appliance' if val == 'none'
874
+ if target_type && target_type != val
875
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
876
+ end
877
+ if !all_target_types.include?(val)
878
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
879
+ end
880
+ target_type = val
881
+ end
882
+ opts.on('--target-type VALUE', String, "alias for context-type") do |val|
883
+ val = val.downcase
884
+ val = 'appliance' if val == 'none'
885
+ if target_type && target_type != val
886
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
887
+ end
888
+ if !all_target_types.include?(val)
889
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
890
+ end
891
+ target_type = val
892
+ end
893
+ opts.add_hidden_option('--target-type')
894
+ opts.on('--instance INSTANCE', String, "Instance name or id to target for execution. This option can be passed more than once.") do |val|
895
+ if target_type && target_type != 'instance'
896
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
897
+ end
868
898
  target_type = 'instance'
869
899
  instance_ids << val
870
900
  end
871
- opts.on('--instances [LIST]', Array, "Instances, comma separated list of instance names or IDs.") do |list|
901
+ opts.on('--instances LIST', Array, "Instances, comma separated list of instance names or IDs.") do |list|
902
+ if target_type && target_type != 'instance'
903
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
904
+ end
872
905
  target_type = 'instance'
873
906
  instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
874
907
  end
875
- opts.on('--host HOST', String, "Host name or id to execute the task on. This option can be passed more than once.") do |val|
908
+ opts.on('--instance-label LABEL', String, "Instance Label") do |val|
909
+ if target_type && target_type != 'instance-label'
910
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
911
+ end
912
+ target_type = 'instance-label'
913
+ instance_label = val
914
+ end
915
+ opts.on('--server SERVER', String, "Server name or id to target for execution. This option can be passed more than once.") do |val|
916
+ if target_type && target_type != 'server'
917
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
918
+ end
876
919
  target_type = 'server'
877
920
  server_ids << val
878
921
  end
879
- opts.on('--hosts [LIST]', Array, "Hosts, comma separated list of host names or IDs.") do |list|
922
+ opts.on('--servers LIST', Array, "Servers, comma separated list of host names or IDs.") do |list|
923
+ if target_type && target_type != 'server'
924
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
925
+ end
880
926
  target_type = 'server'
881
927
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
882
928
  end
883
- opts.on('--server HOST', String, "alias for --host") do |val|
929
+ opts.on('--server-label LABEL', String, "Server Label") do |val|
930
+ if target_type && target_type != 'server-label'
931
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
932
+ end
933
+ target_type = 'server-label'
934
+ server_label = val
935
+ end
936
+ opts.on('--host HOST', String, "alias for --server") do |val|
937
+ if target_type && target_type != 'server'
938
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
939
+ end
884
940
  target_type = 'server'
885
941
  server_ids << val
886
942
  end
887
- opts.on('--servers [LIST]', Array, "alias for --hosts") do |list|
943
+ opts.add_hidden_option('--host')
944
+ opts.on('--hosts HOSTS', Array, "alias for --servers") do |list|
945
+ if target_type && target_type != 'server'
946
+ raise ::OptionParser::InvalidOption.new("The --hosts option cannot be combined with another context (#{target_type})")
947
+ end
888
948
  target_type = 'server'
889
949
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
890
950
  end
891
- opts.add_hidden_option('--server')
892
- opts.add_hidden_option('--servers')
951
+ opts.add_hidden_option('--hosts')
893
952
  opts.on('-a', '--appliance', "Execute on the appliance, the target is the appliance itself.") do
953
+ if target_type && target_type != 'appliance'
954
+ raise ::OptionParser::InvalidOption.new("The --appliance option cannot be combined with another context (#{target_type})")
955
+ end
894
956
  target_type = 'appliance'
895
957
  end
896
958
  opts.on('--config [TEXT]', String, "Custom config") do |val|
@@ -921,46 +983,59 @@ class Morpheus::Cli::Tasks
921
983
  payload = options[:payload]
922
984
  payload.deep_merge!({'job' => passed_options}) unless passed_options.empty?
923
985
  else
924
- # always parse instances and/or hosts
925
- if instance_ids.size > 0 && server_ids.size > 0
926
- raise_command_error "Pass --instance or --host, not both.\n#{optparse}"
927
- elsif instance_ids.size > 0
986
+ # prompt for target type and target
987
+ if target_type.nil?
988
+ # todo: Need api to fetch available Context Types for taskId/workflowId
989
+ available_target_types = get_available_contexts_for_task(task)
990
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
991
+ if !available_target_types.empty?
992
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
993
+ target_type = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'context-type', 'fieldName' => 'targetType', 'fieldLabel' => 'Context Type', 'type' => 'select', 'selectOptions' => available_target_types, 'defaultValue' => default_target_type, 'required' => true, 'description' => 'Context Type determines the type of target(s) for the execution'}], options[:options], @api_client)['targetType']
994
+ end
995
+ end
996
+ if target_type
997
+ params['targetType'] = target_type
998
+ end
999
+ if target_type == 'instance'
1000
+ if instance_ids.empty?
1001
+ instance_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instances', 'fieldName' => 'instances', 'fieldLabel' => 'Instance(s)', 'type' => 'text', 'required' => true, 'description' => 'Instances, comma separated list of instance names or IDs.'}], options[:options], @api_client)['instances']
1002
+ instance_ids = parse_array(instance_ids_value)
1003
+ end
928
1004
  instance_ids.each do |instance_id|
929
1005
  instance = find_instance_by_name_or_id(instance_id)
930
1006
  return 1 if instance.nil?
931
1007
  instances << instance
932
1008
  end
933
1009
  params['instances'] = instances.collect {|it| it['id'] }
934
- elsif server_ids.size > 0
1010
+ elsif target_type == 'instance-label'
1011
+ if instance_label.nil?
1012
+ instance_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instance-label', 'fieldName' => 'instanceLabel', 'fieldLabel' => 'Instance Label', 'type' => 'text', 'required' => true, 'description' => 'Instance Label'}], options[:options], @api_client)['instanceLabel']
1013
+ end
1014
+ # params['config'] ||= {}
1015
+ # params['config']['instanceLabel'] = instance_label
1016
+ params['instanceLabel'] = instance_label
1017
+ elsif target_type == 'server'
1018
+ if server_ids.empty?
1019
+ server_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'servers', 'fieldName' => 'servers', 'fieldLabel' => 'Server(s)', 'type' => 'text', 'required' => true, 'description' => 'Servers, comma separated list of server names or IDs.'}], options[:options], @api_client)['servers']
1020
+ server_ids = parse_array(server_ids_value)
1021
+ end
935
1022
  server_ids.each do |server_id|
936
1023
  server = find_server_by_name_or_id(server_id)
937
1024
  return 1 if server.nil?
938
1025
  servers << server
939
1026
  end
940
1027
  params['servers'] = servers.collect {|it| it['id'] }
941
- end
942
- # validate requires inputs based on task executeTarget
943
- if task['executeTarget'] == 'resource'
944
- if instance_ids.empty? && server_ids.empty?
945
- # todo: prompt for Context: None,Instance,Server and then Instance(s) or Server(s)
946
- raise_command_error "missing required option: --instance or --host\n#{optparse}"
1028
+ elsif target_type == 'server-label'
1029
+ if server_label.nil?
1030
+ server_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'server-label', 'fieldName' => 'serverLabel', 'fieldLabel' => 'Server Label', 'type' => 'text', 'required' => true, 'description' => 'Server Label'}], options[:options], @api_client)['serverLabel']
947
1031
  end
948
- elsif task['executeTarget'] == 'local'
949
- # no targetType required for local
950
- elsif task['executeTarget'] == 'remote'
951
- # not sure about this one
952
- else
953
- # unknown executeTarget
1032
+ # params['config'] ||= {}
1033
+ # params['config']['serverLabel'] = server_label
1034
+ params['serverLabel'] = server_label
954
1035
  end
955
-
956
-
957
-
958
1036
  # todo: prompt to task optionTypes for customOptions
959
1037
  if task['optionTypes']
960
1038
 
961
- end
962
- if target_type
963
- params['targetType'] = target_type
964
1039
  end
965
1040
  job_payload = {}
966
1041
  job_payload.deep_merge!(params)
@@ -1293,4 +1368,24 @@ class Morpheus::Cli::Tasks
1293
1368
  end
1294
1369
  end
1295
1370
 
1371
+ def process_special_task_option_typeaheads(option_types)
1372
+ # massage special task typeaheads options
1373
+ # this makes us all sad
1374
+ option_types.each do |option_type|
1375
+ if option_type['type'] == 'typeahead'
1376
+ if ['operationalWorkflowName','containerScript','containerTemplate'].include?(option_type['code'])
1377
+ option_type.deep_merge!({'config' => {'valueField' => 'name'}})
1378
+ end
1379
+ elsif option_type['type'] == 'hidden'
1380
+ if ['operationalWorkflowId','containerScriptId','containerTemplateId'].include?(option_type['code'])
1381
+ option_type['processValue'] = lambda {|val|
1382
+ if val.to_s.empty?
1383
+ selected_option = Morpheus::Cli::OptionTypes.get_last_select()
1384
+ selected_option ? selected_option['value'] : nil
1385
+ end
1386
+ }
1387
+ end
1388
+ end
1389
+ end
1390
+ end
1296
1391
  end
@@ -550,40 +550,101 @@ class Morpheus::Cli::Workflows
550
550
  target_type = nil
551
551
  instance_ids = []
552
552
  instances = []
553
+ instance_label = nil
553
554
  server_ids = []
554
555
  servers = []
555
- default_refresh_interval = 10
556
+ server_label = nil
557
+ default_refresh_interval = 5
558
+ all_target_types = ['appliance', 'instance', 'instance-label', 'server', 'server-label']
556
559
  optparse = Morpheus::Cli::OptionParser.new do |opts|
557
- opts.banner = subcommand_usage("[workflow] --instance [instance] [options]")
558
- opts.on('--instance INSTANCE', String, "Instance name or id to execute the workflow on. This option can be passed more than once.") do |val|
560
+ opts.banner = subcommand_usage("[workflow] [options]")
561
+ opts.on('--context-type VALUE', String, "Context Type, #{ored_list(all_target_types)}") do |val|
562
+ val = val.downcase
563
+ val = 'appliance' if val == 'none'
564
+ if target_type && target_type != val
565
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
566
+ end
567
+ if !all_target_types.include?(val)
568
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
569
+ end
570
+ target_type = val
571
+ end
572
+ opts.on('--target-type VALUE', String, "alias for context-type") do |val|
573
+ val = val.downcase
574
+ val = 'appliance' if val == 'none'
575
+ if target_type && target_type != val
576
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
577
+ end
578
+ if !all_target_types.include?(val)
579
+ raise ::OptionParser::InvalidOption.new("'#{val}' is invalid. It must be one of the following: instance, instance-label, server, server-label or appliance")
580
+ end
581
+ target_type = val
582
+ end
583
+ opts.add_hidden_option('--target-type')
584
+ opts.on('--instance INSTANCE', String, "Instance name or id to target for execution. This option can be passed more than once.") do |val|
585
+ if target_type && target_type != 'instance'
586
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
587
+ end
559
588
  target_type = 'instance'
560
589
  instance_ids << val
561
590
  end
562
- opts.on('--instances [LIST]', Array, "Instances, comma separated list of instance names or IDs.") do |list|
591
+ opts.on('--instances LIST', Array, "Instances, comma separated list of instance names or IDs.") do |list|
592
+ if target_type && target_type != 'instance'
593
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
594
+ end
563
595
  target_type = 'instance'
564
596
  instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
565
597
  end
566
- opts.on('--host HOST', String, "Host name or id to execute the workflow on. This option can be passed more than once.") do |val|
598
+ opts.on('--instance-label LABEL', String, "Instance Label") do |val|
599
+ if target_type && target_type != 'instance-label'
600
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
601
+ end
602
+ target_type = 'instance-label'
603
+ instance_label = val
604
+ end
605
+ opts.on('--server SERVER', String, "Server name or id to target for execution. This option can be passed more than once.") do |val|
606
+ if target_type && target_type != 'server'
607
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
608
+ end
567
609
  target_type = 'server'
568
610
  server_ids << val
569
611
  end
570
- opts.on('--hosts [LIST]', Array, "Hosts, comma separated list of host names or IDs.") do |list|
612
+ opts.on('--servers LIST', Array, "Servers, comma separated list of host names or IDs.") do |list|
613
+ if target_type && target_type != 'server'
614
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
615
+ end
571
616
  target_type = 'server'
572
617
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
573
618
  end
574
- opts.on('--server HOST', String, "alias for --host") do |val|
619
+ opts.on('--server-label LABEL', String, "Server Label") do |val|
620
+ if target_type && target_type != 'server-label'
621
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
622
+ end
623
+ target_type = 'server-label'
624
+ server_label = val
625
+ end
626
+ opts.on('--host HOST', String, "alias for --server") do |val|
627
+ if target_type && target_type != 'server'
628
+ raise ::OptionParser::InvalidOption.new("cannot be combined with another context (#{target_type})")
629
+ end
575
630
  target_type = 'server'
576
631
  server_ids << val
577
632
  end
578
- opts.on('--servers [LIST]', Array, "alias for --hosts") do |list|
633
+ opts.add_hidden_option('--host')
634
+ opts.on('--hosts HOSTS', Array, "alias for --servers") do |list|
635
+ if target_type && target_type != 'server'
636
+ raise ::OptionParser::InvalidOption.new("The --hosts option cannot be combined with another context (#{target_type})")
637
+ end
579
638
  target_type = 'server'
580
639
  server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
581
640
  end
641
+ opts.add_hidden_option('--hosts')
582
642
  opts.on('-a', '--appliance', "Execute on the appliance, the target is the appliance itself.") do
643
+ if target_type && target_type != 'appliance'
644
+ raise ::OptionParser::InvalidOption.new("The --appliance option cannot be combined with another context (#{target_type})")
645
+ end
583
646
  target_type = 'appliance'
584
647
  end
585
- opts.add_hidden_option('--server')
586
- opts.add_hidden_option('--servers')
587
648
  opts.on('--config [TEXT]', String, "Custom config") do |val|
588
649
  params['customConfig'] = val.to_s
589
650
  end
@@ -611,27 +672,55 @@ class Morpheus::Cli::Workflows
611
672
  payload = options[:payload]
612
673
  payload.deep_merge!({'job' => passed_options}) unless passed_options.empty?
613
674
  else
614
- if instance_ids.size > 0 && server_ids.size > 0
615
- raise_command_error "Pass --instance or --host, not both.\n#{optparse}"
616
- elsif instance_ids.size > 0
675
+ # prompt for target type and target
676
+ if target_type.nil?
677
+ # todo: Need api to fetch available Context Types for taskId/workflowId
678
+ available_target_types = get_available_contexts_for_workflow(workflow)
679
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
680
+ if !available_target_types.empty?
681
+ default_target_type = available_target_types.first ? available_target_types.first['name'] : nil
682
+ target_type = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'context-type', 'fieldName' => 'targetType', 'fieldLabel' => 'Context Type', 'type' => 'select', 'selectOptions' => available_target_types, 'defaultValue' => default_target_type, 'required' => true, 'description' => 'Context Type determines the type of target(s) for the execution'}], options[:options], @api_client)['targetType']
683
+ end
684
+ end
685
+ if target_type
686
+ params['targetType'] = target_type
687
+ end
688
+ if target_type == 'instance'
689
+ if instance_ids.empty?
690
+ instance_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instances', 'fieldName' => 'instances', 'fieldLabel' => 'Instance(s)', 'type' => 'text', 'required' => true, 'description' => 'Instances, comma separated list of instance names or IDs.'}], options[:options], @api_client)['instances']
691
+ instance_ids = parse_array(instance_ids_value)
692
+ end
617
693
  instance_ids.each do |instance_id|
618
694
  instance = find_instance_by_name_or_id(instance_id)
619
695
  return 1 if instance.nil?
620
696
  instances << instance
621
697
  end
622
698
  params['instances'] = instances.collect {|it| it['id'] }
623
- elsif server_ids.size > 0
699
+ elsif target_type == 'instance-label'
700
+ if instance_label.nil?
701
+ instance_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'instance-label', 'fieldName' => 'instanceLabel', 'fieldLabel' => 'Instance Label', 'type' => 'text', 'required' => true, 'description' => 'Instance Label'}], options[:options], @api_client)['instanceLabel']
702
+ end
703
+ # params['config'] ||= {}
704
+ # params['config']['instanceLabel'] = instance_label
705
+ params['instanceLabel'] = instance_label
706
+ elsif target_type == 'server'
707
+ if server_ids.empty?
708
+ server_ids_value = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'servers', 'fieldName' => 'servers', 'fieldLabel' => 'Server(s)', 'type' => 'text', 'required' => true, 'description' => 'Servers, comma separated list of server names or IDs.'}], options[:options], @api_client)['servers']
709
+ server_ids = parse_array(server_ids_value)
710
+ end
624
711
  server_ids.each do |server_id|
625
712
  server = find_server_by_name_or_id(server_id)
626
713
  return 1 if server.nil?
627
714
  servers << server
628
715
  end
629
716
  params['servers'] = servers.collect {|it| it['id'] }
630
- elsif target_type == 'appliance'
631
- # cool, run it locally.
632
- else
633
- # cool, run it locally.
634
- #raise_command_error "missing required option: --instance, --host or --appliance\n#{optparse}"
717
+ elsif target_type == 'server-label'
718
+ if server_label.nil?
719
+ server_label = Morpheus::Cli::OptionTypes.prompt([{'switch' => 'server-label', 'fieldName' => 'serverLabel', 'fieldLabel' => 'Server Label', 'type' => 'text', 'required' => true, 'description' => 'Server Label'}], options[:options], @api_client)['serverLabel']
720
+ end
721
+ # params['config'] ||= {}
722
+ # params['config']['serverLabel'] = server_label
723
+ params['serverLabel'] = server_label
635
724
  end
636
725
 
637
726
  # prompt to workflow optionTypes for customOptions
@@ -643,9 +732,6 @@ class Morpheus::Cli::Workflows
643
732
  }
644
733
  custom_options = Morpheus::Cli::OptionTypes.prompt(custom_option_types, options[:options], @api_client, {})
645
734
  end
646
- if target_type
647
- params['targetType'] = target_type
648
- end
649
735
  job_payload = {}
650
736
  job_payload.deep_merge!(params)
651
737
  passed_options.delete('customOptions')
@@ -41,8 +41,8 @@ module Morpheus::Cli::JobsHelper
41
41
  "Created By" => lambda {|it| it[:created_by]},
42
42
  "Duration" => lambda {|it| it[:duration]},
43
43
  "Status" => lambda {|it| it[:status]},
44
- "Error" => lambda {|it| options[:details] ? it[:error] : truncate_string(it[:error], 32) },
45
- "Output" => lambda {|it| options[:details] ? it[:output] : truncate_string(it[:output], 32) }
44
+ "Error" => lambda {|it| options[:details] ? it[:error].to_s.strip : truncate_string(it[:error], 32).to_s.strip.gsub("\n", ' ') },
45
+ "Output" => lambda {|it| options[:details] ? it[:output].to_s.strip : truncate_string(it[:output], 32).to_s.strip.gsub("\n", ' ') }
46
46
  }
47
47
  print as_pretty_table(events.collect {|it| get_process_event_data(it)}, event_columns.upcase_keys!, options)
48
48
  end
@@ -147,7 +147,7 @@ module Morpheus::Cli::JobsHelper
147
147
  # refresh execution request until it is finished
148
148
  # returns json response data of the last execution request when status reached 'completed' or 'failed'
149
149
  def wait_for_job_execution(job_execution_id, options={}, print_output = true)
150
- refresh_interval = 10
150
+ refresh_interval = 5
151
151
  if options[:refresh_interval].to_i > 0
152
152
  refresh_interval = options[:refresh_interval]
153
153
  end
@@ -168,5 +168,32 @@ module Morpheus::Cli::JobsHelper
168
168
  end
169
169
 
170
170
 
171
+ def get_available_contexts_for_task(task)
172
+ #If task has target of resource, then CAN NOT run it local
173
+ targets = []
174
+ has_resource = task['executeTarget'] == 'resource'
175
+ if !has_resource
176
+ targets << {'name' => 'None', 'value' => 'appliance'}
177
+ end
178
+ targets << {'name' => 'Instance', 'value' => 'instance'}
179
+ targets << {'name' => 'Instance Label', 'value' => 'instance-label'}
180
+ targets << {'name' => 'Server', 'value' => 'server'}
181
+ targets << {'name' => 'Server Label', 'value' => 'server-label'}
182
+ return targets
183
+ end
184
+
185
+ def get_available_contexts_for_workflow(workflow)
186
+ #If any task has target of resource, then CAN NOT run it local
187
+ targets = []
188
+ has_resource = workflow['taskSetTasks'].find {|task| task['executeTarget'] == 'resource' }
189
+ if !has_resource
190
+ targets << {'name' => 'None', 'value' => 'appliance'}
191
+ end
192
+ targets << {'name' => 'Instance', 'value' => 'instance'}
193
+ targets << {'name' => 'Instance Label', 'value' => 'instance-label'}
194
+ targets << {'name' => 'Server', 'value' => 'server'}
195
+ targets << {'name' => 'Server Label', 'value' => 'server-label'}
196
+ return targets
197
+ end
171
198
 
172
199
  end
@@ -88,36 +88,12 @@ module Morpheus::Cli::ProcessesHelper
88
88
 
89
89
  # decolorize, remove newlines and truncate for table cell
90
90
  def format_process_error(process, max_length=20, return_color=cyan)
91
- #return max_length ? truncate_string(process['error'], max_length) : process['error']
92
- out = ""
93
- if process['error']
94
- # lines = process['error'].split("\n").collect {|line| reset + "#{line.to_s.strip}" }
95
- # lines = process['error'].split("\n").collect {|line| "#{line.to_s.strip}" }
96
- lines = [process['error']]
97
- out = lines.join(" ")
98
- if max_length
99
- out = truncate_string(out, max_length)
100
- end
101
- out << return_color if return_color
102
- end
103
- out
91
+ truncate_string(process['error'].to_s.strip.gsub("\n", " "), max_length)
104
92
  end
105
93
 
106
94
  # decolorize, remove newlines and truncate for table cell
107
95
  def format_process_output(process, max_length=20, return_color=cyan)
108
- return max_length ? truncate_string(process['output'], max_length) : process['output']
109
- out = ""
110
- if process['output']
111
- # lines = process['output'].split("\n").collect {|line| reset + "#{line.to_s.strip}" }
112
- # lines = process['error'].split("\n").collect {|line| "#{line.to_s.strip}" }
113
- lines = [process['output']]
114
- out = lines.join(" ")
115
- if max_length
116
- out = truncate_string(out, max_length)
117
- end
118
- out << return_color if return_color
119
- end
120
- out
96
+ truncate_string(process['output'].to_s.strip.gsub("\n", " "), max_length)
121
97
  end
122
98
 
123
99
  # format for either ETA/Duration
@@ -777,15 +777,22 @@ module Morpheus::Cli::ProvisioningHelper
777
777
  option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
778
778
 
779
779
  resource_pool_options = options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], layoutId: layout["id"]}.merge(service_plan.nil? ? {} : {planId: service_plan["id"]}))['data']
780
- resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
781
-
780
+ if options[:resource_pool]
781
+ resource_pool = resource_pool_options.find {|opt| opt['value'] == options[:resource_pool].to_s || opt['value'] == "pool-#{options[:resource_pool]}"}
782
+ end
783
+ pool_required = provision_type["zonePoolRequired"]
784
+ # Should pool_id have the pool-,poolGroup- prefix or not?
785
+ use_pool_prefix = resource_pool_options.find {|opt| opt['value'].to_s.include?("pool") }
782
786
  if resource_pool
783
- pool_id = resource_pool['id']
787
+ pool_id = resource_pool['id'] # id or value?
784
788
  else
785
789
  if options[:default_resource_pool]
786
790
  default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
787
791
  end
788
- resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
792
+ if use_pool_prefix && options[:options]['config'] && options[:options]['config']['resourcePoolId'] && !options[:options]['config']['resourcePoolId'].to_s.include?("pool")
793
+ options[:options]['config']['resourcePoolId'] = "pool-" + options[:options]['config']['resourcePoolId'].to_s
794
+ end
795
+ resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => pool_required, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
789
796
  resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
790
797
  resource_pool_prompt.deep_compact!
791
798
  payload.deep_merge!(resource_pool_prompt)
@@ -795,7 +802,7 @@ module Morpheus::Cli::ProvisioningHelper
795
802
  elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
796
803
  pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
797
804
  end
798
- resource_pool ||= resource_pool_options.find {|it| it['id'] == pool_id}
805
+ resource_pool ||= resource_pool_options.find {|it| it['value'].to_s == pool_id.to_s}
799
806
  end
800
807
  end
801
808
  end
@@ -582,6 +582,9 @@ module Morpheus
582
582
 
583
583
  if no_prompt
584
584
  if !value_found
585
+ if default_value == ""
586
+ default_value = nil
587
+ end
585
588
  if !default_value.nil? && !select_options.nil?
586
589
  matched_option = select_options.find {|it| it[value_field].to_s == default_value.to_s }
587
590
  if matched_option.nil?
@@ -814,7 +817,7 @@ module Morpheus
814
817
  api_params ||= {}
815
818
  api_params['query'] = query_value
816
819
  # skip refresh if you just hit enter
817
- if !query_value.empty?
820
+ if !query_value.empty? || (select_options.nil? || select_options.empty?)
818
821
  select_options = load_options(option_type, api_client, api_params, query_value)
819
822
  end
820
823
 
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "6.0.0"
4
+ VERSION = "6.0.2"
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 6.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-03-02 00:00:00.000000000 Z
14
+ date: 2023-04-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler