morpheus-cli 5.3.2.1 → 5.3.4

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/clouds_interface.rb +4 -11
  5. data/lib/morpheus/api/instances_interface.rb +18 -5
  6. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  7. data/lib/morpheus/api/load_balancer_profiles_interface.rb +10 -0
  8. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +4 -4
  9. data/lib/morpheus/api/network_routers_interface.rb +21 -0
  10. data/lib/morpheus/api/network_servers_interface.rb +42 -0
  11. data/lib/morpheus/api/rest_interface.rb +2 -1
  12. data/lib/morpheus/api/virtual_images_interface.rb +23 -2
  13. data/lib/morpheus/api/virtual_servers_interface.rb +9 -0
  14. data/lib/morpheus/cli/apps.rb +3 -2
  15. data/lib/morpheus/cli/cli_command.rb +14 -6
  16. data/lib/morpheus/cli/cli_registry.rb +55 -2
  17. data/lib/morpheus/cli/cloud_resource_pools_command.rb +170 -134
  18. data/lib/morpheus/cli/clouds.rb +22 -40
  19. data/lib/morpheus/cli/clusters.rb +51 -33
  20. data/lib/morpheus/cli/hosts.rb +0 -1
  21. data/lib/morpheus/cli/instances.rb +372 -150
  22. data/lib/morpheus/cli/invoices_command.rb +117 -133
  23. data/lib/morpheus/cli/library_cluster_layouts_command.rb +20 -0
  24. data/lib/morpheus/cli/library_option_lists_command.rb +3 -3
  25. data/lib/morpheus/cli/load_balancer_pools.rb +111 -0
  26. data/lib/morpheus/cli/load_balancer_virtual_servers.rb +136 -0
  27. data/lib/morpheus/cli/load_balancers.rb +0 -155
  28. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +2 -2
  29. data/lib/morpheus/cli/mixins/provisioning_helper.rb +155 -112
  30. data/lib/morpheus/cli/mixins/rest_command.rb +53 -37
  31. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +488 -0
  32. data/lib/morpheus/cli/monitoring_checks_command.rb +2 -0
  33. data/lib/morpheus/cli/network_routers_command.rb +291 -7
  34. data/lib/morpheus/cli/network_scopes_command.rb +442 -0
  35. data/lib/morpheus/cli/networks_command.rb +3 -3
  36. data/lib/morpheus/cli/option_parser.rb +25 -17
  37. data/lib/morpheus/cli/option_types.rb +42 -15
  38. data/lib/morpheus/cli/subnets_command.rb +7 -2
  39. data/lib/morpheus/cli/tasks.rb +25 -2
  40. data/lib/morpheus/cli/vdi_pools_command.rb +4 -1
  41. data/lib/morpheus/cli/version.rb +1 -1
  42. data/lib/morpheus/cli/virtual_images.rb +251 -29
  43. data/lib/morpheus/cli.rb +9 -1
  44. data/morpheus-cli.gemspec +1 -1
  45. metadata +11 -4
@@ -15,9 +15,10 @@ class Morpheus::Cli::Instances
15
15
 
16
16
  set_command_name :instances
17
17
  set_command_description "View and manage instances."
18
- register_subcommands :list, :count, :get, :view, :add, :update, :remove, :cancel_removal, :logs,
18
+ register_subcommands :list, :count, :get, :view, :add, :update, :remove,
19
+ :cancel_removal, :cancel_expiration, :cancel_shutdown, :extend_expiration, :extend_shutdown,
19
20
  :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details},
20
- :stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
21
+ :logs, :stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
21
22
  :backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
22
23
  :lock, :unlock, :clone_image,
23
24
  :security_groups, :apply_security_groups, :run_workflow, :import_snapshot, :snapshot, :snapshots,
@@ -444,7 +445,7 @@ class Morpheus::Cli::Instances
444
445
  opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
445
446
  options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
446
447
  end
447
- build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
448
+ build_standard_add_options(opts, options) #, [:options, :payload, :json, :dry_run, :remote, :quiet])
448
449
  opts.footer = "Create a new instance." + "\n" +
449
450
  "[name] is required. This is the new instance name." + "\n" +
450
451
  "The available options vary by --type."
@@ -462,33 +463,30 @@ class Morpheus::Cli::Instances
462
463
  options[:instance_name] = args[0]
463
464
  end
464
465
 
