morpheus-cli 5.4.2 → 5.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +4 -1
- data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
- data/lib/morpheus/api/instances_interface.rb +28 -0
- data/lib/morpheus/api/ping_interface.rb +2 -0
- data/lib/morpheus/api/setup_interface.rb +4 -0
- data/lib/morpheus/api/snapshots_interface.rb +19 -0
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
- data/lib/morpheus/cli/commands/clusters.rb +59 -46
- data/lib/morpheus/cli/commands/hosts.rb +12 -0
- data/lib/morpheus/cli/commands/instances.rb +250 -1
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +5 -0
- data/lib/morpheus/cli/commands/networks_command.rb +2 -2
- data/lib/morpheus/cli/commands/ping.rb +3 -5
- data/lib/morpheus/cli/commands/policies_command.rb +1 -1
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
- data/lib/morpheus/cli/commands/remote.rb +16 -10
- data/lib/morpheus/cli/commands/security_groups.rb +2 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
- data/lib/morpheus/cli/commands/setup.rb +1 -1
- data/lib/morpheus/cli/commands/snapshots.rb +139 -0
- data/lib/morpheus/cli/commands/tasks.rb +5 -5
- data/lib/morpheus/cli/commands/user_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +80 -0
- data/lib/morpheus/cli/option_types.rb +26 -11
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +4 -2
@@ -17,7 +17,8 @@ class Morpheus::Cli::Instances
|
|
17
17
|
:logs, :stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
|
18
18
|
:backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
|
19
19
|
:lock, :unlock, :clone_image,
|
20
|
-
:security_groups, :apply_security_groups, :run_workflow,
|
20
|
+
:security_groups, :apply_security_groups, :run_workflow,
|
21
|
+
:import_snapshot, :snapshot, :snapshots, :revert_to_snapshot, :remove_all_snapshots, :remove_all_container_snapshots, :create_linked_clone,
|
21
22
|
:console, :status_check, {:containers => :list_containers},
|
22
23
|
:scaling, {:'scaling-update' => :scaling_update},
|
23
24
|
:wiki, :update_wiki,
|
@@ -52,6 +53,7 @@ class Morpheus::Cli::Instances
|
|
52
53
|
@execution_request_interface = @api_client.execution_request
|
53
54
|
@deploy_interface = @api_client.deploy
|
54
55
|
@deployments_interface = @api_client.deployments
|
56
|
+
@snapshots_interface = @api_client.snapshots
|
55
57
|
end
|
56
58
|
|
57
59
|
def handle(args)
|
@@ -2718,6 +2720,12 @@ class Morpheus::Cli::Instances
|
|
2718
2720
|
payload["volumes"] = volumes
|
2719
2721
|
end
|
2720
2722
|
|
2723
|
+
# plan customizations
|
2724
|
+
plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {}, instance)
|
2725
|
+
if plan_opts && !plan_opts.empty?
|
2726
|
+
payload['servicePlanOptions'] = plan_opts
|
2727
|
+
end
|
2728
|
+
|
2721
2729
|
# only amazon supports this option
|
2722
2730
|
# for now, always do this
|
2723
2731
|
payload["deleteOriginalVolumes"] = true
|
@@ -3361,6 +3369,223 @@ EOT
|
|
3361
3369
|
end
|
3362
3370
|
end
|
3363
3371
|
|
3372
|
+
def revert_to_snapshot(args)
|
3373
|
+
options = {}
|
3374
|
+
instance = nil
|
3375
|
+
snapshot_id = nil
|
3376
|
+
|
3377
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3378
|
+
opts.banner = subcommand_usage("[instance]")
|
3379
|
+
opts.on("--snapshot ID", String, "Optional snapshot") do |val|
|
3380
|
+
snapshot_id = val
|
3381
|
+
end
|
3382
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
3383
|
+
build_standard_add_options(opts, options) #, [:options, :payload, :json, :dry_run, :remote, :quiet])
|
3384
|
+
opts.footer = "Revert an Instance to saved Snapshot previously made." + "\n" +
|
3385
|
+
"[snapshotId] is required. This is the id of the snapshot to replace the current instance."
|
3386
|
+
end
|
3387
|
+
|
3388
|
+
optparse.parse!(args)
|
3389
|
+
if args.count != 1
|
3390
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
3391
|
+
end
|
3392
|
+
connect(options)
|
3393
|
+
begin
|
3394
|
+
instance = find_instance_by_name_or_id(args[0])
|
3395
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to revert instance '#{instance['name']}'?", options)
|
3396
|
+
exit 1
|
3397
|
+
end
|
3398
|
+
options[:options]['instanceId'] = instance['id']
|
3399
|
+
begin
|
3400
|
+
snapshot_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'snapshotId', 'type' => 'select', 'fieldLabel' => 'Snapshot', 'optionSource' => 'instanceSnapshots', 'required' => true, 'description' => 'Select Snapshot.'}], {}, @api_client, options[:options])
|
3401
|
+
|
3402
|
+
if !snapshot_prompt['snapshotId'].to_s.empty?
|
3403
|
+
snapshot_id = snapshot_prompt['snapshotId']
|
3404
|
+
end
|
3405
|
+
rescue RestClient::Exception => e
|
3406
|
+
puts "Failed to load instance snapshots"
|
3407
|
+
end
|
3408
|
+
|
3409
|
+
@instances_interface.setopts(options)
|
3410
|
+
|
3411
|
+
payload = {}
|
3412
|
+
if options[:dry_run]
|
3413
|
+
print_dry_run @instances_interface.dry.revert_to_snapshot(instance['id'], snapshot_id, payload)
|
3414
|
+
return
|
3415
|
+
end
|
3416
|
+
|
3417
|
+
json_response = @instances_interface.revert_to_snapshot(instance['id'], snapshot_id, payload)
|
3418
|
+
if options[:json]
|
3419
|
+
puts as_json(json_response, options)
|
3420
|
+
else
|
3421
|
+
print_green_success "Snapshot revert initiated."
|
3422
|
+
end
|
3423
|
+
return 0
|
3424
|
+
|
3425
|
+
rescue RestClient::Exception => e
|
3426
|
+
print_rest_exception(e, options)
|
3427
|
+
exit 1
|
3428
|
+
end
|
3429
|
+
end
|
3430
|
+
|
3431
|
+
def remove_all_container_snapshots(args)
|
3432
|
+
options = {}
|
3433
|
+
instance = nil
|
3434
|
+
container_id = nil
|
3435
|
+
|
3436
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3437
|
+
opts.banner = subcommand_usage("[instance]")
|
3438
|
+
opts.on("--container ID", String, "Required container") do |val|
|
3439
|
+
container_id = val
|
3440
|
+
end
|
3441
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
3442
|
+
opts.footer = "Remove all snapshots attached to an instances container." + "\n" +
|
3443
|
+
"[containerId] is required. This is the id of the container which removes all attached snapshots."
|
3444
|
+
end
|
3445
|
+
|
3446
|
+
optparse.parse!(args)
|
3447
|
+
if args.count != 1
|
3448
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
3449
|
+
end
|
3450
|
+
connect(options)
|
3451
|
+
begin
|
3452
|
+
instance = find_instance_by_name_or_id(args[0])
|
3453
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove all snapshots for a container?", options)
|
3454
|
+
exit 1
|
3455
|
+
end
|
3456
|
+
options[:options]['instanceId'] = instance['id']
|
3457
|
+
begin
|
3458
|
+
container_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'containerId', 'type' => 'select', 'fieldLabel' => 'Container', 'optionSource' => 'instanceContainers', 'required' => true, 'description' => 'Select Container.'}], {}, @api_client, options[:options])
|
3459
|
+
|
3460
|
+
if !container_prompt['containerId'].to_s.empty?
|
3461
|
+
container_id = container_prompt['containerId']
|
3462
|
+
end
|
3463
|
+
rescue RestClient::Exception => e
|
3464
|
+
puts "Failed to load instance containers"
|
3465
|
+
end
|
3466
|
+
|
3467
|
+
@instances_interface.setopts(options)
|
3468
|
+
|
3469
|
+
payload = {}
|
3470
|
+
if options[:dry_run]
|
3471
|
+
print_dry_run @instances_interface.dry.remove_all_container_snapshots(instance['id'], container_id, payload)
|
3472
|
+
return
|
3473
|
+
end
|
3474
|
+
|
3475
|
+
json_response = @instances_interface.remove_all_container_snapshots(instance['id'], container_id, payload)
|
3476
|
+
if options[:json]
|
3477
|
+
puts as_json(json_response, options)
|
3478
|
+
else
|
3479
|
+
print_green_success "Snapshot delete initiated."
|
3480
|
+
end
|
3481
|
+
return 0
|
3482
|
+
|
3483
|
+
rescue RestClient::Exception => e
|
3484
|
+
print_rest_exception(e, options)
|
3485
|
+
exit 1
|
3486
|
+
end
|
3487
|
+
end
|
3488
|
+
|
3489
|
+
def remove_all_snapshots(args)
|
3490
|
+
options = {}
|
3491
|
+
instance = nil
|
3492
|
+
|
3493
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3494
|
+
opts.banner = subcommand_usage("[instance]")
|
3495
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
3496
|
+
opts.footer = "Remove all snapshots attached to an instance." + "\n" +
|
3497
|
+
"Warning: This will remove all snapshots across all containers of an instance."
|
3498
|
+
end
|
3499
|
+
|
3500
|
+
optparse.parse!(args)
|
3501
|
+
if args.count != 1
|
3502
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
3503
|
+
end
|
3504
|
+
connect(options)
|
3505
|
+
begin
|
3506
|
+
instance = find_instance_by_name_or_id(args[0])
|
3507
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove all snapshots for this instance?", options)
|
3508
|
+
exit 1
|
3509
|
+
end
|
3510
|
+
options[:options]['instanceId'] = instance['id']
|
3511
|
+
|
3512
|
+
@instances_interface.setopts(options)
|
3513
|
+
|
3514
|
+
payload = {}
|
3515
|
+
if options[:dry_run]
|
3516
|
+
print_dry_run @instances_interface.dry.remove_all_instance_snapshots(instance['id'], payload)
|
3517
|
+
return
|
3518
|
+
end
|
3519
|
+
|
3520
|
+
json_response = @instances_interface.remove_all_instance_snapshots(instance['id'], payload)
|
3521
|
+
if options[:json]
|
3522
|
+
puts as_json(json_response, options)
|
3523
|
+
else
|
3524
|
+
print_green_success "Snapshots attaced to instance #{instance['name']} queued for deletion."
|
3525
|
+
end
|
3526
|
+
return 0
|
3527
|
+
|
3528
|
+
rescue RestClient::Exception => e
|
3529
|
+
print_rest_exception(e, options)
|
3530
|
+
exit 1
|
3531
|
+
end
|
3532
|
+
end
|
3533
|
+
|
3534
|
+
def create_linked_clone(args)
|
3535
|
+
options = {}
|
3536
|
+
instance = nil
|
3537
|
+
snapshot_id = nil
|
3538
|
+
|
3539
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
3540
|
+
opts.banner = subcommand_usage("[instance]")
|
3541
|
+
opts.on("--snapshot ID", String, "Optional snapshot") do |val|
|
3542
|
+
snapshot_id = val
|
3543
|
+
end
|
3544
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
3545
|
+
opts.footer = "Create a linked clone using the selected snapshot of an Instance." + "\n" +
|
3546
|
+
"[snapshotId] is required. This is the id of the snapshot which the clone will refer to."
|
3547
|
+
end
|
3548
|
+
|
3549
|
+
optparse.parse!(args)
|
3550
|
+
if args.count != 1
|
3551
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
3552
|
+
end
|
3553
|
+
connect(options)
|
3554
|
+
begin
|
3555
|
+
instance = find_instance_by_name_or_id(args[0])
|
3556
|
+
options[:options]['instanceId'] = instance['id']
|
3557
|
+
begin
|
3558
|
+
snapshot_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'snapshotId', 'type' => 'select', 'fieldLabel' => 'Snapshot', 'optionSource' => 'instanceSnapshots', 'required' => true, 'description' => 'Select Snapshot.'}], {}, @api_client, options[:options])
|
3559
|
+
|
3560
|
+
if !snapshot_prompt['snapshotId'].to_s.empty?
|
3561
|
+
snapshot_id = snapshot_prompt['snapshotId']
|
3562
|
+
end
|
3563
|
+
rescue RestClient::Exception => e
|
3564
|
+
puts "Failed to load instance snapshots"
|
3565
|
+
end
|
3566
|
+
|
3567
|
+
@instances_interface.setopts(options)
|
3568
|
+
|
3569
|
+
payload = {}
|
3570
|
+
if options[:dry_run]
|
3571
|
+
print_dry_run @instances_interface.dry.create_linked_clone(instance['id'], snapshot_id, payload)
|
3572
|
+
return
|
3573
|
+
end
|
3574
|
+
|
3575
|
+
json_response = @instances_interface.create_linked_clone(instance['id'], snapshot_id, payload)
|
3576
|
+
if options[:json]
|
3577
|
+
puts as_json(json_response, options)
|
3578
|
+
else
|
3579
|
+
print_green_success "Linked Clone creation initiated."
|
3580
|
+
end
|
3581
|
+
return 0
|
3582
|
+
|
3583
|
+
rescue RestClient::Exception => e
|
3584
|
+
print_rest_exception(e, options)
|
3585
|
+
exit 1
|
3586
|
+
end
|
3587
|
+
end
|
3588
|
+
|
3364
3589
|
|
3365
3590
|
def scaling(args)
|
3366
3591
|
options = {}
|
@@ -4133,6 +4358,9 @@ EOT
|
|
4133
4358
|
opts.on( '--name VALUE', String, "Image Name (Template Name). Default is server name + timestamp" ) do |val|
|
4134
4359
|
options[:options]['templateName'] = val
|
4135
4360
|
end
|
4361
|
+
opts.on( '--folder VALUE', String, "Folder externalId or '/' to use the root folder" ) do |val|
|
4362
|
+
options[:options]['zoneFolder'] = val
|
4363
|
+
end
|
4136
4364
|
build_standard_update_options(opts, options)
|
4137
4365
|
opts.footer = <<-EOT
|
4138
4366
|
Clone to image (template) for an instance
|
@@ -4144,6 +4372,18 @@ EOT
|
|
4144
4372
|
connect(options)
|
4145
4373
|
instance = find_instance_by_name_or_id(args[0])
|
4146
4374
|
return 1 if instance.nil?
|
4375
|
+
# need to GET provision type for hasFolders
|
4376
|
+
provision_type_code = instance['layout']['provisionTypeCode'] rescue nil
|
4377
|
+
provision_type = nil
|
4378
|
+
if provision_type_code
|
4379
|
+
provision_type = provision_types_interface.list({code:provision_type_code})['provisionTypes'][0]
|
4380
|
+
if provision_type.nil?
|
4381
|
+
print_red_alert "Provision Type not found by code #{provision_type_code}"
|
4382
|
+
exit 1
|
4383
|
+
end
|
4384
|
+
else
|
4385
|
+
provision_type = get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
4386
|
+
end
|
4147
4387
|
payload = {}
|
4148
4388
|
if options[:payload]
|
4149
4389
|
payload = options[:payload]
|
@@ -4156,6 +4396,15 @@ EOT
|
|
4156
4396
|
payload['templateName'] = v_prompt['templateName']
|
4157
4397
|
end
|
4158
4398
|
end
|
4399
|
+
#if instance['layout']['provisionTypeCode'] == 'vmware'
|
4400
|
+
if provision_type && provision_type["hasFolders"]
|
4401
|
+
if payload['zoneFolder'].nil?
|
4402
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'zoneFolder', 'type' => 'select', 'optionSource' => 'vmwareFolders', 'fieldLabel' => 'Folder', 'description' => "Folder externalId or '/' to use the root folder", 'required' => true}], options[:options], @api_client, {siteId: instance['group']['id'], zoneId: instance['cloud']['id']})
|
4403
|
+
if v_prompt['zoneFolder'].to_s != ''
|
4404
|
+
payload['zoneFolder'] = v_prompt['zoneFolder']
|
4405
|
+
end
|
4406
|
+
end
|
4407
|
+
end
|
4159
4408
|
end
|
4160
4409
|
@instances_interface.setopts(options)
|
4161
4410
|
if options[:dry_run]
|
@@ -39,6 +39,9 @@ class Morpheus::Cli::LibraryInstanceTypesCommand
|
|
39
39
|
opts.on('--technology VALUE', String, "Filter by technology") do |val|
|
40
40
|
params['provisionTypeCode'] = val
|
41
41
|
end
|
42
|
+
opts.on('--featured [true|false]',String, "Filter by featured.") do |val|
|
43
|
+
params['featured'] = (val.to_s.downcase != 'false' && val.to_s.downcase != 'off')
|
44
|
+
end
|
42
45
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
43
46
|
opts.footer = "List instance types."
|
44
47
|
end
|
@@ -149,6 +149,11 @@ class Morpheus::Cli::NetworkStaticRoutesCommand
|
|
149
149
|
return 1
|
150
150
|
end
|
151
151
|
|
152
|
+
if !network_type['hasStaticRoutes']
|
153
|
+
print_red_alert "Static routes not supported for #{network_type['name']}"
|
154
|
+
return 1
|
155
|
+
end
|
156
|
+
|
152
157
|
payload = nil
|
153
158
|
if options[:payload]
|
154
159
|
payload = options[:payload]
|
@@ -189,7 +189,7 @@ class Morpheus::Cli::NetworksCommand
|
|
189
189
|
print cyan
|
190
190
|
description_cols = {
|
191
191
|
"ID" => 'id',
|
192
|
-
"Name" => 'name',
|
192
|
+
"Name" => lambda {|it| it['displayName'] ? it['displayName'] : it['name'] },
|
193
193
|
"Description" => 'description',
|
194
194
|
"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
|
195
195
|
"Group" => lambda {|it| it['group'] ? it['group']['name'] : 'Shared' },
|
@@ -242,7 +242,7 @@ class Morpheus::Cli::NetworksCommand
|
|
242
242
|
subnet_rows = subnets.collect { |subnet|
|
243
243
|
{
|
244
244
|
id: subnet['id'],
|
245
|
-
name: " #{subnet['name']}",
|
245
|
+
name: " #{subnet['displayName'] || subnet['name']}",
|
246
246
|
# type: subnet['type'] ? subnet['type']['name'] : '',
|
247
247
|
type: "Subnet",
|
248
248
|
cloud: network['zone'] ? network['zone']['name'] : '',
|
@@ -106,14 +106,12 @@ EOT
|
|
106
106
|
if json_response['applianceUrl']
|
107
107
|
appliance[:appliance_url] = json_response['applianceUrl']
|
108
108
|
end
|
109
|
-
#
|
110
|
-
if appliance[:build_version] && appliance[:status].nil?
|
111
|
-
appliance[:status] = 'ready'
|
112
|
-
end
|
113
|
-
# update setupNeeded?
|
109
|
+
# setupNeeded?
|
114
110
|
if json_response['setupNeeded'] == true
|
115
111
|
# appliance[:setup_needed] = true
|
116
112
|
appliance[:status] = 'fresh'
|
113
|
+
else
|
114
|
+
appliance[:status] = 'ready'
|
117
115
|
end
|
118
116
|
# if took_sec
|
119
117
|
# appliance[:last_check] ||= {}
|
@@ -511,7 +511,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
511
511
|
policy_type_option_types = policy_type['optionTypes']
|
512
512
|
# puts "POLICY OPTION TYPES:\n #{policy_type_option_types.inspect}"
|
513
513
|
if policy_type_option_types
|
514
|
-
config_prompt = Morpheus::Cli::OptionTypes.prompt(policy_type_option_types, options, @api_client)
|
514
|
+
config_prompt = Morpheus::Cli::OptionTypes.prompt(policy_type_option_types, options, @api_client, {}, false, true, true)
|
515
515
|
# everything should be under fieldContext:'config'
|
516
516
|
# payload['policy'].deep_merge!(config_prompt)
|
517
517
|
if config_prompt['config']
|
@@ -69,6 +69,7 @@ class Morpheus::Cli::ProvisioningSettingsCommand
|
|
69
69
|
"Hide Datastore Stats On Selection" => lambda {|it| format_boolean(it['hideDatastoreStats'])},
|
70
70
|
"Cross-Tenant Naming Policies" => lambda {|it| format_boolean(it['crossTenantNamingPolicies'])},
|
71
71
|
"Reuse Naming Sequence Numbers" => lambda {|it| format_boolean(it['reuseSequence'])},
|
72
|
+
"Show Console Keyboard Layout Settings" => lambda {|it| format_boolean(it['showConsoleKeyboardSettings'])},
|
72
73
|
"Deployment Archive Store" => lambda {|it| it['deployStorageProvider'] ? it['deployStorageProvider']['name'] : nil},
|
73
74
|
# Cloud-Init Settings
|
74
75
|
"Cloud-Init Username" => lambda {|it| it['cloudInitUsername']},
|
@@ -102,7 +102,7 @@ EOT
|
|
102
102
|
"URL" => lambda {|it| it[:url] || it[:host] },
|
103
103
|
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
104
104
|
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : '' },
|
105
|
-
"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
105
|
+
#"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
106
106
|
"Secure" => lambda {|it| format_boolean(it[:insecure] != true && (it[:url] || it[:host]).to_s.include?("https")) },
|
107
107
|
"Active" => lambda {|it| it[:active] ? "Yes " + format_is_current() : "No" },
|
108
108
|
#"Authenticated" => lambda {|it| format_boolean it[:authenticated] },
|
@@ -336,7 +336,7 @@ EOT
|
|
336
336
|
print cyan,"Added remote #{new_appliance_name}, status is #{format_appliance_status(appliance)}",reset,"\n"
|
337
337
|
end
|
338
338
|
|
339
|
-
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
339
|
+
#appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
340
340
|
# if !options[:quiet]
|
341
341
|
# print cyan
|
342
342
|
# puts "Status: #{format_appliance_status(appliance)}"
|
@@ -390,7 +390,8 @@ EOT
|
|
390
390
|
end
|
391
391
|
|
392
392
|
end
|
393
|
-
|
393
|
+
# refresh to get buildVersion now that we are logged in
|
394
|
+
appliance, json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
394
395
|
else
|
395
396
|
#puts "Status is #{format_appliance_status(appliance)}"
|
396
397
|
end
|
@@ -1278,7 +1279,7 @@ EOT
|
|
1278
1279
|
"URL" => lambda {|it| it[:url] || it[:host] },
|
1279
1280
|
#"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
1280
1281
|
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : '' },
|
1281
|
-
"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
1282
|
+
#"Appliance URL" => lambda {|it| it[:appliance_url] ? "#{it[:appliance_url]}" : '' },
|
1282
1283
|
"Secure" => lambda {|it| format_appliance_secure(it) },
|
1283
1284
|
"Active" => lambda {|it| it[:active] ? "Yes " + format_is_current() : "No" },
|
1284
1285
|
# "Active" => lambda {|it| format_boolean(it[:active]) },
|
@@ -1696,7 +1697,10 @@ EOT
|
|
1696
1697
|
# wtf, no url...
|
1697
1698
|
return appliance, json_response
|
1698
1699
|
else
|
1699
|
-
|
1700
|
+
# access token is needed for buildVersion
|
1701
|
+
wallet = Morpheus::Cli::Credentials.new(app_name, appliance_url).load_saved_credentials()
|
1702
|
+
setup_interface = Morpheus::SetupInterface.new({url:appliance_url, verify_ssl: !appliance[:insecure], timeout: timeout,
|
1703
|
+
access_token: (wallet && wallet['access_token']) ? wallet['access_token'] : nil})
|
1700
1704
|
start_time = Time.now
|
1701
1705
|
begin
|
1702
1706
|
json_response = setup_interface.check(params)
|
@@ -1734,17 +1738,19 @@ EOT
|
|
1734
1738
|
appliance[:last_check][:took] = (took_sec.to_f*1000).round
|
1735
1739
|
end
|
1736
1740
|
if json_response
|
1737
|
-
if json_response.key?('applianceUrl')
|
1738
|
-
|
1739
|
-
end
|
1740
|
-
if json_response
|
1741
|
-
appliance[:build_version] = json_response['buildVersion']
|
1741
|
+
# if json_response.key?('applianceUrl')
|
1742
|
+
# appliance[:appliance_url] = json_response['applianceUrl']
|
1743
|
+
# end
|
1744
|
+
if json_response['success'] == true
|
1742
1745
|
appliance[:status] = 'ready'
|
1743
1746
|
appliance[:last_check][:success] = true
|
1744
1747
|
# consider bumping this after every successful api command
|
1745
1748
|
appliance[:last_success_at] = Time.now.to_i
|
1746
1749
|
appliance.delete(:error)
|
1747
1750
|
end
|
1751
|
+
if !json_response['buildVersion'].to_s.empty?
|
1752
|
+
appliance[:build_version] = json_response['buildVersion']
|
1753
|
+
end
|
1748
1754
|
if json_response.key?('setupNeeded')
|
1749
1755
|
if json_response['setupNeeded'] == true
|
1750
1756
|
appliance[:setup_needed] = true
|
@@ -855,7 +855,7 @@ class Morpheus::Cli::SecurityGroups
|
|
855
855
|
|
856
856
|
end
|
857
857
|
|
858
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'sourceType', 'fieldLabel' => 'Source Type', 'type' => 'select', 'optionSource' => 'securityGroupSourceType', 'required' => true, 'defaultValue' => 'cidr'}], options[:options], @api_client)
|
858
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'sourceType', 'fieldLabel' => 'Source Type', 'type' => 'select', 'optionSource' => 'securityGroupSourceType', 'required' => true, 'defaultValue' => 'cidr'}], options[:options], @api_client, {'rule.securityGroupId': security_group['id'], 'securityGroupRule.direction': payload['rule']['direction']})
|
859
859
|
payload['rule']['sourceType'] = v_prompt['sourceType'] unless v_prompt['sourceType'].nil?
|
860
860
|
|
861
861
|
if payload['rule']['sourceType'] == 'cidr'
|
@@ -869,7 +869,7 @@ class Morpheus::Cli::SecurityGroups
|
|
869
869
|
payload['rule']['sourceTier'] = {"id" => v_prompt['sourceTier']} unless v_prompt['sourceTier'].nil?
|
870
870
|
end
|
871
871
|
|
872
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'destinationType', 'fieldLabel' => 'Destination Type', 'type' => 'select', 'optionSource' => 'securityGroupDestinationType', 'required' => true, 'defaultValue' => 'instance'}], options[:options], @api_client)
|
872
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'destinationType', 'fieldLabel' => 'Destination Type', 'type' => 'select', 'optionSource' => 'securityGroupDestinationType', 'required' => true, 'defaultValue' => 'instance'}], options[:options], @api_client, {'rule.securityGroupId': security_group['id'], 'securityGroupRule.direction': payload['rule']['direction']})
|
873
873
|
payload['rule']['destinationType'] = v_prompt['destinationType'] unless v_prompt['destinationType'].nil?
|
874
874
|
|
875
875
|
if payload['rule']['destinationType'] == 'cidr'
|
@@ -575,7 +575,7 @@ class Morpheus::Cli::ServicePlanCommand
|
|
575
575
|
options[:provisionType] = options[:provisionType] || (args.count > 1 ? args[1] : nil)
|
576
576
|
|
577
577
|
if !options[:provisionType].nil?
|
578
|
-
provision_types = @service_plans_interface.provision_types()['provisionTypes']
|
578
|
+
provision_types = @service_plans_interface.provision_types({max: 10000})['provisionTypes']
|
579
579
|
provision_type = provision_types.find {|it| it['name'] == options[:provisionType] || it['code'] == options[:provisionType] || it['id'] == options[:provisionType].to_i}
|
580
580
|
|
581
581
|
if provision_type.nil?
|
@@ -95,7 +95,7 @@ EOT
|
|
95
95
|
# my_terminal.execute("setup needed?")
|
96
96
|
# theres a bug here with --remote-url :status == "unknown"
|
97
97
|
# but hey, we got json back, so set status to "ready"
|
98
|
-
if appliance_status_json
|
98
|
+
if appliance_status_json
|
99
99
|
@remote_appliance[:status] == 'ready'
|
100
100
|
end
|
101
101
|
remote_status_string = format_appliance_status(@remote_appliance, cyan)
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::Snapshots
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
|
6
|
+
set_command_name :snapshots
|
7
|
+
set_command_description "View or remove snapshot"
|
8
|
+
register_subcommands :get, :remove
|
9
|
+
|
10
|
+
alias_subcommand :details, :get
|
11
|
+
set_default_subcommand :get
|
12
|
+
|
13
|
+
def connect(opts)
|
14
|
+
@api_client = establish_remote_appliance_connection(opts)
|
15
|
+
@snapshots_interface = @api_client.snapshots
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle(args)
|
19
|
+
handle_subcommand(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(args)
|
23
|
+
options = {}
|
24
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
25
|
+
opts.banner = subcommand_usage("[id]")
|
26
|
+
opts.footer = "Get Snapshot details." + "\n" +
|
27
|
+
"[snapshotId] is required. This is the id of the snapshot."
|
28
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
29
|
+
end
|
30
|
+
optparse.parse!(args)
|
31
|
+
if args.count < 1
|
32
|
+
puts_error "[id] argument is required"
|
33
|
+
puts_error optparse
|
34
|
+
return 1
|
35
|
+
end
|
36
|
+
|
37
|
+
connect(options)
|
38
|
+
id_list = parse_id_list(args)
|
39
|
+
|
40
|
+
return run_command_for_each_arg(id_list) do |arg|
|
41
|
+
_get(arg, options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def _get(arg, options)
|
46
|
+
begin
|
47
|
+
|
48
|
+
@snapshots_interface.setopts(options)
|
49
|
+
if options[:dry_run]
|
50
|
+
print_dry_run @snapshots_interface.dry.get(arg.to_i)
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
json_response = @snapshots_interface.get(arg.to_i)
|
55
|
+
if options[:json]
|
56
|
+
puts as_json(json_response, options, "snapshot")
|
57
|
+
return 0
|
58
|
+
elsif options[:yaml]
|
59
|
+
puts as_yaml(json_response, options, "snapshot")
|
60
|
+
return 0
|
61
|
+
end
|
62
|
+
|
63
|
+
if options[:csv]
|
64
|
+
puts records_as_csv([json_response['snapshot']], options)
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
snapshot = json_response['snapshot']
|
68
|
+
|
69
|
+
print_h1 "Snapshot Details"
|
70
|
+
print cyan
|
71
|
+
description_cols = {
|
72
|
+
"ID" => 'id',
|
73
|
+
"Name" => 'name',
|
74
|
+
"Description" => 'description',
|
75
|
+
"External Id" => 'externalId',
|
76
|
+
"Status" => 'status',
|
77
|
+
"State" => 'state',
|
78
|
+
"Snapshot Type" => 'snapshotType',
|
79
|
+
"Snapshot Created" => 'snapshotCreated',
|
80
|
+
"Cloud" => 'zone.name',
|
81
|
+
"Datastore" => 'datastore',
|
82
|
+
"Parent Snapshot" => 'parentSnapshot',
|
83
|
+
"Active" => 'currentlyActive',
|
84
|
+
"Date Created" => 'dateCreated'
|
85
|
+
}
|
86
|
+
print_description_list(description_cols, snapshot)
|
87
|
+
|
88
|
+
print reset, "\n"
|
89
|
+
|
90
|
+
return 0
|
91
|
+
rescue RestClient::Exception => e
|
92
|
+
print_rest_exception(e, options)
|
93
|
+
return 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def remove(args)
|
98
|
+
options = {}
|
99
|
+
instance = nil
|
100
|
+
snapshot_id = nil
|
101
|
+
|
102
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
103
|
+
opts.banner = subcommand_usage("[instance]")
|
104
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
105
|
+
opts.footer = "Remove/Delete a snapshot." + "\n" +
|
106
|
+
"[snapshotId] is required. This is the id of the snapshot to delete."
|
107
|
+
end
|
108
|
+
|
109
|
+
optparse.parse!(args)
|
110
|
+
if args.count != 1
|
111
|
+
raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
|
112
|
+
end
|
113
|
+
snapshot_id = args[0].to_i
|
114
|
+
connect(options)
|
115
|
+
begin
|
116
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove a snapshot?", options)
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
|
120
|
+
payload = {}
|
121
|
+
if options[:dry_run]
|
122
|
+
print_dry_run @snapshots_interface.dry.remove(snapshot_id, payload)
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
json_response = @snapshots_interface.remove(snapshot_id, payload)
|
127
|
+
if options[:json]
|
128
|
+
puts as_json(json_response, options)
|
129
|
+
else
|
130
|
+
print_green_success "Snapshot delete initiated."
|
131
|
+
end
|
132
|
+
return 0
|
133
|
+
|
134
|
+
rescue RestClient::Exception => e
|
135
|
+
print_rest_exception(e, options)
|
136
|
+
exit 1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -179,7 +179,7 @@ class Morpheus::Cli::Tasks
|
|
179
179
|
task_option_config = {}
|
180
180
|
task_option_columns = []
|
181
181
|
task_type['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |optionType|
|
182
|
-
if optionType['
|
182
|
+
if optionType['code'] == 'script'
|
183
183
|
script_content = task['taskOptions'][optionType['fieldName']]
|
184
184
|
elsif optionType['fieldName'] == 'httpHeaders' || optionType['fieldName'] == 'webHeaders'
|
185
185
|
http_headers = task['taskOptions']['httpHeaders'] || task['taskOptions']['webHeaders']
|
@@ -553,11 +553,11 @@ class Morpheus::Cli::Tasks
|
|
553
553
|
payload['task']['retryCount'] = v_prompt['retryCount'].to_i unless v_prompt['retryCount'].nil?
|
554
554
|
end
|
555
555
|
# Retry Delay
|
556
|
-
if options[:options]['
|
557
|
-
payload['task']['
|
556
|
+
if options[:options]['retryDelaySeconds']
|
557
|
+
payload['task']['retryDelaySeconds'] = options[:options]['retryDelaySeconds'].to_i
|
558
558
|
else
|
559
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => '
|
560
|
-
payload['task']['
|
559
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'retryDelaySeconds', 'fieldLabel' => 'Retry Delay', 'type' => 'number', 'defaultValue' => 10}], options[:options], @api_client)
|
560
|
+
payload['task']['retryDelaySeconds'] = v_prompt['retryDelaySeconds'].to_i unless v_prompt['retryDelaySeconds'].nil?
|
561
561
|
end
|
562
562
|
end
|
563
563
|
|