morpheus-cli 6.0.2 → 6.1.1
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 +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +8 -0
- data/lib/morpheus/api/backups_interface.rb +4 -0
- data/lib/morpheus/api/cypher_interface.rb +11 -5
- data/lib/morpheus/api/load_balancer_pool_nodes_interface.rb +8 -0
- data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
- data/lib/morpheus/api/load_balancer_pools_secondary_interface.rb +9 -0
- data/lib/morpheus/api/roles_interface.rb +8 -8
- data/lib/morpheus/cli/cli_command.rb +115 -2
- data/lib/morpheus/cli/commands/backup_jobs_command.rb +3 -7
- data/lib/morpheus/cli/commands/backups_command.rb +133 -19
- data/lib/morpheus/cli/commands/invoices_command.rb +1 -1
- data/lib/morpheus/cli/commands/load_balancer_pool_nodes.rb +87 -0
- data/lib/morpheus/cli/commands/load_balancer_pools.rb +7 -4
- data/lib/morpheus/cli/commands/networks_command.rb +31 -0
- data/lib/morpheus/cli/commands/roles.rb +403 -586
- data/lib/morpheus/cli/commands/service_catalog_command.rb +77 -103
- data/lib/morpheus/cli/commands/users.rb +46 -2
- data/lib/morpheus/cli/mixins/backups_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +6 -6
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +5 -2
@@ -544,13 +544,12 @@ EOT
|
|
544
544
|
def update_cart(args)
|
545
545
|
options = {}
|
546
546
|
params = {}
|
547
|
-
payload = {}
|
548
547
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
549
548
|
opts.banner = subcommand_usage("--name [name]")
|
550
549
|
opts.on('--name [NAME]', String, "Set an optional name for your catalog order") do |val|
|
551
550
|
options[:options]['name'] = val.to_s
|
552
551
|
end
|
553
|
-
build_standard_update_options(opts, options, [:sigdig])
|
552
|
+
build_standard_update_options(opts, options, [:payloads, :sigdig])
|
554
553
|
opts.footer = <<-EOT
|
555
554
|
Update your cart settings, such as name.
|
556
555
|
EOT
|
@@ -560,29 +559,26 @@ EOT
|
|
560
559
|
connect(options)
|
561
560
|
# fetch current cart
|
562
561
|
# cart = @service_catalog_interface.get_cart()['cart']
|
563
|
-
payload = {}
|
564
562
|
update_cart_object_key = 'order'
|
565
|
-
|
566
|
-
payload = options[:payload]
|
563
|
+
payloads = parse_payloads(options, update_cart_object_key) do |payload|
|
567
564
|
payload.deep_merge!({update_cart_object_key => parse_passed_options(options)})
|
568
|
-
else
|
569
|
-
payload.deep_merge!({update_cart_object_key => parse_passed_options(options)})
|
570
|
-
payload.deep_merge!({update_cart_object_key => params})
|
571
565
|
if payload[update_cart_object_key].empty? # || options[:no_prompt]
|
572
566
|
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
573
567
|
end
|
574
568
|
end
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
569
|
+
process_payloads(payloads, options) do |payload|
|
570
|
+
@service_catalog_interface.setopts(options)
|
571
|
+
if options[:dry_run]
|
572
|
+
print_dry_run @service_catalog_interface.dry.update_cart(payload)
|
573
|
+
next
|
574
|
+
end
|
575
|
+
json_response = @service_catalog_interface.update_cart(payload)
|
576
|
+
#cart = json_response['cart']
|
577
|
+
#cart = @service_catalog_interface.get_cart()['cart']
|
578
|
+
render_response(json_response, options, 'cart') do
|
579
|
+
print_green_success "Updated cart"
|
580
|
+
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
581
|
+
end
|
586
582
|
end
|
587
583
|
return 0, nil
|
588
584
|
end
|
@@ -590,7 +586,6 @@ EOT
|
|
590
586
|
def add(args)
|
591
587
|
options = {}
|
592
588
|
params = {}
|
593
|
-
payload = {}
|
594
589
|
type_id = nil
|
595
590
|
workflow_context = nil
|
596
591
|
workflow_target = nil
|
@@ -613,7 +608,7 @@ EOT
|
|
613
608
|
workflow_target = val.to_s
|
614
609
|
end
|
615
610
|
opts.add_hidden_option('--sigdig')
|
616
|
-
build_standard_update_options(opts, options, [:sigdig])
|
611
|
+
build_standard_update_options(opts, options, [:payloads, :sigdig])
|
617
612
|
opts.footer = <<-EOT
|
618
613
|
Add an item to your cart
|
619
614
|
[type] is required, this is name or id of a catalog item type.
|
@@ -626,13 +621,8 @@ EOT
|
|
626
621
|
if args.count > 0
|
627
622
|
type_id = args.join(" ")
|
628
623
|
end
|
629
|
-
payload = {}
|
630
624
|
add_item_object_key = 'item'
|
631
|
-
|
632
|
-
if options[:payload]
|
633
|
-
payload = options[:payload]
|
634
|
-
payload.deep_merge!({add_item_object_key => parse_passed_options(options)})
|
635
|
-
else
|
625
|
+
payloads = parse_payloads(options, add_item_object_key) do |payload|
|
636
626
|
payload.deep_merge!({add_item_object_key => parse_passed_options(options)})
|
637
627
|
# prompt for Type
|
638
628
|
if type_id
|
@@ -725,49 +715,45 @@ EOT
|
|
725
715
|
if options[:validate_only]
|
726
716
|
params['validate'] = true
|
727
717
|
end
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
if
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
718
|
+
process_payloads(payloads, options) do |payload|
|
719
|
+
@service_catalog_interface.setopts(options)
|
720
|
+
if options[:dry_run]
|
721
|
+
print_dry_run @service_catalog_interface.dry.create_cart_item(payload, params)
|
722
|
+
next
|
723
|
+
end
|
724
|
+
json_response = @service_catalog_interface.create_cart_item(payload, params)
|
725
|
+
cart_item = json_response['item']
|
726
|
+
render_response(json_response, options) do
|
727
|
+
if options[:validate_only]
|
728
|
+
if json_response['success']
|
729
|
+
print_h2 "Validated Cart Item", [], options
|
730
|
+
cart_item_columns = {
|
731
|
+
"Type" => lambda {|it| it['type']['name'] rescue '' },
|
732
|
+
#"Qty" => lambda {|it| it['quantity'] },
|
733
|
+
"Price" => lambda {|it| it['price'] ? format_money(it['price'] , it['currency'], {sigdig:options[:sigdig] || default_sigdig}) : "No pricing configured" },
|
734
|
+
"Status" => lambda {|it|
|
735
|
+
status_string = format_catalog_item_status(it)
|
736
|
+
if it['errorMessage'].to_s != ""
|
737
|
+
status_string << " - #{it['errorMessage']}"
|
738
|
+
end
|
739
|
+
status_string
|
740
|
+
},
|
741
|
+
#"Config" => lambda {|it| truncate_string(format_name_values(it['config']), 50) }
|
742
|
+
}
|
743
|
+
print as_pretty_table([cart_item], cart_item_columns.upcase_keys!)
|
744
|
+
print reset, "\n"
|
745
|
+
print_green_success(json_response['msg'] || "Item is valid")
|
746
|
+
print reset, "\n"
|
747
|
+
else
|
748
|
+
# not needed because it will be http 400
|
749
|
+
print_rest_errors(json_response, options)
|
750
|
+
end
|
756
751
|
else
|
757
|
-
|
758
|
-
|
752
|
+
print_green_success "Added item to cart"
|
753
|
+
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
759
754
|
end
|
760
|
-
else
|
761
|
-
print_green_success "Added item to cart"
|
762
|
-
get_cart([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
763
755
|
end
|
764
756
|
end
|
765
|
-
if json_response['success']
|
766
|
-
return 0, nil
|
767
|
-
else
|
768
|
-
# not needed because it will be http 400
|
769
|
-
return 1, json_response['msg'] || 'request failed'
|
770
|
-
end
|
771
757
|
end
|
772
758
|
|
773
759
|
def update_cart_item(args)
|
@@ -882,7 +868,6 @@ EOT
|
|
882
868
|
def checkout(args)
|
883
869
|
options = {}
|
884
870
|
params = {}
|
885
|
-
payload = {}
|
886
871
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
887
872
|
opts.banner = subcommand_usage()
|
888
873
|
build_standard_add_options(opts, options, [:auto_confirm, :sigdig])
|
@@ -936,7 +921,6 @@ EOT
|
|
936
921
|
def add_order(args)
|
937
922
|
options = {}
|
938
923
|
params = {}
|
939
|
-
payload = {}
|
940
924
|
type_id = nil
|
941
925
|
workflow_context = nil
|
942
926
|
workflow_target = nil
|
@@ -961,7 +945,7 @@ EOT
|
|
961
945
|
opts.on('--target ID', String, "Target Resource (Instance or Server) for operational workflow types") do |val|
|
962
946
|
workflow_target = val.to_s
|
963
947
|
end
|
964
|
-
build_standard_add_options(opts, options, [:sigdig])
|
948
|
+
build_standard_add_options(opts, options, [:payloads, :sigdig])
|
965
949
|
opts.footer = <<-EOT
|
966
950
|
Place an order for new inventory.
|
967
951
|
This allows creating a new order without using the cart.
|
@@ -978,14 +962,8 @@ EOT
|
|
978
962
|
end
|
979
963
|
payload = {}
|
980
964
|
order_object_key = 'order'
|
981
|
-
|
982
|
-
|
983
|
-
if options[:payload]
|
984
|
-
payload = options[:payload]
|
985
|
-
payload.deep_merge!({order_object_key => passed_options}) unless passed_options.empty?
|
986
|
-
else
|
987
|
-
payload.deep_merge!({order_object_key => passed_options}) unless passed_options.empty?
|
988
|
-
|
965
|
+
payloads = parse_payloads(options, order_object_key) do |payload|
|
966
|
+
payload.deep_merge!({order_object_key => {}})
|
989
967
|
# Prompt for 1-N Types
|
990
968
|
# still_prompting = options[:no_prompt] != true
|
991
969
|
still_prompting = true
|
@@ -1106,36 +1084,32 @@ EOT
|
|
1106
1084
|
params['validate'] = true
|
1107
1085
|
#payload['validate'] = true
|
1108
1086
|
end
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
if
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1087
|
+
process_payloads(payloads, options) do |payload|
|
1088
|
+
@service_catalog_interface.setopts(options)
|
1089
|
+
if options[:dry_run]
|
1090
|
+
print_dry_run @service_catalog_interface.dry.create_order(payload, params)
|
1091
|
+
next
|
1092
|
+
end
|
1093
|
+
json_response = @service_catalog_interface.create_order(payload, params)
|
1094
|
+
order = json_response['order'] || json_response['cart']
|
1095
|
+
render_response(json_response, options) do
|
1096
|
+
if options[:validate_only]
|
1097
|
+
if json_response['success']
|
1098
|
+
print_h2 "Review Order", [], options
|
1099
|
+
print_order_details(order, options)
|
1100
|
+
print_green_success(json_response['msg'] || "Order is valid")
|
1101
|
+
print reset, "\n"
|
1102
|
+
else
|
1103
|
+
# not needed because it will be http 400
|
1104
|
+
print_rest_errors(json_response, options)
|
1105
|
+
end
|
1123
1106
|
else
|
1124
|
-
|
1125
|
-
|
1107
|
+
print_green_success "Order placed"
|
1108
|
+
print_h2 "Order Details", [], options
|
1109
|
+
print_order_details(order, options)
|
1126
1110
|
end
|
1127
|
-
else
|
1128
|
-
print_green_success "Order placed"
|
1129
|
-
print_h2 "Order Details", [], options
|
1130
|
-
print_order_details(order, options)
|
1131
1111
|
end
|
1132
1112
|
end
|
1133
|
-
if json_response['success']
|
1134
|
-
return 0, nil
|
1135
|
-
else
|
1136
|
-
# not needed because it will be http 400
|
1137
|
-
return 1, json_response['msg'] || 'request failed'
|
1138
|
-
end
|
1139
1113
|
end
|
1140
1114
|
|
1141
1115
|
def remove(args)
|
@@ -297,7 +297,29 @@ EOT
|
|
297
297
|
if access.count > 0
|
298
298
|
access.each {|it| it['access'] = format_access_string(it['access'], available_access_levels)}
|
299
299
|
|
300
|
-
if ['features'
|
300
|
+
if ['features'].include?(field)
|
301
|
+
if access.find {|it| !it['subCategory'].to_s.empty? }
|
302
|
+
rows = access.collect do |it|
|
303
|
+
{
|
304
|
+
code: it['code'],
|
305
|
+
name: it['name'],
|
306
|
+
category: it['subCategory'].to_s.titleize,
|
307
|
+
access: format_access_string(it['access']),
|
308
|
+
}
|
309
|
+
end
|
310
|
+
if options[:sort]
|
311
|
+
rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
|
312
|
+
else
|
313
|
+
rows.sort! {|a,b| [a[:category],a[:name],a[:code]] <=> [b[:category],b[:name],b[:code]] }
|
314
|
+
end
|
315
|
+
if options[:direction] == 'desc'
|
316
|
+
rows.reverse!
|
317
|
+
end
|
318
|
+
print as_pretty_table(rows, [:category, :name, :code, :access], options)
|
319
|
+
else
|
320
|
+
print as_pretty_table(access, [:name, :code, :access], options)
|
321
|
+
end
|
322
|
+
elsif ['instance_types','report_types'].include?(field)
|
301
323
|
print as_pretty_table(access, [:name, :code, :access], options)
|
302
324
|
else
|
303
325
|
print as_pretty_table(access, [:name, :access], options)
|
@@ -422,7 +444,29 @@ EOT
|
|
422
444
|
if access.count > 0
|
423
445
|
access.each {|it| it['access'] = format_access_string(it['access'], available_access_levels)}
|
424
446
|
|
425
|
-
if ['features'
|
447
|
+
if ['features'].include?(field)
|
448
|
+
if access.find {|it| !it['subCategory'].to_s.empty? }
|
449
|
+
rows = access.collect do |it|
|
450
|
+
{
|
451
|
+
code: it['code'],
|
452
|
+
name: it['name'],
|
453
|
+
category: it['subCategory'].to_s.titleize,
|
454
|
+
access: format_access_string(it['access']),
|
455
|
+
}
|
456
|
+
end
|
457
|
+
if options[:sort]
|
458
|
+
rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
|
459
|
+
else
|
460
|
+
rows.sort! {|a,b| [a[:category],a[:name],a[:code]] <=> [b[:category],b[:name],b[:code]] }
|
461
|
+
end
|
462
|
+
if options[:direction] == 'desc'
|
463
|
+
rows.reverse!
|
464
|
+
end
|
465
|
+
print as_pretty_table(rows, [:category, :name, :code, :access], options)
|
466
|
+
else
|
467
|
+
print as_pretty_table(access, [:name, :code, :access], options)
|
468
|
+
end
|
469
|
+
elsif ['instance_types','report_types'].include?(field)
|
426
470
|
print as_pretty_table(access, [:name, :code, :access], options)
|
427
471
|
else
|
428
472
|
print as_pretty_table(access, [:name, :access], options)
|
@@ -719,7 +719,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
719
719
|
service_plan = nil
|
720
720
|
|
721
721
|
prompt_service_plan = -> {
|
722
|
-
service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id}.merge(resource_pool.nil? ? {} : {'resourcePoolId' => resource_pool['id']}))
|
722
|
+
service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id}.merge(resource_pool.nil? ? {} : {'poolId' => resource_pool['id'], 'resourcePoolId' => resource_pool['id']}))
|
723
723
|
service_plans = service_plans_json["plans"]
|
724
724
|
if locked_fields.include?('plan.id')
|
725
725
|
plan_id = options[:options]['plan']['id'] rescue nil
|
@@ -773,8 +773,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
773
773
|
has_zone_pools = provision_type && provision_type["id"] && provision_type["hasZonePools"]
|
774
774
|
if has_zone_pools
|
775
775
|
# pluck out the resourcePoolId option type to prompt for
|
776
|
-
resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
777
|
-
option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
776
|
+
resource_pool_option_type = option_type_list.find {|opt| ['poolId','resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
777
|
+
option_type_list = option_type_list.reject {|opt| ['poolId','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
780
|
if options[:resource_pool]
|
@@ -836,7 +836,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
836
836
|
# add selectable datastores for resource pool
|
837
837
|
if options[:select_datastore]
|
838
838
|
begin
|
839
|
-
selectable_datastores = datastores_interface.list({'zoneId' => cloud_id, 'siteId' => group_id, 'resourcePoolId' => resource_pool['id']})
|
839
|
+
selectable_datastores = datastores_interface.list({'zoneId' => cloud_id, 'siteId' => group_id, 'poolId' => resource_pool['id'], 'resourcePoolId' => resource_pool['id']})
|
840
840
|
service_plan['datastores'] = {'clusters' => [], 'datastores' => []}
|
841
841
|
['clusters', 'datastores'].each do |type|
|
842
842
|
service_plan['datastores'][type] ||= []
|
@@ -1538,7 +1538,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1538
1538
|
|
1539
1539
|
if datastore_options.empty? && storage_type['hasDatastore'] != false
|
1540
1540
|
begin
|
1541
|
-
datastore_res = datastores_interface.list({'resourcePoolId' => current_root_volume['resourcePoolId'], 'zoneId' => options['zoneId'], 'siteId' => options['siteId']})['datastores']
|
1541
|
+
datastore_res = datastores_interface.list({'poolId' => current_root_volume['resourcePoolId'], 'resourcePoolId' => current_root_volume['resourcePoolId'], 'zoneId' => options['zoneId'], 'siteId' => options['siteId']})['datastores']
|
1542
1542
|
datastore_res.each do |opt|
|
1543
1543
|
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
1544
1544
|
end
|
@@ -1578,7 +1578,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1578
1578
|
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
1579
1579
|
network_interfaces = []
|
1580
1580
|
api_params = {zoneId: zone_id, provisionTypeId: provision_type_id}.merge(options[:api_params] || {})
|
1581
|
-
if pool_id
|
1581
|
+
if pool_id
|
1582
1582
|
api_params[:poolId] = pool_id
|
1583
1583
|
end
|
1584
1584
|
|
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.
|
4
|
+
version: 6.1.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-
|
14
|
+
date: 2023-05-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -260,7 +260,9 @@ files:
|
|
260
260
|
- lib/morpheus/api/library_spec_templates_interface.rb
|
261
261
|
- lib/morpheus/api/license_interface.rb
|
262
262
|
- lib/morpheus/api/load_balancer_monitors_interface.rb
|
263
|
+
- lib/morpheus/api/load_balancer_pool_nodes_interface.rb
|
263
264
|
- lib/morpheus/api/load_balancer_pools_interface.rb
|
265
|
+
- lib/morpheus/api/load_balancer_pools_secondary_interface.rb
|
264
266
|
- lib/morpheus/api/load_balancer_profiles_interface.rb
|
265
267
|
- lib/morpheus/api/load_balancer_types_interface.rb
|
266
268
|
- lib/morpheus/api/load_balancer_virtual_servers_interface.rb
|
@@ -434,6 +436,7 @@ files:
|
|
434
436
|
- lib/morpheus/cli/commands/library_upgrades_command.rb
|
435
437
|
- lib/morpheus/cli/commands/license.rb
|
436
438
|
- lib/morpheus/cli/commands/load_balancer_monitors.rb
|
439
|
+
- lib/morpheus/cli/commands/load_balancer_pool_nodes.rb
|
437
440
|
- lib/morpheus/cli/commands/load_balancer_pools.rb
|
438
441
|
- lib/morpheus/cli/commands/load_balancer_profiles.rb
|
439
442
|
- lib/morpheus/cli/commands/load_balancer_types.rb
|