465
- begin
466
- payload = nil
467
- if options[:payload]
468
- payload = options[:payload]
469
- # support -O OPTION switch on top of --payload
470
- payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
471
- # obviously should support every option that prompt supports on top of -- payload as well
472
- # group, cloud and type for now
473
- # todo: also support :layout, service_plan, :resource_pool, etc.
474
- group = nil
475
- if options[:group]
476
- group = find_group_by_name_or_id_for_provisioning(options[:group])
477
- if group.nil?
478
- return 1, "group not found by #{options[:group]}"
479
- end
480
- #payload["siteId"] = group["id"]
481
- payload.deep_merge!({"instance" => {"site" => {"id" => group["id"]} } })
466
+ if options[:payload]
467
+ payload = options[:payload]
468
+ # support -O OPTION switch on top of --payload
469
+ payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
470
+ # obviously should support every option that prompt supports on top of -- payload as well
471
+ # group, cloud and type for now
472
+ # todo: also support :layout, service_plan, :resource_pool, etc.
473
+ group = nil
474
+ if options[:group]
475
+ group = find_group_by_name_or_id_for_provisioning(options[:group])
476
+ if group.nil?
477
+ return 1, "group not found by #{options[:group]}"
482
478
  end
483
- if options[:cloud]
484
- group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
485
- cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
486
- if cloud.nil?
487
- return 1, "cloud not found by #{options[:cloud]}"
488
- end
489
- payload["zoneId"] = cloud["id"]
490
- payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
479
+ payload.deep_merge!({"instance" => {"site" => {"id" => group["id"]} } })
480
+ end
481
+ if options[:cloud]
482
+ group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
483
+ cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
484
+ if cloud.nil?
485
+ return 1, "cloud not found by #{options[:cloud]}"
491
486
  end
487
+ payload["zoneId"] = cloud["id"]
488
+ payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
489
+ end
492
490
  if options[:cloud]
493
491
  group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
494
492
  cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
@@ -498,96 +496,90 @@ class Morpheus::Cli::Instances
498
496
  payload["zoneId"] = cloud["id"]
499
497
  payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
500
498
  end
501
- if options[:instance_type_code]
502
- # should just use find_instance_type_by_name_or_id
503
- # note that the api actually will match name name or code
504
- instance_type = (options[:instance_type_code].to_s =~ /\A\d{1,}\Z/) ? find_instance_type_by_id(options[:instance_type_code]) : find_instance_type_by_code(options[:instance_type_code])
505
- if instance_type.nil?
506
- return 1, "instance type not found by #{options[:cloud]}"
507
- end
508
- payload.deep_merge!({"instance" => {"type" => instance_type["code"] } })
509
- payload.deep_merge!({"instance" => {"instanceType" => {"code" => instance_type["code"]} } })
499
+ if options[:instance_type_code]
500
+ # should just use find_instance_type_by_name_or_id
501
+ # note that the api actually will match name name or code
502
+ instance_type = (options[:instance_type_code].to_s =~ /\A\d{1,}\Z/) ? find_instance_type_by_id(options[:instance_type_code]) : find_instance_type_by_code(options[:instance_type_code])
503
+ if instance_type.nil?
504
+ return 1, "instance type not found by #{options[:cloud]}"
510
505
  end
511
-
512
- else
513
- # use active group by default
514
- options[:group] ||= @active_group_id
515
- options[:select_datastore] = true
516
- options[:name_required] = true
517
- # prompt for all the instance configuration options
518
- # this provisioning helper method handles all (most) of the parsing and prompting
519
- # and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
520
- payload = prompt_new_instance(options)
521
- # clean payload of empty objects
522
- # note: this is temporary and should be fixed upstream in OptionTypes.prompt()
523
- if payload['instance'].is_a?(Hash)
524
- payload['instance'].keys.each do |k|
525
- v = payload['instance'][k]
526
- payload['instance'].delete(k) if v.is_a?(Hash) && v.empty?
527
- end
528
- end
529
- if payload['config'].is_a?(Hash)
530
- payload['config'].keys.each do |k|
531
- v = payload['config'][k]
532
- payload['config'].delete(k) if v.is_a?(Hash) && v.empty?
533
- end
534
- end
535
- end
536
- payload['instance'] ||= {}
537
- if options[:instance_name]
538
- payload['instance']['name'] = options[:instance_name]
539
- end
540
- if options[:description] && !payload['instance']['description']
541
- payload['instance']['description'] = options[:description]
542
- end
543
- if options[:environment] && !payload['instance']['instanceContext']
544
- payload['instance']['instanceContext'] = options[:environment]
545
- end
546
- payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
547
- payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
548
- payload[:createBackup] = options[:create_backup] if !options[:create_backup].nil?
549
- payload['instance']['expireDays'] = options[:expire_days] if options[:expire_days]
550
- payload['instance']['shutdownDays'] = options[:shutdown_days] if options[:shutdown_days]
551
- if options.key?(:create_user)
552
- payload['config'] ||= {}
553
- payload['config']['createUser'] = options[:create_user]
506
+ payload.deep_merge!({"instance" => {"type" => instance_type["code"] } })
507
+ payload.deep_merge!({"instance" => {"instanceType" => {"code" => instance_type["code"]} } })
554
508
  end
