morpheus-cli 5.4.0 → 5.4.3.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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/account_users_interface.rb +68 -0
  4. data/lib/morpheus/api/api_client.rb +55 -10
  5. data/lib/morpheus/api/audit_interface.rb +9 -0
  6. data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
  7. data/lib/morpheus/api/instances_interface.rb +49 -0
  8. data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
  9. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  10. data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
  11. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
  12. data/lib/morpheus/api/load_balancers_interface.rb +5 -0
  13. data/lib/morpheus/api/network_routers_interface.rb +9 -0
  14. data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
  15. data/lib/morpheus/api/ping_interface.rb +2 -0
  16. data/lib/morpheus/api/read_interface.rb +4 -3
  17. data/lib/morpheus/api/rest_interface.rb +3 -3
  18. data/lib/morpheus/api/secondary_read_interface.rb +1 -1
  19. data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
  20. data/lib/morpheus/api/setup_interface.rb +4 -0
  21. data/lib/morpheus/api/snapshots_interface.rb +19 -0
  22. data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
  23. data/lib/morpheus/api/storage_servers_interface.rb +9 -0
  24. data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
  25. data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
  26. data/lib/morpheus/api/users_interface.rb +16 -63
  27. data/lib/morpheus/cli/cli_command.rb +253 -5
  28. data/lib/morpheus/cli/cli_registry.rb +1 -1
  29. data/lib/morpheus/cli/commands/alias_command.rb +1 -1
  30. data/lib/morpheus/cli/commands/apps.rb +14 -78
  31. data/lib/morpheus/cli/commands/audit.rb +188 -0
  32. data/lib/morpheus/cli/commands/blueprints_command.rb +1 -1
  33. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
  34. data/lib/morpheus/cli/commands/change_password_command.rb +4 -4
  35. data/lib/morpheus/cli/commands/clusters.rb +96 -58
  36. data/lib/morpheus/cli/commands/hosts.rb +27 -15
  37. data/lib/morpheus/cli/commands/image_builder_command.rb +4 -8
  38. data/lib/morpheus/cli/commands/instances.rb +359 -3
  39. data/lib/morpheus/cli/commands/integrations_command.rb +1 -12
  40. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
  41. data/lib/morpheus/cli/commands/load_balancer_monitors.rb +70 -0
  42. data/lib/morpheus/cli/commands/load_balancer_pools.rb +29 -50
  43. data/lib/morpheus/cli/commands/load_balancer_profiles.rb +64 -0
  44. data/lib/morpheus/cli/commands/load_balancer_types.rb +9 -4
  45. data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +69 -58
  46. data/lib/morpheus/cli/commands/load_balancers.rb +109 -6
  47. data/lib/morpheus/cli/commands/network_firewalls_command.rb +22 -5
  48. data/lib/morpheus/cli/commands/network_routers_command.rb +96 -45
  49. data/lib/morpheus/cli/commands/network_static_routes_command.rb +451 -0
  50. data/lib/morpheus/cli/commands/network_transport_zones_command.rb +4 -4
  51. data/lib/morpheus/cli/commands/networks_command.rb +2 -2
  52. data/lib/morpheus/cli/commands/open_command.rb +30 -0
  53. data/lib/morpheus/cli/commands/options.rb +98 -0
  54. data/lib/morpheus/cli/commands/ping.rb +3 -5
  55. data/lib/morpheus/cli/commands/policies_command.rb +2 -2
  56. data/lib/morpheus/cli/commands/prices_command.rb +7 -7
  57. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
  58. data/lib/morpheus/cli/commands/remote.rb +20 -12
  59. data/lib/morpheus/cli/commands/roles.rb +1 -1
  60. data/lib/morpheus/cli/commands/security_groups.rb +2 -2
  61. data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
  62. data/lib/morpheus/cli/commands/setup.rb +1 -1
  63. data/lib/morpheus/cli/commands/shell.rb +2 -2
  64. data/lib/morpheus/cli/commands/snapshots.rb +139 -0
  65. data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
  66. data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
  67. data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
  68. data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
  69. data/lib/morpheus/cli/commands/tasks.rb +5 -5
  70. data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
  71. data/lib/morpheus/cli/commands/user_groups_command.rb +1 -1
  72. data/lib/morpheus/cli/commands/user_settings_command.rb +3 -2
  73. data/lib/morpheus/cli/commands/user_sources_command.rb +1 -1
  74. data/lib/morpheus/cli/commands/users.rb +28 -28
  75. data/lib/morpheus/cli/commands/view.rb +102 -0
  76. data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
  77. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
  78. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
  79. data/lib/morpheus/cli/mixins/print_helper.rb +50 -18
  80. data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
  81. data/lib/morpheus/cli/mixins/provisioning_helper.rb +96 -6
  82. data/lib/morpheus/cli/mixins/rest_command.rb +148 -74
  83. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +174 -82
  84. data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
  85. data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
  86. data/lib/morpheus/cli/option_types.rb +95 -28
  87. data/lib/morpheus/cli/version.rb +1 -1
  88. data/lib/morpheus/cli.rb +1 -0
  89. data/lib/morpheus/ext/string.rb +29 -6
  90. data/lib/morpheus/routes.rb +238 -0
  91. data/lib/morpheus/util.rb +6 -1
  92. metadata +26 -2
