morpheus-cli 6.0.0 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/jobs_interface.rb +2 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +11 -9
- data/lib/morpheus/cli/commands/instances.rb +1 -1
- data/lib/morpheus/cli/commands/jobs_command.rb +50 -3
- data/lib/morpheus/cli/commands/service_catalog_command.rb +32 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +51 -22
- data/lib/morpheus/cli/commands/shell.rb +1 -1
- data/lib/morpheus/cli/commands/tasks.rb +129 -34
- data/lib/morpheus/cli/commands/workflows.rb +108 -22
- data/lib/morpheus/cli/mixins/jobs_helper.rb +30 -3
- data/lib/morpheus/cli/mixins/processes_helper.rb +2 -26
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -1
- data/lib/morpheus/cli/option_types.rb +1 -1
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4160be97bfb96acf0fe1091e9e8d6ecde617bd2aba547ef1cfab8a11d6134ecf
|
4
|
+
data.tar.gz: 5e0675e4e1061595e560e2395625e7a7546813e68e09a8237ccd33d92aeb948d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2992a310163d78082f7d748ca4ae50c673c32e7ae782497bb89f721135ed66509549c124290e9b4bd644cad2e3838c878331427ddd1090325f8946c7d30e731
|
7
|
+
data.tar.gz: 48ec07412e0cdcad359ea2dc050cc5017a9a39e368fb662e50b880628213fc4681b85da9cd5d8503ea7426be0fbac77b5e61d2dd8bc397ab13f0ce21695d2758
|
data/Dockerfile
CHANGED
@@ -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
|
@@ -1020,7 +1020,7 @@ EOT
|
|
1020
1020
|
end
|
1021
1021
|
|
1022
1022
|
def apply(args)
|
1023
|
-
default_refresh_interval =
|
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' => '
|
761
|
-
{'fieldName' => '
|
762
|
-
{'fieldName' => '
|
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' =>
|
765
|
-
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflowConfig', 'fieldLabel' => 'Config', 'type' => 'textarea', 'description' => 'Enter configuration for the Workflow', 'required' => false, 'noParse' => true, 'displayOrder' =>
|
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' =>
|
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' =>
|
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' =>
|
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' =>
|
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
|
|
@@ -4946,7 +4946,7 @@ EOT
|
|
4946
4946
|
end
|
4947
4947
|
|
4948
4948
|
def apply(args)
|
4949
|
-
default_refresh_interval =
|
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]")
|
@@ -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
|
@@ -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
|
-
|
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
|
-
|
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
|
289
|
-
|
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
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
(params['config'] ||= {})['
|
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
|
@@ -396,13 +407,31 @@ class Morpheus::Cli::ServicePlanCommand
|
|
396
407
|
true
|
397
408
|
)
|
398
409
|
params['maxMemory'] = bytes[:bytes]
|
399
|
-
# (params['config'] ||= {})['memorySizeType'] = bytes[:unit].downcase
|
400
410
|
rescue
|
401
411
|
print "Invalid Value... Please try again.\n"
|
402
412
|
end
|
413
|
+
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
414
|
end
|
404
415
|
end
|
405
416
|
|
417
|
+
# add'n options
|
418
|
+
addn_options = [
|
419
|
+
{'fieldName' => 'maxCores', 'fieldLabel' => 'Core Count', 'type' => 'number', 'required' => true, 'defaultValue' => 1, 'displayOrder' => 1},
|
420
|
+
{'fieldName' => 'customCores', 'fieldLabel' => 'Custom Cores', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 2},
|
421
|
+
{'fieldName' => 'coresPerSocket', 'fieldLabel' => 'Cores Per Socket', 'type' => 'number', 'required' => true, 'defaultValue' => 1, 'displayOrder' => 3},
|
422
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minStorage', 'fieldLabel' => 'Min Total Storage (GB)', 'type' => 'number', 'displayOrder' => 1},
|
423
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxStorage', 'fieldLabel' => 'Max Total Storage (GB)', 'type' => 'number', 'displayOrder' => 2},
|
424
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minPerDiskSize', 'fieldLabel' => 'Min Per Disk Size (GB)', 'type' => 'number', 'displayOrder' => 3},
|
425
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxPerDiskSize', 'fieldLabel' => 'Max Per Disk Size (GB)', 'type' => 'number', 'displayOrder' => 4},
|
426
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minMemory', 'fieldLabel' => 'Min Memory (GB)', 'type' => 'number', 'displayOrder' => 5},
|
427
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxMemory', 'fieldLabel' => 'Max Memory (GB)', 'type' => 'number', 'displayOrder' => 6},
|
428
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'minCores', 'fieldLabel' => 'Min Cores', 'type' => 'number', 'displayOrder' => 7},
|
429
|
+
{'fieldContext' => 'config.ranges', 'fieldGroup' => 'Custom Ranges', 'fieldName' => 'maxCores', 'fieldLabel' => 'Max Cores', 'type' => 'number', 'displayOrder' => 8}
|
430
|
+
]
|
431
|
+
|
432
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(addn_options, options[:options], @api_client, params)
|
433
|
+
params.deep_merge!(v_prompt)
|
434
|
+
|
406
435
|
# price sets
|
407
436
|
if params['priceSets'].nil? && !options[:no_prompt]
|
408
437
|
price_sets = []
|
@@ -517,17 +546,17 @@ class Morpheus::Cli::ServicePlanCommand
|
|
517
546
|
opts.on('--price-sets [LIST]', Array, 'Price set(s), comma separated list of price set IDs') do |list|
|
518
547
|
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
548
|
end
|
520
|
-
opts.on('--min-storage NUMBER', String, "Min storage
|
521
|
-
|
522
|
-
bytes = parse_bytes_param(val, '--min-storage', 'GB')
|
523
|
-
((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = bytes[:number]
|
524
|
-
(params['config'] ||= {})['storageSizeType'] = bytes[:unit].downcase
|
549
|
+
opts.on('--min-storage NUMBER', String, "Min total storage in GB.") do |val|
|
550
|
+
((params['config'] ||= {})['ranges'] ||= {})['minStorage'] = val.to_i
|
525
551
|
end
|
526
|
-
opts.on('--max-storage NUMBER', String, "Max storage
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
(params['config'] ||= {})['
|
552
|
+
opts.on('--max-storage NUMBER', String, "Max total storage in GB.") do |val|
|
553
|
+
((params['config'] ||= {})['ranges'] ||= {})['maxStorage'] = val.to_i
|
554
|
+
end
|
555
|
+
opts.on('--min-per-disk-size NUMBER', String, "Min per disk size in GB.") do |val|
|
556
|
+
((params['config'] ||= {})['ranges'] ||= {})['minPerDiskSize'] = val.to_i
|
557
|
+
end
|
558
|
+
opts.on('--max-per-disk-size NUMBER', String, "Max per disk size in GB.") do |val|
|
559
|
+
((params['config'] ||= {})['ranges'] ||= {})['maxPerDiskSize'] = val.to_i
|
531
560
|
end
|
532
561
|
opts.on('--min-memory NUMBER', String, "Min memory. Assumes MB unless optional modifier specified, ex: 1GB") do |val|
|
533
562
|
# Memory does get converted to bytes
|
@@ -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
|
-
|
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
|
-
|
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]
|
867
|
-
opts.on('--
|
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
|
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('--
|
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('--
|
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
|
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.
|
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('--
|
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
|
-
#
|
925
|
-
if
|
926
|
-
|
927
|
-
|
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
|
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
|
-
|
942
|
-
|
943
|
-
|
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
|
-
|
949
|
-
#
|
950
|
-
|
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
|
-
|
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]
|
558
|
-
opts.on('--
|
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
|
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('--
|
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('--
|
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
|
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.
|
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
|
-
|
615
|
-
|
616
|
-
|
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
|
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 == '
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
#
|
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 =
|
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
|
-
|
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
|
-
|
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
|
@@ -778,6 +778,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
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
780
|
resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
|
781
|
+
pool_required = provision_type["zonePoolRequired"]
|
781
782
|
|
782
783
|
if resource_pool
|
783
784
|
pool_id = resource_pool['id']
|
@@ -785,7 +786,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
785
786
|
if options[:default_resource_pool]
|
786
787
|
default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
|
787
788
|
end
|
788
|
-
resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' =>
|
789
|
+
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
790
|
resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
|
790
791
|
resource_pool_prompt.deep_compact!
|
791
792
|
payload.deep_merge!(resource_pool_prompt)
|
@@ -814,7 +814,7 @@ module Morpheus
|
|
814
814
|
api_params ||= {}
|
815
815
|
api_params['query'] = query_value
|
816
816
|
# skip refresh if you just hit enter
|
817
|
-
if !query_value.empty?
|
817
|
+
if !query_value.empty? || (select_options.nil? || select_options.empty?)
|
818
818
|
select_options = load_options(option_type, api_client, api_params, query_value)
|
819
819
|
end
|
820
820
|
|
data/lib/morpheus/cli/version.rb
CHANGED
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.
|
4
|
+
version: 6.0.1
|
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-
|
14
|
+
date: 2023-03-14 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|