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
@@ -484,7 +484,7 @@ module Morpheus::Cli::ProvisioningHelper
484
484
  if options[:instance_type_code]
485
485
  instance_type_code = options[:instance_type_code]
486
486
  else
487
- instance_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{groupId: group_id})
487
+ instance_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{groupId: group_id}, no_prompt, true)
488
488
  instance_type_code = instance_type_prompt['type']
489
489
  end
490
490
  if instance_type_code.to_s =~ /\A\d{1,}\Z/
@@ -584,7 +584,7 @@ module Morpheus::Cli::ProvisioningHelper
584
584
  if options[:description]
585
585
  options[:options]['description'] = options[:description]
586
586
  end
587
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false}], options[:options])
587
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'defaultValue' => options[:default_description]}], options[:options])
588
588
  payload['instance']['description'] = v_prompt['description'] if !v_prompt['description'].empty?
589
589
 
590
590
  # Environment
@@ -593,14 +593,14 @@ module Morpheus::Cli::ProvisioningHelper
593
593
  elsif options[:options]['instanceContext'] && !options[:options]['environment']
594
594
  options[:options]['environment'] = options[:options]['instanceContext']
595
595
  end
596
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
596
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments(), 'defaultValue' => options[:default_environment]}], options[:options])
597
597
  payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
598
598
 
599
599
  # Labels (used to be called tags)
600
600
  if options[:labels]