555
- if options[:user_group_id]
556
- payload['instance']['userGroup'] = {'id' => options[:user_group_id] }
557
- end
558
- if options[:workflow_id]
559
- if options[:workflow_id].to_s =~ /\A\d{1,}\Z/
560
- payload['taskSetId'] = options[:workflow_id].to_i
561
- else
562
- payload['taskSetName'] = options[:workflow_id]
509
+ else
510
+ # use active group by default
511
+ options[:group] ||= @active_group_id
512
+ options[:select_datastore] = true
513
+ options[:name_required] = true
514
+ # prompt for all the instance configuration options
515
+ # this provisioning helper method handles all (most) of the parsing and prompting
516
+ # and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
517
+ payload = prompt_new_instance(options)
518
+ # clean payload of empty objects
519
+ # note: this is temporary and should be fixed upstream in OptionTypes.prompt()
520
+ if payload['instance'].is_a?(Hash)
521
+ payload['instance'].keys.each do |k|
522
+ v = payload['instance'][k]
523
+ payload['instance'].delete(k) if v.is_a?(Hash) && v.empty?
563
524
  end
564
525
  end
565
- if options[:enable_load_balancer]
566
- lb_payload = prompt_instance_load_balancer(payload['instance'], nil, options)
567
- payload.deep_merge!(lb_payload)
568
- end
569
- @instances_interface.setopts(options)
570
- if options[:dry_run]
571
- print_dry_run @instances_interface.dry.create(payload)
572
- return 0
526
+ if payload['config'].is_a?(Hash)
527
+ payload['config'].keys.each do |k|
528
+ v = payload['config'][k]
529
+ payload['config'].delete(k) if v.is_a?(Hash) && v.empty?
530
+ end
573
531
  end
532
+ end
574
533
 
575
- json_response = @instances_interface.create(payload)
576
- if options[:json]
577
- puts as_json(json_response, options)
578
- elsif !options[:quiet]
579
- instance_id = json_response["instance"]["id"]
580
- instance_name = json_response["instance"]["name"]
581
- print_green_success "Provisioning instance [#{instance_id}] #{instance_name}"
582
- # print details
583
- get_args = [instance_id] + (options[:remote] ? ["-r",options[:remote]] : []) + (options[:refresh_interval] ? ['--refresh', options[:refresh_interval].to_s] : [])
584
- get(get_args)
534
+ payload['instance'] ||= {}
535
+ if options[:instance_name]
536
+ payload['instance']['name'] = options[:instance_name]
537
+ end
538
+ if options[:description] && !payload['instance']['description']
539
+ payload['instance']['description'] = options[:description]
540
+ end
541
+ if options[:environment] && !payload['instance']['instanceContext']
542
+ payload['instance']['instanceContext'] = options[:environment]
543
+ end
544
+ payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
545
+ payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
546
+ payload[:createBackup] = options[:create_backup] if !options[:create_backup].nil?
547
+ payload['instance']['expireDays'] = options[:expire_days] if options[:expire_days]
548
+ payload['instance']['shutdownDays'] = options[:shutdown_days] if options[:shutdown_days]
549
+ if options.key?(:create_user)
550
+ payload['config'] ||= {}
551
+ payload['config']['createUser'] = options[:create_user]
552
+ end
553
+ if options[:user_group_id]
554
+ payload['instance']['userGroup'] = {'id' => options[:user_group_id] }
555
+ end
556
+ if options[:workflow_id]
557
+ if options[:workflow_id].to_s =~ /\A\d{1,}\Z/
558
+ payload['taskSetId'] = options[:workflow_id].to_i
559
+ else
560
+ payload['taskSetName'] = options[:workflow_id]
585
561
  end
562
+ end
563
+ if options[:enable_load_balancer]
564
+ lb_payload = prompt_instance_load_balancer(payload['instance'], nil, options)
565
+ payload.deep_merge!(lb_payload)
566
+ end
567
+ @instances_interface.setopts(options)
568
+ if options[:dry_run]
569
+ print_dry_run @instances_interface.dry.create(payload)
586
570
  return 0
587
- rescue RestClient::Exception => e
588
- print_rest_exception(e, options)
589
- return 1
590
571
  end