@@ -22,7 +22,7 @@ class Morpheus::Cli::Hosts
22
22
  def connect(opts)
23
23
  @api_client = establish_remote_appliance_connection(opts)
24
24
  @accounts_interface = @api_client.accounts
25
- @users_interface = @api_client.users
25
+ @account_users_interface = @api_client.account_users
26
26
  @clouds_interface = @api_client.clouds
27
27
  @options_interface = @api_client.options
28
28
  @tasks_interface = @api_client.tasks
@@ -81,25 +81,25 @@ class Morpheus::Cli::Hosts
81
81
  opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
82
82
  params['planCode'] = parse_id_list(val)
83
83
  end
84
- opts.on( '', '--vm', "Show only virtual machines" ) do |val|
84
+ opts.on('--vm', "Show only virtual machines" ) do
85
85
  params[:vm] = true
86
86
  end
87
- opts.on( '', '--hypervisor', "Show only VM Hypervisors" ) do |val|
87
+ opts.on('--hypervisor', "Show only VM Hypervisors" ) do
88
88
  params[:vmHypervisor] = true
89
89
  end
90
- opts.on( '', '--container', "Show only Container Hypervisors" ) do |val|
90
+ opts.on('--container', "Show only Container Hypervisors" ) do
91
91
  params[:containerHypervisor] = true
92
92
  end
93
- opts.on( '', '--baremetal', "Show only Baremetal Servers" ) do |val|
93
+ opts.on('--baremetal', "Show only Baremetal Servers" ) do
94
94
  params[:bareMetalHost] = true
95
95
  end
96
- opts.on( '', '--status STATUS', "Filter by Status" ) do |val|
96
+ opts.on('--status STATUS', String, "Filter by Status" ) do |val|
97
97
  params[:status] = val
98
98
  end
99
- opts.on( '', '--agent', "Show only Servers with the agent installed" ) do |val|
99
+ opts.on('--agent', "Show only Servers with the agent installed" ) do
100
100
  params[:agentInstalled] = true
101
101
  end
102
- opts.on( '', '--noagent', "Show only Servers with No agent" ) do |val|
102
+ opts.on('--noagent', "Show only Servers with No agent" ) do
103
103
  params[:agentInstalled] = false
104
104
  end
105
105
  opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
@@ -374,25 +374,25 @@ class Morpheus::Cli::Hosts
374
374
  opts.on( '-i', '--ip IPADDRESS', "Filter by IP Address" ) do |val|
375
375
  params[:ip] = val
376
376
  end
377
- opts.on( '', '--vm', "Show only virtual machines" ) do |val|
377
+ opts.on('--vm', "Show only virtual machines" ) do
378
378
  params[:vm] = true
379
379
  end
380
- opts.on( '', '--hypervisor', "Show only VM Hypervisors" ) do |val|
380
+ opts.on('--hypervisor', "Show only VM Hypervisors" ) do
381
381
  params[:vmHypervisor] = true
382
382
  end
383
- opts.on( '', '--container', "Show only Container Hypervisors" ) do |val|
383
+ opts.on('--container', "Show only Container Hypervisors" ) do
384
384
  params[:containerHypervisor] = true