601
601
  payload['instance']['labels'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
602
602
  else
603
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false}], options[:options])
603
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'defaultValue' => options[:default_labels]}], options[:options])
604
604
  payload['instance']['labels'] = v_prompt['labels'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['labels'].empty?
605
605
  end
606
606
 
@@ -657,13 +657,11 @@ module Morpheus::Cli::ProvisioningHelper
657
657
  version_value = default_version_value
658
658
  version_is_required = default_layout_value.nil?
659
659
  if default_layout_value.nil? && options[:options]["layout"].nil? && options[:always_prompt] != true
660
- #version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'optionSource' => 'instanceVersions', 'required' => true, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
661
660
  version_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'selectOptions' => available_versions, 'required' => version_is_required, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
662
661
  version_value = version_prompt['version']
663
662
  end
664
663
  end
665
-
666
- layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.', 'defaultValue' => default_layout_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_value, creatable: true})['layout']
664
+ layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.', 'defaultValue' => default_layout_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_value, creatable: true}, no_prompt, true)['layout']
667
665
  end
668
666
  end
669
667
 
@@ -679,7 +677,7 @@ module Morpheus::Cli::ProvisioningHelper
679
677
  end
680
678
  layout_id = layout['id']
681
679
  payload['instance']['layout'] = {'id' => layout['id'], 'code' => layout['code']}
682
-
680
+
683
681
  # need to GET provision type for optionTypes, and other settings...
684
682
  provision_type_code = layout['provisionTypeCode'] || layout['provisionType']['code']
685
683
  provision_type = nil
@@ -693,50 +691,6 @@ module Morpheus::Cli::ProvisioningHelper
693
691
  provision_type = get_provision_type_for_zone_type(cloud['zoneType']['id'])
694
692
  end
695
693
 
696
- # prompt for service plan
697
- plan_id = nil
698
- service_plan = nil
699
- service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
700
- service_plans = service_plans_json["plans"]
701
- if locked_fields.include?('plan.id')
702
- plan_id = options[:options]['plan']['id'] rescue nil
703
- if plan_id.nil?
704
- plan_id = options[:options]['instance']['plan']['id'] rescue nil
705
- end
706
- service_plan = service_plans.find {|sp| sp['id'] == plan_id }
707
- else
708
- service_plan = service_plans.find {|sp| sp['id'] == options[:service_plan].to_i} if options[:service_plan]
709
-
710
- if !service_plan
711
- service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"], 'code' => sp['code']} } # already sorted
712
- default_plan = nil
713
- if payload['plan']
714
- default_plan = payload['plan']
715
- elsif payload['instance'] && payload['instance']['plan']
716
- default_plan = payload['instance']['plan']
717
- end
718
-
719
- if options[:default_plan] && service_plans_dropdown.find {|sp| [sp["name"], sp["value"].to_s, sp["code"]].include?(options[:default_plan].to_s)}
720
- default_plan_value = options[:default_plan]
721
- else
722
- default_plan_value = options[:default_plan] || (default_plan.is_a?(Hash) ? default_plan['id'] : default_plan)
723
- end
724
- 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', 'defaultValue' => default_plan_value}],options[:options])
725
- plan_id = plan_prompt['servicePlan']
726
- service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
727
- if !service_plan
728
- print_red_alert "Plan not found by id #{plan_id}"
729
- exit 1
730
- end
731
- end
732
- #todo: consolidate these, instances api looks for instance.plan.id and apps looks for plan.id
733
- if options[:for_app]
734
- payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
735
- else
736
- payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
737
- end
738
- end
739
-
740
694
  # build config option types
741
695
  option_type_list = []
742
696
  if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
@@ -745,47 +699,112 @@ module Morpheus::Cli::ProvisioningHelper
745
699
  if !instance_type['optionTypes'].nil? && !instance_type['optionTypes'].empty?
746
700
  option_type_list += instance_type['optionTypes']
747
701
  end
748
- if !provision_type.nil? && !provision_type['optionTypes'].nil? && !provision_type['optionTypes'].empty?
749
- option_type_list += provision_type['optionTypes']
750
- end
751
702
 
752
- # prompt for resource pool
703
+ api_params = {groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_value}
704
+
753
705
  pool_id = nil
754
706
  resource_pool = nil
755
- if locked_fields.include?('config.resourcePoolId')
756
- pool_id = payload['config']['resourcePoolId'] rescue nil
757
- elsif locked_fields.include?('config.resourcePool')
758
- pool_id = payload['config']['resourcePool'] rescue nil
759
- elsif locked_fields.include?('config.azureResourceGroupId')
760
- pool_id = payload['config']['azureResourceGroupId'] rescue nil
761
- else
762
- has_zone_pools = provision_type && provision_type["id"] && provision_type["hasZonePools"]
763
- if has_zone_pools
764
- # pluck out the resourcePoolId option type to prompt for
765
- resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
766
- option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
767
- resource_pool_options = options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], planId: service_plan["id"], layoutId: layout["id"]})['data']
768
- resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
769
-
770
- if resource_pool
771
- pool_id = resource_pool['id']
772
- else
773
- if options[:default_resource_pool]
774
- default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
707
+ service_plan = nil
708
+
709
+ prompt_service_plan = -> {
710
+ service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id}.merge(resource_pool.nil? ? {} : {'resourcePoolId' => resource_pool['id']}))
711
+ service_plans = service_plans_json["plans"]
712
+ if locked_fields.include?('plan.id')
713
+ plan_id = options[:options]['plan']['id'] rescue nil
714
+ if plan_id.nil?
715
+ plan_id = options[:options]['instance']['plan']['id'] rescue nil
716
+ end
717
+ service_plan = service_plans.find {|sp| sp['id'] == plan_id }
718
+ else
719
+ service_plan = service_plans.find {|sp| sp['id'] == options[:service_plan].to_i} if options[:service_plan]
720
+
721
+ if !service_plan
722
+ service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"], 'code' => sp['code']} } # already sorted
723
+ default_plan = nil
724
+ if payload['plan']
725
+ default_plan = payload['plan']
726
+ elsif payload['instance'] && payload['instance']['plan']
727
+ default_plan = payload['instance']['plan']
728
+ end
729
+
730
+ if options[:default_plan] && service_plans_dropdown.find {|sp| [sp["name"], sp["value"].to_s, sp["code"]].include?(options[:default_plan].to_s)}
731
+ default_plan_value = options[:default_plan]
732
+ else
733
+ default_plan_value = options[:default_plan] || (default_plan.is_a?(Hash) ? default_plan['id'] : default_plan)
775
734
  end