572
+
573
+ json_response = @instances_interface.create(payload)
574
+ render_response(json_response, options, "instance") do
575
+ instance_id = json_response["instance"]["id"]
576
+ instance_name = json_response["instance"]["name"]
577
+ print_green_success "Provisioning instance [#{instance_id}] #{instance_name}"
578
+ # print details
579
+ get_args = [instance_id] + (options[:remote] ? ["-r",options[:remote]] : []) + (options[:refresh_interval] ? ['--refresh', options[:refresh_interval].to_s] : [])
580
+ get(get_args)
581
+ end
582
+ return 0, nil
591
583
  end
592
584
 
593
585
  def update(args)
@@ -1373,7 +1365,6 @@ class Morpheus::Cli::Instances
1373
1365
  "Status" => lambda {|it| format_instance_status(it) }
1374
1366
  }
1375
1367
  description_cols.delete("Labels") if labels.nil? || labels.empty?
1376
- description_cols.delete("Tags") if tags.nil? || tags.empty?
1377
1368
  description_cols.delete("Apps") if instance['apps'].nil? || instance['apps'].empty?
1378
1369
  description_cols.delete("Power Schedule") if instance['powerSchedule'].nil?
1379
1370
  description_cols.delete("Expire Date") if instance['expireDate'].nil?
@@ -1702,19 +1693,77 @@ class Morpheus::Cli::Instances
1702
1693
  options = {:options => {}}
1703
1694
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1704
1695
  opts.banner = subcommand_usage("[instance] -g GROUP")
1705
- opts.on('--name VALUE', String, "Name") do |val|
1706
- options[:options]['name'] = val
1707
- end
1708
1696
  opts.on( '-g', '--group GROUP', "Group Name or ID for the new instance" ) do |val|
1709
1697
  options[:group] = val
1710
1698
  end
1711
1699
  opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID for the new instance" ) do |val|
1712
1700
  options[:cloud] = val
1713
1701
  end
1702
+ opts.on('--name VALUE', String, "Name") do |val|
1703
+ options[:options]['name'] = val
1704
+ end
1705
+ opts.on("--description [TEXT]", String, "Description") do |val|
1706
+ options[:description] = val.to_s
1707
+ end
1708
+ opts.on("--environment ENV", String, "Environment code") do |val|
1709
+ options[:environment] = val.to_s
1710
+ end
1711
+ opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
1712
+ options[:metadata] = val
1713
+ end
1714
+ opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
1715
+ options[:metadata] = val
1716
+ end
1717
+ opts.add_hidden_option('--metadata')
1718
+ opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
1719
+ options[:labels] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
1720
+ end
1721
+ # opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
1722
+ # options[:copies] = val.to_i
1723
+ # end
1724
+ # opts.on("--layout-size NUMBER", Integer, "Apply a multiply factor of containers/vms within the instance") do |val|
1725
+ # options[:layout_size] = val.to_i
1726
+ # end
1727
+ # opts.on( '-l', '--layout LAYOUT', "Layout ID" ) do |val|
1728
+ # options[:layout] = val
1729
+ # end
1730
+ opts.on( '-p', '--plan PLAN', "Service plan ID") do |val|
1731
+ options[:service_plan] = val
1732
+ end
1733
+ opts.on( '--resource-pool ID', String, "Resource pool ID" ) do |val|
1734
+ options[:resource_pool] = val
1735
+ end
1736
+ opts.on("--workflow ID", String, "Automation: Workflow ID") do |val|
1737
+ options[:workflow_id] = val
1738
+ end
1739
+ opts.on("--ports ARRAY", String, "Exposed Ports, JSON formatted list of objects containing name and port") do |val|
1740
+ # expects format like --ports '[{"name":"web","port":8080}]'
1741
+ ports_array = JSON.parse(val)
1742
+ options[:ports] = ports_array
1743
+ options[:options]['ports'] = ports_array
1744
+ end
1745
+ # opts.on('-L', "--lb", "Enable Load Balancer") do
1746
+ # options[:enable_load_balancer] = true
1747
+ # end
1714
1748
  opts.on("--create-user on|off", String, "User Config: Create Your User. Default is on") do |val|
1715
1749
  options[:create_user] = !['false','off','0'].include?(val.to_s)
1716
1750
  end