385
385
  end
386
- opts.on( '', '--baremetal', "Show only Baremetal Servers" ) do |val|
386
+ opts.on('--baremetal', "Show only Baremetal Servers" ) do
387
387
  params[:bareMetalHost] = true
388
388
  end
389
- opts.on( '', '--status STATUS', "Filter by Status" ) do |val|
389
+ opts.on('--status STATUS', "Filter by Status" ) do |val|
390
390
  params[:status] = val
391
391
  end
392
- opts.on( '', '--agent', "Show only Servers with the agent installed" ) do |val|
392
+ opts.on('--agent', "Show only Servers with the agent installed" ) do
393
393
  params[:agentInstalled] = true
394
394
  end
395
- opts.on( '', '--noagent', "Show only Servers with No agent" ) do |val|
395
+ opts.on('--noagent', "Show only Servers with No agent" ) do
396
396
  params[:agentInstalled] = false
397
397
  end
398
398
  opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
@@ -878,6 +878,12 @@ class Morpheus::Cli::Hosts
878
878
  payload['volumes'] = volumes
879
879
  end
880
880
 
881
+ # plan customizations
882
+ plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {})
883
+ if plan_opts && !plan_opts.empty?
884
+ payload['servicePlanOptions'] = plan_opts
885
+ end
886
+
881
887
  # prompt for network interfaces (if supported)
882
888
  if server_type["provisionType"] && server_type["provisionType"]["id"] && server_type["provisionType"]["hasNetworks"]
883
889
  begin
@@ -1252,6 +1258,12 @@ class Morpheus::Cli::Hosts
1252
1258
  payload[:volumes] = volumes
1253
1259
  end
1254
1260
 
1261
+ # plan customizations
1262
+ plan_opts = prompt_service_plan_options(service_plan, options, @api_client, {}, server)
1263
+ if plan_opts && !plan_opts.empty?
1264
+ payload['servicePlanOptions'] = plan_opts
1265
+ end
1266
+
1255
1267
  # todo: reconfigure networks
1256
1268
  # need to get provision_type_id for network info
1257
1269
  # prompt for network interfaces (if supported)
@@ -1065,20 +1065,16 @@ class Morpheus::Cli::ImageBuilderCommand
1065
1065
  preseed_script_id = nil
1066
1066
  if options['preseedScript']
1067
1067
  preseed_script = find_preseed_script(options['preseedScript'])
1068
- if !preseed_script
1069
- print_red_alert "Preseed Script not found: #{options['preseedScript']}"
1070
- return false
1068
+ if preseed_script
1069
+ preseed_script_id = preseed_script['id']
1071
1070
  end
1072
- preseed_script_id = preseed_script['id']
1073
1071
  else
1074
1072
  preseed_script_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'preseedScript', 'type' => 'select', 'fieldLabel' => 'Preseed Script', 'selectOptions' => get_available_preseed_scripts(), 'required' => false, 'description' => 'Select Preseed Script.', 'defaultValue' => default_values['preseedScript'], :fmt=>:natural}],options,api_client,{})
1075
1073
  # preseed_script_id = preseed_script_prompt['preseedScript']
1076
1074
  preseed_script = find_preseed_script(preseed_script_prompt['preseedScript'])
1077
- if !preseed_script
1078
- print_red_alert "Preseed Script not found: '#{preseed_script_prompt['preseedScript']}'"
1079
- return false
1075
+ if preseed_script
1076
+ preseed_script_id = preseed_script['id']
1080
1077
  end
1081
- preseed_script_id = preseed_script['id']
1082
1078
  end
1083
1079
  if preseed_script_id
1084
1080
  # payload['preseedScript'] = preseed_script_id
@@ -17,12 +17,14 @@ 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,
24
25
  {:exec => :execution_request},
25
- :deploys
26
+ :deploys,
27
+ :refresh, :apply
26
28
  #register_subcommands :firewall_disable, :firewall_enable
27
29
  # register_subcommands {:'lb-update' => :load_balancer_update}
28
30
  alias_subcommand :details, :get
@@ -35,7 +37,7 @@ class Morpheus::Cli::Instances
35
37
  def connect(opts)