776
- resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
777
- resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{})
778
- resource_pool_prompt.deep_compact!
779
- payload.deep_merge!(resource_pool_prompt)
780
- resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
781
- if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
782
- pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
783
- elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
784
- pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
735
+ 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', 'defaultValue' => default_plan_value}],options[:options], api_client, {}, no_prompt, true)
736
+ plan_id = plan_prompt['servicePlan']
737
+ service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
738
+ if !service_plan
739
+ print_red_alert "Plan not found by id #{plan_id}"
740
+ exit 1
741
+ end
742
+ end
743
+ #todo: consolidate these, instances api looks for instance.plan.id and apps looks for plan.id
744
+ if options[:for_app]
745
+ payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
746
+ else
747
+ payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
748
+ end
749
+ end
750
+ }
751
+
752
+ prompt_resource_pool = -> {
753
+ # prompt for resource pool
754
+ if locked_fields.include?('config.resourcePoolId')
755
+ pool_id = payload['config']['resourcePoolId'] rescue nil
756
+ elsif locked_fields.include?('config.resourcePool')
757
+ pool_id = payload['config']['resourcePool'] rescue nil
758
+ elsif locked_fields.include?('config.azureResourceGroupId')
759
+ pool_id = payload['config']['azureResourceGroupId'] rescue nil
760
+ else
761
+ has_zone_pools = provision_type && provision_type["id"] && provision_type["hasZonePools"]
762
+ if has_zone_pools
763
+ # pluck out the resourcePoolId option type to prompt for
764
+ resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
765
+ option_type_list = option_type_list.reject {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
766
+
767
+ resource_pool_options = options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], layoutId: layout["id"]}.merge(service_plan.nil? ? {} : {planId: service_plan["id"]}))['data']
768
+ resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
769
+
770
+ if resource_pool
771
+ pool_id = resource_pool['id']
772
+ else
773
+ if options[:default_resource_pool]
774
+ default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
775
+ end
776
+ resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
777
+ resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
778
+ resource_pool_prompt.deep_compact!
779
+ payload.deep_merge!(resource_pool_prompt)
780
+ resource_pool = Morpheus::Cli::OptionTypes.get_last_select()
781
+ if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
782
+ pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
783
+ elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
784
+ pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
785
+ end
786
+ resource_pool ||= resource_pool_options.find {|it| it['id'] == pool_id}
785
787
  end
786
- resource_pool ||= resource_pool_options.find {|it| it['id'] == pool_id}
787
788
  end
788
789
  end
790
+ }
791
+
792
+ prompt_provision_options = -> {
793
+ if !provision_type.nil? && !provision_type['optionTypes'].nil? && !provision_type['optionTypes'].empty?
794
+ option_type_list += provision_type['optionTypes'].reject {|it| (it['fieldGroup'] || '').downcase == 'provisiontype'}
795
+ provision_config_payload = Morpheus::Cli::OptionTypes.prompt(provision_type['optionTypes'].reject {|it| (it['fieldGroup'] || '').downcase != 'provisiontype'}, options[:options], @api_client, api_params, no_prompt, true)
796
+ payload.deep_merge!(provision_config_payload)
797
+ end
798
+ }
799
+
800
+ if ['openstack', 'huawei', 'opentelekom'].include?(cloud_type['zoneType']['code'])
801
+ prompt_resource_pool.call
802
+ prompt_provision_options.call
803
+ prompt_service_plan.call
804
+ else
805
+ prompt_service_plan.call
806
+ prompt_provision_options.call
807
+ prompt_resource_pool.call
789
808
  end
790
809
 
791
810
  # remove host selection for kubernetes
@@ -858,7 +877,7 @@ module Morpheus::Cli::ProvisioningHelper
858
877
  if provision_type && provision_type["hasNetworks"]
859
878
  # prompt for network interfaces (if supported)
860
879
  begin
861
- network_interfaces = prompt_network_interfaces(cloud_id, provision_type["id"], pool_id, options)
880
+ network_interfaces = prompt_network_interfaces(cloud_id, provision_type["id"], pool_id, options.merge({:api_params => payload['config']}))
862
881
  if !network_interfaces.empty?
863
882
  payload['networkInterfaces'] = network_interfaces
864
883
  end
@@ -921,7 +940,6 @@ module Morpheus::Cli::ProvisioningHelper
921
940
  end
922
941
 
