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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +4 -1
  3. data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
  4. data/lib/morpheus/api/instances_interface.rb +28 -0
  5. data/lib/morpheus/api/ping_interface.rb +2 -0
  6. data/lib/morpheus/api/setup_interface.rb +4 -0
  7. data/lib/morpheus/api/snapshots_interface.rb +19 -0
  8. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
  9. data/lib/morpheus/cli/commands/clusters.rb +59 -46
  10. data/lib/morpheus/cli/commands/hosts.rb +12 -0
  11. data/lib/morpheus/cli/commands/instances.rb +250 -1
  12. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
  13. data/lib/morpheus/cli/commands/network_static_routes_command.rb +5 -0
  14. data/lib/morpheus/cli/commands/networks_command.rb +2 -2
  15. data/lib/morpheus/cli/commands/ping.rb +3 -5
  16. data/lib/morpheus/cli/commands/policies_command.rb +1 -1
  17. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
  18. data/lib/morpheus/cli/commands/remote.rb +16 -10
  19. data/lib/morpheus/cli/commands/security_groups.rb +2 -2
  20. data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
  21. data/lib/morpheus/cli/commands/setup.rb +1 -1
  22. data/lib/morpheus/cli/commands/snapshots.rb +139 -0
  23. data/lib/morpheus/cli/commands/tasks.rb +5 -5
  24. data/lib/morpheus/cli/commands/user_settings_command.rb +1 -1
  25. data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
  26. data/lib/morpheus/cli/mixins/provisioning_helper.rb +80 -0
  27. data/lib/morpheus/cli/option_types.rb +26 -11
  28. data/lib/morpheus/cli/version.rb +1 -1
  29. 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, :import_snapshot, :snapshot, :snapshots,
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
- # set status to ready if we have a version but no status yet for some reason
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
- setup_interface = Morpheus::SetupInterface.new({url:appliance_url, verify_ssl: !appliance[:insecure], timeout: timeout})
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
- appliance[:appliance_url] = json_response['applianceUrl']
1739
- end
1740
- if json_response.key?('buildVersion')
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 && appliance_status_json['setupNeeded'] == false
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['fieldLabel'].to_s.downcase == 'script'
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]['retryDelay']
557
- payload['task']['retryDelay'] = options[:options]['retryDelay'].to_i
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' => 'retryDelay', 'fieldLabel' => 'Retry Delay', 'type' => 'number', 'defaultValue' => 10}], options[:options], @api_client)
560
- payload['task']['retryDelay'] = v_prompt['retryDelay'].to_i unless v_prompt['retryDelay'].nil?
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