36
38
  @api_client = establish_remote_appliance_connection(opts)
37
39
  @accounts_interface = @api_client.accounts
38
- @users_interface = @api_client.users
40
+ @account_users_interface = @api_client.account_users
39
41
  @instances_interface = @api_client.instances
40
42
  @task_sets_interface = @api_client.task_sets
41
43
  @logs_interface = @api_client.logs
@@ -51,6 +53,7 @@ class Morpheus::Cli::Instances
51
53
  @execution_request_interface = @api_client.execution_request
52
54
  @deploy_interface = @api_client.deploy
53
55
  @deployments_interface = @api_client.deployments
56
+ @snapshots_interface = @api_client.snapshots
54
57
  end
55
58
 
56
59
  def handle(args)
@@ -77,6 +80,12 @@ class Morpheus::Cli::Instances
77
80
  opts.on( '--created-by USER', "Alias for --owner" ) do |val|
78
81
  options[:owner] = val
79
82
  end
83
+ opts.on('--agent', "Show only Instances with the agent installed" ) do
84
+ params[:agentInstalled] = true
85
+ end
86
+ opts.on('--noagent', "Show only Instances with No agent" ) do
87
+ params[:agentInstalled] = false
88
+ end
80
89
  opts.add_hidden_option('--created-by')
81
90
  opts.on('--status STATUS', "Filter by status i.e. provisioning,running,starting,stopping") do |val|
82
91
  params['status'] = (params['status'] || []) + val.to_s.split(',').collect {|s| s.strip }.select {|s| s != "" }
@@ -2711,6 +2720,12 @@ class Morpheus::Cli::Instances
2711
2720
  payload["volumes"] = volumes
2712
2721
  end
2713
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
+
2714
2729
  # only amazon supports this option
2715
2730
  # for now, always do this
2716
2731
  payload["deleteOriginalVolumes"] = true
@@ -3354,6 +3369,223 @@ EOT
3354
3369
  end
3355
3370
  end
3356
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
+
3357
3589
 
3358
3590
  def scaling(args)
3359
3591
  options = {}
@@ -4126,6 +4358,9 @@ EOT
4126
4358
  opts.on( '--name VALUE', String, "Image Name (Template Name). Default is server name + timestamp" ) do |val|
4127
4359
  options[:options]['templateName'] = val
4128
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
4129
4364
  build_standard_update_options(opts, options)
4130
4365
  opts.footer = <<-EOT
4131
4366
  Clone to image (template) for an instance
@@ -4137,6 +4372,18 @@ EOT
4137
4372
  connect(options)
4138
4373
  instance = find_instance_by_name_or_id(args[0])
4139
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
4140
4387
  payload = {}
4141
4388
  if options[:payload]
4142
4389
  payload = options[:payload]
@@ -4149,6 +4396,15 @@ EOT
4149
4396
  payload['templateName'] = v_prompt['templateName']
4150
4397
  end
4151
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
4152
4408
  end
4153
4409
  @instances_interface.setopts(options)
4154
4410
  if options[:dry_run]
@@ -4230,6 +4486,106 @@ EOT
4230
4486
  return 0, nil
4231
4487
  end
4232
4488
 