923
942
  # prompt for option types
924
- api_params = {groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_value}
925
943
  api_params['config'] = payload['config'] if payload['config']
926
944
  api_params['poolId'] = payload['config']['resourcePoolId'] if payload['config'] && payload['config']['resourcePoolId']
927
945
 
@@ -935,10 +953,21 @@ module Morpheus::Cli::ProvisioningHelper
935
953
  end
936
954
  end
937
955
 
938
- instance_config_payload = Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options], @api_client, api_params)
939
- payload.deep_merge!(instance_config_payload)
956
+ option_type_list += [
957
+ {'fieldName' => 'userGroup.id', 'fieldLabel' => 'User Group', 'fieldGroup' => 'User Config', 'type' => 'select', 'optionSource' => 'userGroups', 'displayOrder' => 0, 'fieldContext' => 'instance'},
958
+ {'fieldName' => 'hostName', 'fieldLabel' => 'Hostname', 'fieldGroup' => 'Advanced', 'type' => 'string', 'displayOrder' => 1},
959
+ {'fieldName' => 'networkDomain.id', 'fieldLabel' => 'Domain', 'fieldGroup' => 'Advanced', 'type' => 'select', 'optionSource' => 'networkDomains', 'displayOrder' => 2, 'fieldContext' => 'instance'},
960
+ {'fieldName' => 'timezone', 'fieldLabel' => 'Time Zone', 'fieldGroup' => 'Advanced', 'type' => 'select', 'optionSource' => 'timezones', 'displayOrder' => 3, 'fieldContext' => 'config'}
961
+ ]
940
962
 
941
- ## Network Options
963
+ if instance_type['hasAutoScale']
964
+ option_type_list += [
965
+ {'fieldName' => 'layoutSize', 'fieldLabel' => 'Scale Factor', 'fieldGroup' => 'Advanced', 'type' => 'number', 'defaultValue' => 1, 'displayOrder' => 0},
966
+ ]
967
+ end
968
+
969
+ instance_config_payload = Morpheus::Cli::OptionTypes.prompt(option_type_list.reject {|ot| ot['type'] == 'exposedPorts'}, options[:options], @api_client, api_params, no_prompt, true)
970
+ payload.deep_merge!(instance_config_payload)
942
971
 
943
972
  # prompt for exposed ports
944
973
  if payload['ports'].nil?
@@ -950,10 +979,6 @@ module Morpheus::Cli::ProvisioningHelper
950
979
  end
951
980
  end
952
981
 
953
- ## Advanced Options
954
-
955
- # scale factor
956
-
957
982
  # prompt for environment variables
958
983
  evars = prompt_evars(options)
959
984
  if !evars.empty?
@@ -961,20 +986,28 @@ module Morpheus::Cli::ProvisioningHelper
961
986
  end
962
987
 
963
988
  # metadata tags
964
- if options[:options]['metadata'].is_a?(Array) && !options[:metadata]
965
- options[:metadata] = options[:options]['metadata']
989
+ # metadata_tag_key = 'metadata'
990
+ metadata_tag_key = 'tags'
991
+ if !options[:metadata]
992
+ if options[:options]['metadata'].is_a?(Array)
993
+ options[:metadata] = options[:options]['metadata']
994
+ end
995
+ if options[:options]['tags'].is_a?(Array)
996
+ options[:metadata] = options[:options]['tags']
997
+ end
966
998
  end
967
999
  if options[:metadata]
1000
+ metadata = []
968
1001
  if options[:metadata] == "[]" || options[:metadata] == "null"
969
- payload['metadata'] = []
1002
+ metadata = []
970
1003
  elsif options[:metadata].is_a?(Array)
971
- payload['metadata'] = options[:metadata]
1004
+ metadata = options[:metadata]
972
1005
  else
973
1006
  # parse string into format name:value, name:value
974
1007
  # merge IDs from current metadata
975
1008
  # todo: should allow quoted semicolons..
976
- metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
977
- metadata_list = metadata_list.collect do |it|
1009
+ metadata = options[:metadata].split(",").select {|it| !it.to_s.empty? }
1010
+ metadata = metadata.collect do |it|
978
1011
  metadata_pair = it.split(":")