1717
- build_common_options(opts, options, [:options, :payload, :auto_confirm, :json, :dry_run, :remote])
1751
+ opts.on("--user-group USERGROUP", String, "User Config: User Group") do |val|
1752
+ options[:user_group_id] = val
1753
+ end
1754
+ opts.on("--shutdown-days DAYS", Integer, "Automation: Shutdown Days") do |val|
1755
+ options[:shutdown_days] = val.to_i
1756
+ end
1757
+ opts.on("--expire-days DAYS", Integer, "Automation: Expiration Days") do |val|
1758
+ options[:expire_days] = val.to_i
1759
+ end
1760
+ opts.on("--create-backup [on|off]", String, "Automation: Create Backups.") do |val|
1761
+ options[:create_backup] = ['on','true','1',''].include?(val.to_s.downcase) ? 'on' : 'off'
1762
+ end
1763
+ opts.on("--security-groups LIST", String, "Security Groups, comma separated list of security group IDs") do |val|
1764
+ options[:security_groups] = val.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
1765
+ end
1766
+ build_standard_post_options(opts, options, [:auto_confirm])
1718
1767
  end
1719
1768
  optparse.parse!(args)
1720
1769
  if args.count < 1 || args.count > 2
@@ -1732,12 +1781,20 @@ class Morpheus::Cli::Instances
1732
1781
 
1733
1782
  # defaults derived from clone
1734
1783
  options[:default_name] = instance['name'] + '-clone' if instance['name']
1784
+ options[:default_description] = instance['description'] if !instance['description'].to_s.empty?
1785
+ options[:default_environment] = instance['environment'] if instance['environment']
1735
1786
  options[:default_group] = instance['group']['id'] if instance['group']
1736
1787
  options[:default_cloud] = instance['cloud']['name'] if instance['cloud']
1737
1788
  options[:default_plan] = instance['plan']['name'] if instance['plan']
1738
1789
  options[:default_resource_pool] = instance['config']['resourcePoolId'] if instance['config']
1739
1790
  options[:default_config] = instance['config']
1740
1791
  options[:default_security_group] = instance['config']['securityGroups'][0]['id'] if instance['config'] && (instance['config']['securityGroups'] || []).count > 0
1792
+ if instance['labels'] && !instance['labels'].empty?
1793
+ options[:default_labels] = (instance['labels'] || []).join(',')
1794
+ end
1795
+ if instance['tags'] && !instance['tags'].empty?
1796
+ options[:current_tags] = instance['tags']
1797
+ end
1741
1798
 
1742
1799
  # immutable derived from clone
1743
1800
  options[:instance_type_code] = instance['instanceType']['code'] if instance['instanceType']
@@ -1775,13 +1832,52 @@ class Morpheus::Cli::Instances
1775
1832
  payload.deep_merge!(passed_options)
1776
1833
  end
1777
1834
 
1835
+ #payload['instance'] ||= {}
1836
+ # if options[:instance_name]
1837
+ # payload['instance']['name'] = options[:instance_name]
1838
+ # end
1839
+ # if options[:description] && !payload['instance']['description']
1840
+ # payload['instance']['description'] = options[:description]
1841
+ # end
1842
+ # if options[:environment] && !payload['instance']['instanceContext']
1843
+ # payload['instance']['instanceContext'] = options[:environment]
1844
+ # end
1845
+
1846
+ #payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
1847
+ if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
1848
+ payload[:layoutSize] = options[:layout_size]
1849
+ end
1850
+ if !options[:create_backup].nil?
1851
+ payload[:createBackup] = options[:create_backup]
1852
+ end
1853
+ if options[:expire_days]
1854
+ payload['instance'] ||= {}
1855
+ payload['instance']['expireDays'] = options[:expire_days]
1856
+ end
1857
+ if options[:shutdown_days]
1858
+ payload['instance'] ||= {}
1859
+ payload['shutdownDays'] = options[:shutdown_days]
1860
+ end
1778
1861
  # JD: this actually fixed a customer problem
1779
1862
  # It appears to be important to pass this... not sure if config.createUser is necessary...
1780
1863
  if options[:create_user].nil?
1781
1864
  options[:create_user] = true
1782
1865
  end
1783
- if options[:create_user] != nil
1784
- payload.deep_merge!({'createUser' => options[:create_user], 'config' =>{'createUser' => options[:create_user]}})
1866
+ if options.key?(:create_user)
1867
+ payload['config'] ||= {}
1868
+ payload['config']['createUser'] = options[:create_user]
1869
+ payload['createUser'] = options[:create_user]
1870
+ end
1871
+ if options[:user_group_id]
1872
+ payload['instance'] ||= {}
1873
+ payload['instance']['userGroup'] = {'id' => options[:user_group_id] }
1874
+ end
1875
+ if options[:workflow_id]
1876
+ if options[:workflow_id].to_s =~ /\A\d{1,}\Z/
1877
+ payload['taskSetId'] = options[:workflow_id].to_i
1878
+ else
1879
+ payload['taskSetName'] = options[:workflow_id]
1880
+ end
1785
1881
  end