4489
+ def refresh(args)
4490
+ params, payload, options = {}, {}, {}
4491
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
4492
+ opts.banner = subcommand_usage("[instance] [options]")
4493
+ build_standard_update_options(opts, options, [:auto_confirm])
4494
+ opts.footer = <<-EOT
4495
+ Refresh an instance.
4496
+ [instance] is required. This is the name or id of an instance.
4497
+ This is only supported by certain types of instances such as terraform.
4498
+ EOT
4499
+ end
4500
+ optparse.parse!(args)
4501
+ verify_args!(args:args, optparse:optparse, count:1)
4502
+ connect(options)
4503
+
4504
+ begin
4505
+ instance = find_instance_by_name_or_id(args[0])
4506
+ return 1 if instance.nil?
4507
+ # construct request
4508
+ params.merge!(parse_query_options(options))
4509
+ payload = {}
4510
+ if options[:payload]
4511
+ payload = options[:payload]
4512
+ payload.deep_merge!(parse_passed_options(options))
4513
+ else
4514
+ payload.deep_merge!(parse_passed_options(options))
4515
+ # raise_command_error "Specify at least one option to update.\n#{optparse}" if payload.empty?
4516
+ end
4517
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to refresh this instance: #{instance['name']}?")
4518
+ return 9, "aborted command"
4519
+ end
4520
+ @instances_interface.setopts(options)
4521
+ if options[:dry_run]
4522
+ print_dry_run @instances_interface.dry.refresh(instance["id"], params, payload)
4523
+ return
4524
+ end
4525
+ json_response = @instances_interface.refresh(instance["id"], params, payload)
4526
+ render_response(json_response, options) do
4527
+ print_green_success "Refreshing instance #{instance['name']}"
4528
+ # return _get(instance['id'], options)
4529
+ end
4530
+ return 0, nil
4531
+ rescue RestClient::Exception => e
4532
+ print_rest_exception(e, options)
4533
+ exit 1
4534
+ end
4535
+ end
4536
+
4537
+ def apply(args)
4538
+ params, payload, options = {}, {}, {}
4539
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
4540
+ opts.banner = subcommand_usage("[instance] [options]")
4541
+ build_standard_update_options(opts, options, [:auto_confirm])
4542
+ opts.footer = <<-EOT
4543
+ Apply an instance.
4544
+ [instance] is required. This is the name or id of an instance.
4545
+ This is only supported by certain types of instances such as terraform.
4546
+ EOT
4547
+ end
4548
+ optparse.parse!(args)
4549
+ verify_args!(args:args, optparse:optparse, count:1)
4550
+ connect(options)
4551
+
4552
+ begin
4553
+ instance = find_instance_by_name_or_id(args[0])
4554
+ return 1 if instance.nil?
4555
+ # construct request
4556
+ params.merge!(parse_query_options(options))
4557
+ payload = {}
4558
+ if options[:payload]
4559
+ payload = options[:payload]
4560
+ payload.deep_merge!(parse_passed_options(options))
4561
+ else
4562
+ payload.deep_merge!(parse_passed_options(options))
4563
+ # raise_command_error "Specify at least one option to update.\n#{optparse}" if payload.empty?
4564
+ end
4565
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to apply this instance: #{instance['name']}?")
4566
+ return 9, "aborted command"
4567
+ end
4568
+ @instances_interface.setopts(options)
4569
+ if options[:dry_run]
4570
+ print_dry_run @instances_interface.dry.apply(instance["id"], params, payload)
4571
+ return
4572
+ end
4573
+ json_response = @instances_interface.apply(instance["id"], params, payload)
4574
+ render_response(json_response, options) do
4575
+ print_green_success "Applying instance #{instance['name']}"
4576
+ # return _get(instance['id'], options)
4577
+ end
4578
+ return 0, nil
4579
+ rescue RestClient::Exception => e
4580
+ print_rest_exception(e, options)
4581
+ exit 1
4582
+ end
4583
+ end
4584
+
4585
+ # todo: print state summary
4586
+ def state_summary(args)
4587
+ end
4588
+
4233
4589
  private
4234
4590
 
4235
4591
  def find_zone_by_name_or_id(group_id, val)
@@ -1122,19 +1122,8 @@ EOT
1122
1122
 
1123
1123
  def add_integration_object_option_types