979
1012
  if metadata_pair.size < 2 && it.include?("=")
980
1013
  metadata_pair = it.split("=")
@@ -984,13 +1017,13 @@ module Morpheus::Cli::ProvisioningHelper
984
1017
  row['value'] = metadata_pair[1].to_s.strip
985
1018
  row
986
1019
  end
987
- payload['metadata'] = metadata_list
988
1020
  end
1021
+ payload[metadata_tag_key] = metadata
989
1022
  else
990
1023
  # prompt for metadata tags
991
1024
  metadata = prompt_metadata(options)
992
1025
  if !metadata.empty?
993
- payload['metadata'] = metadata
1026
+ payload[metadata_tag_key] = metadata
994
1027
  end
995
1028
  end
996
1029
 
@@ -1327,13 +1360,9 @@ module Morpheus::Cli::ProvisioningHelper
1327
1360
 
1328
1361
  field_context = "dataVolume#{volume_index}"
1329
1362
 
1330
- if no_prompt
1331
- volume_action = 'keep'
1332
- else
1333
- action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
1334
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
1335
- volume_action = v_prompt[field_context]['action']
1336
- end
1363
+ action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
1364
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'defaultValue' => 'keep', 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
1365
+ volume_action = v_prompt[field_context]['action']
1337
1366
 
1338
1367
  if volume_action == 'delete'
1339
1368
  # deleted volume is just excluded from post params
@@ -1490,10 +1519,11 @@ module Morpheus::Cli::ProvisioningHelper
1490
1519
  #puts "Configure Networks:"
1491
1520
  no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
1492
1521
  network_interfaces = []
1493
- api_params = {zoneId: zone_id, provisionTypeId: provision_type_id}
1522
+ api_params = {zoneId: zone_id, provisionTypeId: provision_type_id}.merge(options[:api_params] || {})
1494
1523
  if pool_id.to_s =~ /\A\d{1,}\Z/
1495
1524
  api_params[:poolId] = pool_id
1496
1525
  end
1526
+
1497
1527
  zone_network_options_json = api_client.options.options_for_source('zoneNetworkOptions', api_params)
1498
1528
  # puts "zoneNetworkOptions JSON"
1499
1529
  # puts JSON.pretty_generate(zone_network_options_json)
@@ -1575,7 +1605,7 @@ module Morpheus::Cli::ProvisioningHelper
1575
1605
  default_network_value = (network_options.find {|n| n['value'] == default_network_id} || {})['name']
1576
1606
 
1577
1607
  # choose network
1578
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => default_network_value}], options[:options])
1608
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => default_network_value}], options[:options], api_client, {}, no_prompt, true)
1579
1609
  network_interface['network'] = {}
1580
1610
  network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_s
1581
1611
  selected_network = networks.find {|it| it["id"].to_s == network_interface['network']['id'] }
@@ -1715,6 +1745,19 @@ module Morpheus::Cli::ProvisioningHelper
1715
1745
  no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
1716
1746
  metadata_array = []
1717
1747
  metadata_index = 0
1748
+ # Keep Current Tags (foo:bar,hello:world)
1749
+ # this is used by clone()
1750
+ if options[:current_tags] && !options[:current_tags].empty?
1751
+ current_tags_string = options[:current_tags].collect { |tag| tag['name'].to_s + '=' + tag['value'].to_s }.join(', ')
1752
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'keepExistingTags', 'type' => 'checkbox', 'fieldLabel' => "Keep existing metadata tags (#{current_tags_string}) ?", 'required' => true, 'description' => 'Whether or not to keep existing metadata tags', 'defaultValue' => true}], options[:options])
1753
+ if ['on','true','1',''].include?(v_prompt['keepExistingTags'].to_s.downcase)
1754
+ options[:current_tags].each do |tag|
1755
+ current_tag = tag.clone
1756
+ current_tag.delete('id')
1757
+ metadata_array << current_tag
1758
+ end
1759
+ end
1760
+ end
1718
1761
  has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
1719
1762
  add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a metadata tag?", {default: false}))
1720
1763
  while add_another_metadata do