1786
1882
  unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to clone the instance #{instance['name']} as '#{payload['name']}'?", options)
1787
1883
  return 9, "aborted command"
@@ -1931,7 +2027,7 @@ class Morpheus::Cli::Instances
1931
2027
  opts.on('--muteMonitoring [on|off]', String, "Mute monitoring. Default is off.") do |val|
1932
2028
  params['muteMonitoring'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
1933
2029
  end
1934
- opts.add_hidden_option('muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
2030
+ opts.add_hidden_option('--muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
1935
2031
  build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
1936
2032
  opts.footer = "Stop an instance.\n" +
1937
2033
  "[instance] is required. This is the name or id of an instance. Supports 1-N [instance] arguments."
@@ -2059,7 +2155,7 @@ class Morpheus::Cli::Instances
2059
2155
  opts.on('--muteMonitoring [on|off]', String, "Mute monitoring. Default is on.") do |val|
2060
2156
  params['muteMonitoring'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
2061
2157
  end
2062
- opts.add_hidden_option('muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
2158
+ opts.add_hidden_option('--muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
2063
2159
  build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
2064
2160
  opts.footer = "Restart an instance.\n" +
2065
2161
  "[instance] is required. This is the name or id of an instance. Supports 1-N [instance] arguments."
@@ -2127,7 +2223,7 @@ class Morpheus::Cli::Instances
2127
2223
  opts.on('--muteMonitoring [on|off]', String, "Mute monitoring. Default is on.") do |val|
2128
2224
  params['muteMonitoring'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
2129
2225
  end
2130
- opts.add_hidden_option('muteMonitoring')
2226
+ opts.add_hidden_option('--muteMonitoring')
2131
2227
  opts.on('--server [on|off]', String, "Suspend instance server. Default is off.") do |val|
2132
2228
  params['server'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
2133
2229
  end
@@ -2233,7 +2329,7 @@ class Morpheus::Cli::Instances
2233
2329
  opts.on('--muteMonitoring [on|off]', String, "Mute monitoring. Default is off.") do |val|
2234
2330
  params['muteMonitoring'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
2235
2331
  end
2236
- opts.add_hidden_option('muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
2332
+ opts.add_hidden_option('--muteMonitoring') if opts.is_a?(Morpheus::Cli::OptionParser)
2237
2333
  build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
2238
2334
  opts.footer = "Stop service on an instance.\n" +
2239
2335
  "[instance] is required. This is the name or id of an instance. Supports 1-N [instance] arguments."
@@ -2361,7 +2457,7 @@ class Morpheus::Cli::Instances
2361
2457
  opts.on('--muteMonitoring [on|off]', String, "Mute monitoring. Default is on.") do |val|
2362
2458
  params['muteMonitoring'] = val.nil? || val.to_s == 'on' || val.to_s == 'true'
2363
2459
  end
2364
- opts.add_hidden_option('muteMonitoring')
2460
+ opts.add_hidden_option('--muteMonitoring')
2365
2461
  build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
2366
2462
  opts.footer = "Restart service on an instance.\n" +
2367
2463
  "[instance] is required. This is the name or id of an instance. Supports 1-N [instance] arguments."
@@ -2592,17 +2688,18 @@ class Morpheus::Cli::Instances
2592
2688
  cloud_id = instance['cloud']['id']
2593
2689
  layout_id = instance['layout']['id']
2594
2690
  plan_id = instance['plan']['id']
2595
-
2691
+ current_plan_name = instance['plan']['name']
2596
2692
  # prompt for service plan
2597
2693
  service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, siteId: group_id, layoutId: layout_id})
2598
2694
  service_plans = service_plans_json["plans"]
2599
2695
  service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
2600
2696
  service_plans_dropdown.each do |plan|
2601
- if plan['value'] && plan['value'].to_i == plan_id.to_i
2602
- plan['name'] = "#{plan['name']} (current)"
2603
- end
2697
+ # if plan['value'] && plan['value'].to_i == plan_id.to_i
2698
+ # plan['name'] = "#{plan['name']} (current)"
2699
+ # current_plan_name = plan['name']
2700
+ # end
2604
2701
  end
2605
- plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
2702
+ plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'defaultValue' => current_plan_name, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
2606
2703
  service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
2607
2704
  new_plan_id = service_plan["id"]
2608
2705
  #payload[:servicePlan] = new_plan_id # ew, this api uses servicePlanId instead
@@ -2622,7 +2719,8 @@ class Morpheus::Cli::Instances
2622
2719
  # for now, always do this
2623
2720
  payload["deleteOriginalVolumes"] = true
2624
2721
  end
2625
-
2722
+ payload.delete("rootVolume")
2723
+ (1..20).each {|i| payload.delete("dataVolume#{i}") }
2626
2724
  @instances_interface.setopts(options)
2627
2725
  if options[:dry_run]
2628
2726
  print_dry_run @instances_interface.dry.resize(instance['id'], payload)
@@ -2783,34 +2881,158 @@ EOT
2783
2881
 
2784
2882
  def cancel_removal(args)
2785
2883
  options = {}
2884
+ params = {}
2786
2885
  optparse = Morpheus::Cli::OptionParser.new do |opts|
2787
2886
  opts.banner = subcommand_usage("[instance]")
2788
- build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
2887
+ build_standard_update_options(opts, options)
2888
+ opts.footer = <<-EOT
2889
+ Cancel removal of an instance.
2890
+ This is a way to undo delete of an instance still pending removal.
2891
+ [instance] is required. This is the name or id of an instance
2892
+ EOT
2789
2893
  end
2790
2894
  optparse.parse!(args)
2791
- if args.count < 1
2792
- puts optparse
2793
- exit 1
2895
+ verify_args!(args:args, optparse:optparse, count:1)
2896
+ connect(options)
2897
+ params.merge!(parse_query_options(options))
2898
+ payload = options[:payload] || {}
2899
+ payload.deep_merge!(parse_passed_options(options))
2900
+ instance = find_instance_by_name_or_id(args[0])
2901
+ @instances_interface.setopts(options)
2902
+ if options[:dry_run]
2903
+ print_dry_run @instances_interface.dry.cancel_removal(instance['id'], params, payload)
2904
+ return
2794
2905
  end
2906
+ json_response = @instances_interface.cancel_removal(instance['id'], params, payload)
2907
+ render_response(json_response, options) do
2908
+ print_green_success "Canceled removal for instance #{instance['name']} ..."
2909
+ get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
2910
+ end
2911
+ return 0, nil
2912
+ end
2913
+
2914
+ def cancel_expiration(args)
2915
+ options = {}
2916
+ params = {}
2917
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2918
+ opts.banner = subcommand_usage("[instance]")
2919
+ build_standard_update_options(opts, options, [:query]) # query params instead of p
2920
+ opts.footer = <<-EOT
2921
+ Cancel expiration of an instance.
2922
+ [instance] is required. This is the name or id of an instance
2923
+ EOT
2924
+ end
2925
+ optparse.parse!(args)
2926
+ verify_args!(args:args, optparse:optparse, count:1)
2795
2927
  connect(options)
2796
- begin
2797
- instance = find_instance_by_name_or_id(args[0])
2798
- @instances_interface.setopts(options)
2799
- if options[:dry_run]
2800
- print_dry_run @instances_interface.dry.cancel_removal(instance['id'])
2801
- return
2802
- end
2803
- json_response = @instances_interface.cancel_removal(instance['id'])
2804
- if options[:json]
2805
- print as_json(json_response, options), "\n"
2806
- return
2807
- elsif !options[:quiet]
2808
- get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
2809
- end
2810
- rescue RestClient::Exception => e
2811
- print_rest_exception(e, options)
2812
- exit 1
2928
+ params.merge!(parse_query_options(options))
2929
+ payload = options[:payload] || {}
2930
+ payload.deep_merge!(parse_passed_options(options))
2931
+ instance = find_instance_by_name_or_id(args[0])
2932
+ @instances_interface.setopts(options)
2933
+ if options[:dry_run]
2934
+ print_dry_run @instances_interface.dry.cancel_expiration(instance['id'], params, payload)
2935
+ return
2813
2936
  end
2937
+ json_response = @instances_interface.cancel_expiration(instance['id'], params, payload)
2938
+ render_response(json_response, options) do
2939
+ print_green_success "Canceled expiration for instance #{instance['name']} ..."
2940
+ get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
2941
+ end
2942
+ return 0, nil
2943
+ end
2944
+
2945
+ def cancel_shutdown(args)
2946
+ options = {}
2947
+ params = {}
2948
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2949
+ opts.banner = subcommand_usage("[instance]")
2950
+ build_standard_update_options(opts, options, [:query]) # query params instead of p
2951
+ opts.footer = <<-EOT
2952
+ Cancel shutdown for an instance.
2953
+ [instance] is required. This is the name or id of an instance
2954
+ EOT
2955
+ end
2956
+ optparse.parse!(args)
2957
+ verify_args!(args:args, optparse:optparse, count:1)
2958
+ connect(options)
2959
+ params.merge!(parse_query_options(options))
2960
+ payload = options[:payload] || {}
2961
+ payload.deep_merge!(parse_passed_options(options))
2962
+ instance = find_instance_by_name_or_id(args[0])
2963
+ @instances_interface.setopts(options)
2964
+ if options[:dry_run]
2965
+ print_dry_run @instances_interface.dry.cancel_shutdown(instance['id'], params, payload)
2966
+ return
2967
+ end
2968
+ json_response = @instances_interface.cancel_shutdown(instance['id'], params, payload)
2969
+ render_response(json_response, options) do
2970
+ print_green_success "Canceled shutdown for instance #{instance['name']} ..."
2971
+ get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
2972
+ end
2973
+ return 0, nil
2974
+ end
2975
+
2976
+ def extend_expiration(args)
2977
+ options = {}
2978
+ params = {}
2979
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2980
+ opts.banner = subcommand_usage("[instance]")
2981
+ build_standard_update_options(opts, options, [:query]) # query params instead of p
2982
+ opts.footer = <<-EOT
2983
+ Extend expiration for an instance.
2984
+ [instance] is required. This is the name or id of an instance
2985
+ EOT
2986
+ end
2987
+ optparse.parse!(args)
2988
+ verify_args!(args:args, optparse:optparse, count:1)
2989
+ connect(options)
2990
+ params.merge!(parse_query_options(options))
2991
+ payload = options[:payload] || {}
2992
+ payload.deep_merge!(parse_passed_options(options))
2993
+ instance = find_instance_by_name_or_id(args[0])
2994
+ @instances_interface.setopts(options)
2995
+ if options[:dry_run]
2996
+ print_dry_run @instances_interface.dry.extend_expiration(instance['id'], params, payload)
2997
+ return
2998
+ end
2999
+ json_response = @instances_interface.extend_expiration(instance['id'], params, payload)
3000
+ render_response(json_response, options) do
3001
+ print_green_success "Extended expiration for instance #{instance['name']} ..."
3002
+ get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
3003
+ end
3004
+ return 0, nil
3005
+ end
3006
+
3007
+ def extend_shutdown(args)
3008
+ options = {}
3009
+ params = {}
3010
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3011
+ opts.banner = subcommand_usage("[instance]")
3012
+ build_standard_update_options(opts, options, [:query]) # query params instead of p
3013
+ opts.footer = <<-EOT
3014
+ Extend shutdown for an instance.
3015
+ [instance] is required. This is the name or id of an instance
3016
+ EOT
3017
+ end
3018
+ optparse.parse!(args)
3019
+ verify_args!(args:args, optparse:optparse, count:1)
3020
+ connect(options)
3021
+ params.merge!(parse_query_options(options))
3022
+ payload = options[:payload] || {}
3023
+ payload.deep_merge!(parse_passed_options(options))
3024
+ instance = find_instance_by_name_or_id(args[0])
3025
+ @instances_interface.setopts(options)
3026
+ if options[:dry_run]
3027
+ print_dry_run @instances_interface.dry.extend_shutdown(instance['id'], params, payload)
3028
+ return
3029
+ end
3030
+ json_response = @instances_interface.extend_shutdown(instance['id'], params, payload)
3031
+ render_response(json_response, options) do
3032
+ print_green_success "Extended shutdown for instance #{instance['name']} ..."
3033
+ get([instance['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
3034
+ end
3035
+ return 0, nil
2814
3036
  end
2815
3037
 
2816
3038
  def firewall_disable(args)
@@ -3615,7 +3837,7 @@ EOT
3615
3837
  opts.on('--process-id ID', String, "Display details about a specfic event." ) do |val|
3616
3838
  options[:process_id] = val
3617
3839
  end
3618
- opts.add_hidden_option('process-id')
3840
+ opts.add_hidden_option('--process-id')
3619
3841
  build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
3620
3842
  opts.footer = "Display history details for a specific process.\n" +
3621
3843
  "[instance] is required. This is the name or id of an instance.\n" +
@@ -3715,7 +3937,7 @@ EOT
3715
3937
  opts.on('--event-id ID', String, "Display details about a specfic event." ) do |val|
3716
3938
  options[:event_id] = val
3717
3939
  end
3718
- opts.add_hidden_option('event-id')
3940
+ opts.add_hidden_option('--event-id')
3719
3941
  build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
3720
3942
  opts.footer = "Display history details for a specific process event.\n" +
3721
3943
  "[instance] is required. This is the name or id of an instance.\n" +