1124
1124
  [
1125
- {'code' => 'integrationObject.type', 'shorthand' => '-t', 'switch' => 'type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'integrationObjectTypes', 'required' => true, 'description' => "Integration Object Type eg. cloud, layout, blueprint, catalog", 'displayOrder' => 1},
1125
+ {'code' => 'integrationObject.type', 'shorthand' => '-t', 'switch' => 'type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'integrationObjectTypes', 'required' => true, 'description' => "Integration Object Type eg. catalog", 'displayOrder' => 1},
1126
1126
  # {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'description' => 'Display Name of the integration object, default is the name of the referenced object', 'displayOrder' => 2},
1127
- {'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 3},
1128
- {'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'cloud', 'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Cloud', 'displayOrder' => 4},
1129
- {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'instance-type', 'fieldName' => 'instanceType', 'fieldLabel' => 'Instance Type', 'type' => 'select', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Instance Type', 'displayOrder' => 5},
1130
- {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'technology', 'fieldName' => 'zoneType', 'fieldLabel' => 'Cloud Type', 'type' => 'select', 'optionSource' => 'zoneTypes', 'required' => true, 'description' => 'Cloud Type (Technology)', 'displayOrder' => 5},
1131
- {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'layout', 'fieldName' => 'layout', 'fieldLabel' => 'Layout', 'type' => 'select', 'optionSource' => 'layouts', 'required' => true, 'description' => 'Layout', 'displayOrder' => 6},
1132
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'fieldName' => 'name', 'fieldLabel' => 'Catalog Item Name', 'type' => 'text', 'required' => true, 'description' => 'Display Name of the integration object', 'displayOrder' => 7},
1133
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'required' => true, 'description' => 'Blueprint', 'displayOrder' => 8, 'noParams' => true},
1134
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 9},
1135
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'default-cloud', 'fieldName' => 'defaultCloud', 'fieldLabel' => 'Default Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => false, 'description' => 'Default Cloud', 'displayOrder' => 10},
1136
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'environment', 'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'optionSource' => 'environments', 'required' => false, 'description' => 'Environment', 'displayOrder' => 11},
1137
- {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'config', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'Config JSON', 'displayOrder' => 12},
1138
1127
  {'dependsOnCode' => 'integrationObject.type:catalog', 'switch' => 'catalog', 'fieldName' => 'catalog', 'fieldLabel' => 'Catalog Item', 'type' => 'select', 'optionSource' => 'catalogItemTypes', 'required' => true, 'description' => 'Catalog Item', 'displayOrder' => 13},
1139
1128
  ]
1140
1129
  end
@@ -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
@@ -0,0 +1,70 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::LoadBalancerMonitors
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::RestCommand
6
+ include Morpheus::Cli::SecondaryRestCommand
7
+ include Morpheus::Cli::LoadBalancersHelper
8
+
9
+ set_command_description "View and manage load balancer monitors."
10
+ set_command_name :'load-balancer-monitors'
11
+ register_subcommands :list, :get, :add, :update, :remove
12
+ register_interfaces :load_balancer_monitors,
13
+ :load_balancers, :load_balancer_types
14
+
15
+ set_rest_parent_name :load_balancers
16
+
17
+ # set_rest_interface_name :load_balancer_monitors
18
+ # set_parent_rest_interface_name :load_balancers
19
+
20
+ # todo: a configurable way to load the optionTypes
21
+ # option_types = loadBalancer['monitorOptionTypes']
22
+ # set_rest_has_type true
23
+ # set_rest_type :load_balancer_virtual_server_types
24
+
25
+ protected
26
+
27
+ def load_balancer_monitor_list_column_definitions(options)
28
+ {
29
+ "ID" => 'id',
30
+ "Name" => 'name',
31
+ "Monitor Type" => lambda {|it| it['monitorTypeDisplay'] || it['monitorType'] },
32
+ }
33
+ end
34
+
35
+ def load_balancer_monitor_column_definitions(options)
36
+ {
37
+ "ID" => 'id',
38
+ "Name" => 'name',
39
+ "Load Balancer" => lambda {|it| it['loadBalancer'] ? it['loadBalancer']['name'] : '' },
40
+ "Description" => 'description',
41
+ "Monitor Type" => lambda {|it| it['monitorTypeDisplay'] || it['monitorType'] },
42
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
43
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
44
+ }
45
+ end
46
+
47
+ def load_balancer_monitor_object_key
48
+ 'loadBalancerMonitor'
49
+ end
50
+
51
+ def load_balancer_monitor_list_key
52
+ 'loadBalancerMonitors'
53
+ end
54
+
55
+ def load_balancer_monitor_label
56
+ 'Load Balancer Monitor'
57
+ end
58
+
59
+ def load_balancer_monitor_label_plural
60
+ 'Load Balancer Monitors'
61
+ end
62
+
63
+ def load_option_types_for_load_balancer_monitor(type_record, parent_record)
64
+ load_balancer = parent_record
65
+ load_balancer_type_id = load_balancer['type']['id']
66
+ load_balancer_type = find_by_id(:load_balancer_type, load_balancer_type_id)
67
+ load_balancer_type['monitorOptionTypes']
68
+ end
69
+
70
+ end