morpheus-cli 6.2.2 → 6.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) 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/clusters_interface.rb +7 -0
  5. data/lib/morpheus/api/network_security_server_types_interface.rb +9 -0
  6. data/lib/morpheus/api/network_server_types_interface.rb +9 -0
  7. data/lib/morpheus/api/network_servers_interface.rb +4 -0
  8. data/lib/morpheus/cli/cli_command.rb +1 -0
  9. data/lib/morpheus/cli/commands/clouds.rb +101 -28
  10. data/lib/morpheus/cli/commands/clouds_types.rb +141 -0
  11. data/lib/morpheus/cli/commands/clusters.rb +44 -0
  12. data/lib/morpheus/cli/commands/instances.rb +1 -0
  13. data/lib/morpheus/cli/commands/network_dhcp_relays_command.rb +1 -42
  14. data/lib/morpheus/cli/commands/network_dhcp_servers_command.rb +3 -44
  15. data/lib/morpheus/cli/commands/network_edge_clusters_command.rb +1 -42
  16. data/lib/morpheus/cli/commands/network_firewalls_command.rb +1 -41
  17. data/lib/morpheus/cli/commands/network_pool_servers_command.rb +3 -1
  18. data/lib/morpheus/cli/commands/network_routers_command.rb +4 -6
  19. data/lib/morpheus/cli/commands/network_security_server_types.rb +20 -0
  20. data/lib/morpheus/cli/commands/network_server_types_command.rb +20 -0
  21. data/lib/morpheus/cli/commands/network_servers_command.rb +368 -0
  22. data/lib/morpheus/cli/commands/network_transport_zones_command.rb +1 -41
  23. data/lib/morpheus/cli/commands/networks_command.rb +1 -1
  24. data/lib/morpheus/cli/commands/options.rb +135 -2
  25. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +103 -2
  26. data/lib/morpheus/cli/mixins/networks_helper.rb +62 -0
  27. data/lib/morpheus/cli/mixins/print_helper.rb +28 -7
  28. data/lib/morpheus/cli/mixins/prompt_helper.rb +15 -0
  29. data/lib/morpheus/cli/mixins/provisioning_helper.rb +25 -9
  30. data/lib/morpheus/cli/mixins/rest_command.rb +1 -1
  31. data/lib/morpheus/cli/option_types.rb +3 -3
  32. data/lib/morpheus/cli/version.rb +1 -1
  33. data/lib/morpheus/logging.rb +6 -3
  34. metadata +10 -2
@@ -15,9 +15,22 @@ class Morpheus::Cli::Options
15
15
  end
16
16
 
17
17
  def handle(args)
18
- list(args)
18
+ # todo: probably just make these proper subcommands
19
+ # handle_subcommand(args)
20
+ # handle some special cases that do not conform to name, value
21
+ # This also provides some help on their by documenting the required parameters.
22
+ source_name = args[0]
23
+ if source_name == "networkServices"
24
+ network_services(args[1..-1])
25
+ elsif source_name == "zoneNetworkOptions"
26
+ zone_network_options(args[1..-1])
27
+ else
28
+ list(args)
29
+ end
19
30
  end
20
31
 
32
+ # This is the default handler for the options command.
33
+ # It shows the NAME and VALUE for the list of "data" returned.
21
34
  def list(args)
22
35
  options = {}
23
36
  params = {}
@@ -67,6 +80,9 @@ EOT
67
80
  begin
68
81
  json_response = @options_interface.options_for_source(source_name, params)
69
82
  rescue RestClient::Exception => e
83
+ if Morpheus::Logging.debug? # or options[:debug]
84
+ raise e
85
+ end
70
86
  if e.response && e.response.code == 404
71
87
  raise_command_error("Options source not found by name '#{source_name}'", args, optparse)
72
88
  elsif e.response && e.response.code == 500
@@ -88,8 +104,125 @@ EOT
88
104
  print cyan,"No options found.",reset,"\n"
89
105
  else
90
106
  print as_pretty_table(records, [:name, :value], options)
91
- print_results_pagination(json_response)
107
+ print_results_pagination({size: records.size, total: records.size})
108
+ end
109
+ print reset,"\n"
110
+ end
111
+ return 0, nil
112
+ end
113
+
114
+ # handle some well option sources by name
115
+
116
+ def network_services(args)
117
+ options = {}
118
+ params = {}
119
+ source_name = "networkServices"
120
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
121
+ opts.banner = "Usage: morpheus #{command_name} #{source_name} #{args[0]}"
122
+ # build_standard_list_options(opts, options)
123
+ build_standard_get_options(opts, options)
124
+ opts.footer = <<-EOT
125
+ View list of options for source '#{source_name}'.
126
+ This is the list of network service types (network server types) that can be added.
127
+ EOT
128
+ end
129
+ optparse.parse!(args)
130
+ verify_args!(args:args, optparse:optparse, count: 0)
131
+ connect(options)
132
+ params.merge!(parse_list_options(options))
133
+ @options_interface.setopts(options)
134
+ if options[:dry_run]
135
+ print_dry_run @options_interface.dry.options_for_source(source_name, params)
136
+ return
137
+ end
138
+ json_response = @options_interface.options_for_source(source_name, params)
139
+ render_response(json_response, options, "data") do
140
+ records = json_response["data"].collect {|r| r['services']}.compact.flatten
141
+ print_h1 "Morpheus Options", ["Source: #{source_name}"] + parse_list_subtitles(options), options, ""
142
+ if records.nil? || records.empty?
143
+ print cyan,"No options found.",reset,"\n"
144
+ else
145
+ json_response["data"].each do |data_row|
146
+ if data_row['services'] && !data_row['services'].empty?
147
+ services = []
148
+ data_row['services'].each do |service_row|
149
+ services << {name: service_row['name'], code: service_row['code'] , id: service_row['id'], value: service_row['id']}
150
+ end
151
+ # print_h2 "#{data_row['name']} Options", [], options
152
+ print_h2 "#{data_row['name']}", [], options
153
+ print as_pretty_table(services, [:id, :name, :code], options)
154
+ end
155
+ end
156
+ end
157
+ print_results_pagination({size: records.size, total: records.size})
158
+ print reset,"\n"
159
+ end
160
+ return 0, nil
161
+ end
162
+
163
+ # # this is a really slow one right now, need to look into that.
164
+ # def networks(args)
165
+ # end
166
+
167
+ def zone_network_options(args)
168
+ options = {}
169
+ params = {}
170
+ source_name = "zoneNetworkOptions"
171
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
172
+ opts.banner = "Usage: morpheus #{command_name} #{source_name} #{args[0]}"
173
+ # build_standard_list_options(opts, options)
174
+ build_standard_get_options(opts, options)
175
+ opts.footer = <<-EOT
176
+ View list of options for source '#{source_name}'.
177
+ This is the list of networks available when provisioning to a particular cloud and layout.
178
+
179
+ Required Parameters:
180
+ Cloud ID (zoneId)
181
+ Layout ID (layoutId)
182
+
183
+ Examples:
184
+ options #{source_name} -Q zoneId=40&layoutId=1954
185
+ EOT
186
+ end
187
+ optparse.parse!(args)
188
+ verify_args!(args:args, optparse:optparse, count: 0)
189
+ connect(options)
190
+ params.merge!(parse_list_options(options))
191
+ @options_interface.setopts(options)
192
+ if options[:dry_run]
193
+ print_dry_run @options_interface.dry.options_for_source(source_name, params)
194
+ return
195
+ end
196
+ # This requires Cloud and Layout -Q zoneId=40&layoutId=1954
197
+ # todo: prompt
198
+ json_response = @options_interface.options_for_source(source_name, params)
199
+ render_response(json_response, options, "data") do
200
+ # This is different, data is a Hash, not an Array...
201
+ networks = json_response["data"]["networks"]
202
+ network_groups = json_response["data"]["networkGroups"]
203
+ network_subnets = json_response["data"]["networkSubnets"]
204
+ records = [networks, network_groups, network_subnets].compact.flatten
205
+ print_h1 "Morpheus Options", ["Source: #{source_name}"] + parse_list_subtitles(options), options, ""
206
+ if records.nil? || records.empty?
207
+ print cyan,"No options found.",reset,"\n"
208
+ else
209
+ if networks && !networks.empty?
210
+ print_h2 "Networks", [], options
211
+ rows = networks.collect {|row| {name: row['name'], value: row['id']} }
212
+ print as_pretty_table(rows, [:name, :value], options)
213
+ end
214
+ if network_groups && !network_groups.empty?
215
+ print_h2 "Network Groups", [], options
216
+ rows = network_groups.collect {|row| {name: row['name'], value: row['id']} }
217
+ print as_pretty_table(rows, [:name, :value], options)
218
+ end
219
+ if network_subnets && !network_subnets.empty?
220
+ print_h2 "Subnets", [], options
221
+ rows = network_subnets.collect {|row| {name: row['name'], value: row['id']} }
222
+ print as_pretty_table(rows, [:name, :value], options)
223
+ end
92
224
  end
225
+ print_results_pagination({size: records.size, total: records.size})
93
226
  print reset,"\n"
94
227
  end
95
228
  return 0, nil
@@ -137,6 +137,7 @@ module Morpheus::Cli::InfrastructureHelper
137
137
  return cloud_type_for_name(val)
138
138
  end
139
139
  end
140
+
140
141
  def cloud_type_for_id(id)
141
142
  return get_available_cloud_types().find { |z| z['id'].to_i == id.to_i}
142
143
  end
@@ -633,7 +634,6 @@ module Morpheus::Cli::InfrastructureHelper
633
634
  "Name" => lambda {|it| it['name'] },
634
635
  "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
635
636
  "URL" => lambda {|it| it['serviceUrl'] },
636
- #"Pools" => lambda {|it| it['pools'] ? anded_list(it['pools'].collect {|p| p['name'] }, 3) : '' },
637
637
  "Enabled" => lambda {|it| format_boolean(it['enabled']) },
638
638
  "Status" => lambda {|it| format_network_pool_server_status(it) },
639
639
  "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
@@ -661,7 +661,6 @@ module Morpheus::Cli::InfrastructureHelper
661
661
  "Extra Attributes" => lambda {|it| it['config'] ? it['config']['extraAttributes'] : nil },
662
662
  "Enabled" => lambda {|it| format_boolean(it['enabled']) },
663
663
  "Status" => lambda {|it| format_network_pool_server_status(it) },
664
- #"Pools" => lambda {|it| it['pools'] ? anded_list(it['pools'].collect {|p| p['name'] }, 3) : '' },
665
664
  "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
666
665
  "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
667
666
  }
@@ -706,4 +705,106 @@ module Morpheus::Cli::InfrastructureHelper
706
705
  }
707
706
  end
708
707
 
708
+ def find_network_server_type_by_name_or_id(val)
709
+ if val.to_s =~ /\A\d{1,}\Z/
710
+ return find_network_server_type_by_id(val)
711
+ else
712
+ # always find by code too
713
+ #return find_network_server_type_by_name(val)
714
+ return find_network_server_type_by_name_or_code(val)
715
+ end
716
+ end
717
+
718
+ def find_network_server_type_by_id(id)
719
+ begin
720
+ json_response = @network_server_types_interface.get(id.to_i)
721
+ return json_response['networkServerType']
722
+ rescue RestClient::Exception => e
723
+ if e.response && e.response.code == 404
724
+ print_red_alert "Network Server Type not found by id #{id}"
725
+ return nil
726
+ else
727
+ raise e
728
+ end
729
+ end
730
+ end
731
+
732
+ def find_network_server_type_by_name(name)
733
+ json_response = @network_server_types_interface.list({name: name.to_s})
734
+ network_server_types = json_response['networkServerTypes']
735
+ if network_server_types.empty?
736
+ print_red_alert "Network Server Type not found by name #{name}"
737
+ return nil
738
+ elsif network_server_types.size > 1
739
+ print_red_alert "#{network_server_types.size} network server types found by name #{name}"
740
+ # print_networks_table(networks, {color: red})
741
+ rows = network_server_types.collect do |it|
742
+ {id: it['id'], name: it['name']}
743
+ end
744
+ puts as_pretty_table(rows, [:id, :code, :name], {color:red})
745
+ return nil
746
+ else
747
+ return network_server_types[0]
748
+ end
749
+ end
750
+
751
+ def find_network_server_type_by_name_or_code(name)
752
+ json_response = @network_server_types_interface.list({phrase: name.to_s, max: 100})
753
+ downcase_name = name.to_s.downcase
754
+ network_server_types = json_response['networkServerTypes'].select { |it|
755
+ it['code'].to_s.downcase == downcase_name || it['name'].to_s.downcase == downcase_name
756
+ }
757
+ if network_server_types.empty?
758
+ print_red_alert "Network Server Type not found by name or code '#{name}'"
759
+ return nil
760
+ elsif network_server_types.size > 1
761
+ print_red_alert "#{network_server_types.size} network server types found with name or code '#{name}'"
762
+ # print_networks_table(networks, {color: red})
763
+ rows = network_server_types.collect do |it|
764
+ {id: it['id'], name: it['name']}
765
+ end
766
+ puts as_pretty_table(rows, [:id, :code, :name], {color:red})
767
+ return nil
768
+ else
769
+ return network_server_types[0]
770
+ end
771
+ end
772
+
773
+ def network_server_type_list_column_definitions(options)
774
+ {
775
+ "ID" => 'id',
776
+ "Name" => 'name',
777
+ "Code" => 'code',
778
+ "Description" => 'description',
779
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) }
780
+ }
781
+ end
782
+
783
+ def network_server_type_column_definitions(options)
784
+ {
785
+ "ID" => 'id',
786
+ "Name" => 'name',
787
+ "Code" => 'code',
788
+ "Description" => 'description',
789
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
790
+ "Selectable" => lambda {|it| format_boolean(it['selectable']) },
791
+ "Creatable" => lambda {|it| format_boolean(it['creatable']) },
792
+ "Plugin" => lambda {|it| format_boolean(it['isPlugin']) },
793
+ "Embedded" => lambda {|it| format_boolean(it['isEmbedded']) },
794
+ #"Integration Code" => lambda {|it| it['integrationCode'] },
795
+ "Networks" => lambda {|it| format_boolean(it['hasNetworks']) },
796
+ "Gateways" => lambda {|it| format_boolean(it['hasGateways']) },
797
+ "DHCP Servers" => lambda {|it| format_boolean(it['hasDhcpServers']) },
798
+ "DHCP Relays" => lambda {|it| format_boolean(it['hasDhcpRelays']) },
799
+ # "Route Tables" => lambda {|it| format_boolean(it['hasRouteTables']) },
800
+ "Routers" => lambda {|it| format_boolean(it['hasRouters']) },
801
+ "Switches" => lambda {|it| format_boolean(it['hasSwitches']) },
802
+ "Firewall" => lambda {|it| format_boolean(it['hasFirewall']) },
803
+ "Security Groups" => lambda {|it| format_boolean(it['hasSecurityGroups']) },
804
+ "Load Balancers" => lambda {|it| format_boolean(it['hasLoadBalancers']) },
805
+ # "Security Code" => lambda {|it| it['securityCode'] },
806
+ # "User Visible" => lambda {|it| format_boolean(it['userVisible']) },
807
+ }
808
+ end
809
+
709
810
  end
@@ -0,0 +1,62 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ require 'morpheus/cli/option_types'
3
+ require 'morpheus/rest_client'
4
+ # Mixin for Morpheus::Cli command classes
5
+ # Provides common methods for networking commands
6
+ module Morpheus::Cli::NetworksHelper
7
+
8
+ def self.included(klass)
9
+ klass.send :include, Morpheus::Cli::PrintHelper
10
+ end
11
+
12
+ def network_servers_interface
13
+ # @api_client.network_servers
14
+ raise "#{self.class} has not defined @network_servers_interface" if @network_servers_interface.nil?
15
+ @network_servers_interface
16
+ end
17
+
18
+ def find_network_server(val)
19
+ if val.to_s =~ /\A\d{1,}\Z/
20
+ return find_network_server_by_id(val)
21
+ else
22
+ if server = find_network_server_by_name(val)
23
+ return find_network_server_by_id(server['id'])
24
+ end
25
+ end
26
+ end
27
+
28
+ def find_network_server_by_id(id)
29
+ begin
30
+ # Use query parameter `details=true` to get the full type object with all its configuration settings and optionTypes
31
+ json_response = @network_servers_interface.get(id.to_i, {details:true})
32
+ return json_response['networkServer']
33
+ rescue RestClient::Exception => e
34
+ if e.response && e.response.code == 404
35
+ print_red_alert "Network Server not found by id #{id}"
36
+ return nil
37
+ else
38
+ raise e
39
+ end
40
+ end
41
+ end
42
+
43
+ def find_network_server_by_name(name)
44
+ # Use query parameter `details=true` to get the full type object with all its configuration settings and optionTypes
45
+ json_response = @network_servers_interface.list({phrase: name.to_s, details:true})
46
+ servers = json_response['networkServers']
47
+ if servers.empty?
48
+ print_red_alert "Network Server not found by name #{name}"
49
+ return nil
50
+ elsif servers.size > 1
51
+ print_red_alert "#{servers.size} network servers found by name #{name}"
52
+ rows = servers.collect do |it|
53
+ {id: it['id'], name: it['name']}
54
+ end
55
+ puts as_pretty_table(rows, [:id, :name], {color:red})
56
+ return nil
57
+ else
58
+ return servers[0]
59
+ end
60
+ end
61
+
62
+ end
@@ -58,7 +58,7 @@ module Morpheus::Cli::PrintHelper
58
58
  # title - subtitle1, subtitle2
59
59
  # ==================
60
60
  #
61
- def print_h1(title, subtitles=nil, options=nil)
61
+ def print_h1(title, subtitles=nil, options=nil, suffix_content="\n")
62
62
  # ok, support all these formats for now:
63
63
  # print_h1(title, options={})
64
64
  # print_h1(title, subtitles, options={})
@@ -89,14 +89,18 @@ module Morpheus::Cli::PrintHelper
89
89
  end
90
90
  out << "\n"
91
91
  if options[:border_style] == :thin
92
- out << "\n"
92
+
93
93
  else
94
- out << "#{color}#{bold}==================#{reset}\n\n"
94
+ out << "#{color}#{bold}==================#{reset}\n"
95
+ end
96
+ # Default suffix_content is typically one extra newline
97
+ if !suffix_content.to_s.empty?
98
+ out << suffix_content.to_s
95
99
  end
96
100
  print out
97
101
  end
98
102
 
99
- def print_h2(title, subtitles=nil, options=nil)
103
+ def print_h2(title, subtitles=nil, options=nil, suffix_content="\n")
100
104
  # ok, support all these formats for now:
101
105
  # print_h2(title={})
102
106
  # print_h2(title, options={})
@@ -117,9 +121,13 @@ module Morpheus::Cli::PrintHelper
117
121
  end
118
122
  out << "\n"
119
123
  if options[:border_style] == :thin
120
- out << "\n"
124
+
121
125
  else
122
- out << "#{color}---------------------#{reset}\n\n"
126
+ out << "#{color}---------------------#{reset}\n"
127
+ end
128
+ # Default suffix_content is typically one extra newline
129
+ if !suffix_content.to_s.empty?
130
+ out << suffix_content.to_s
123
131
  end
124
132
  print out
125
133
  end
@@ -1505,8 +1513,21 @@ module Morpheus::Cli::PrintHelper
1505
1513
  def format_option_types_table(option_types, options={}, domain_name=nil)
1506
1514
  columns = [
1507
1515
  {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
1508
- {"FIELD NAME" => lambda {|it| [it['fieldContext'] == domain_name ? nil : it['fieldContext'], it['fieldName']].select {|it| !it.to_s.empty? }.join('.') } },
1516
+ {"FIELD NAME" => lambda {|it|
1517
+ if it['fieldContext'] && it['fieldContext'] != domain_name && it['fieldContext'] != 'domain'
1518
+ "#{it['fieldContext']}.#{it['fieldName']}"
1519
+ else
1520
+ "#{it['fieldName']}"
1521
+ end
1522
+ } },
1509
1523
  {"TYPE" => lambda {|it| it['type'] } },
1524
+ {"OPTION SOURCE" => lambda {|it|
1525
+ if it['optionSourceType']
1526
+ "#{it['optionSourceType']}/#{it['optionSource']}"
1527
+ else
1528
+ "#{it['optionSource']}"
1529
+ end
1530
+ } },
1510
1531
  {"DEFAULT" => lambda {|it| it['defaultValue'] } },
1511
1532
  {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
1512
1533
  ]
@@ -0,0 +1,15 @@
1
+ # Mixin for Morpheus::Cli command classes
2
+ # Provides common methods for prompting for input
3
+ module Morpheus::Cli::PromptHelper
4
+
5
+ # prompt for a single option type and and return the input value
6
+ # @param option_type [Hash] The OptionType input record to prompt for , contians fieldName, fieldLabel, etc.
7
+ # @param options [Hash] The context being constructed, checks this for the value before prompting the user for input.
8
+ # @param no_prompt [Boolean] The context being constructed, checks this for the value before prompting the user for input.
9
+ # @param api_params [Hash] Optional map of parameters to include in API request for select option types
10
+ # @return input value for the option type, usually a string or number if the value is an ID or of type: number
11
+ def prompt_value(option_type, options, no_prompt=false, api_params={})
12
+ # this does not work with fieldContext, so get rid of it
13
+ return Morpheus::Cli::OptionTypes.prompt([option_type.merge({'fieldContext' => nil})], options, @api_client, api_params, no_prompt)[option_type['fieldName']]
14
+ end
15
+ end
@@ -915,8 +915,8 @@ module Morpheus::Cli::ProvisioningHelper
915
915
 
916
916
  # Security Groups
917
917
  # look for securityGroups option type... this is old and goofy
918
- sg_option_type = option_type_list.find {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
919
- option_type_list = option_type_list.reject {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['name'] == 'securityId')) }
918
+ sg_option_type = option_type_list.find {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['fieldName'] == 'securityId' || opt['name'] == 'securityId')) }
919
+ option_type_list = option_type_list.reject {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['fieldName'] == 'securityId' || opt['name'] == 'securityId')) }
920
920
  if locked_fields.include?('securityGroups')
921
921
  # payload['securityGroups'] = options[:options]['securityGroups'] if options[:options]['securityGroups']
922
922
  else
@@ -924,19 +924,35 @@ module Morpheus::Cli::ProvisioningHelper
924
924
  # ok.. seed data has changed and serverTypes do not have this optionType anymore...
925
925
  if sg_option_type.nil?
926
926
  if provision_type && (provision_type["code"] == 'amazon')
927
- sg_option_type = {'fieldContext' => 'config', 'fieldName' => 'securityId', 'type' => 'select', 'fieldLabel' => 'Security Group', 'optionSource' => 'amazonSecurityGroup', 'required' => true, 'description' => 'Select security group.', 'defaultValue' => options[:default_security_group]}
927
+ sg_option_type = {'fieldContext' => 'config', 'fieldName' => 'securityId', 'type' => 'select', 'fieldLabel' => 'Security Group', 'optionSource' => 'amazonSecurityGroup', 'optionSourceType' => 'amazon', 'required' => true, 'description' => 'Select security group.', 'defaultValue' => options[:default_security_group]}
928
928
  end
929
929
  end
930
930
  sg_api_params = {zoneId: cloud_id, poolId: pool_id}
931
- has_security_groups = !!sg_option_type
932
- available_security_groups = []
933
- if sg_option_type && sg_option_type['type'] == 'select' && sg_option_type['optionSource']
934
- sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params, sg_option_type['optionSourceType'])
935
- available_security_groups = sg_option_results['data'].collect do |it|
936
- {"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
931
+ # The amazon plugin uses a new optionSource options/amazon/awsPluginEc2SecurityGroup
932
+ # which expects parameter config.resourcePoolId=pool-ID
933
+ if sg_option_type
934
+ if sg_option_type['optionSource'] == 'awsPluginEc2SecurityGroup'
935
+ if pool_id
936
+ sg_api_params[:config] ||= {}
937
+ sg_api_params[:config][:resourcePoolId] = pool_id
938
+ end
939
+ # convert multiSelect to select to make prompt_security_groups() work
940
+ # though we should should be able to skip the prompt_security_groups and use multiSelect instead
941
+ sg_option_type['type'] = 'select' if sg_option_type['type'] == 'multiSelect'
942
+ sg_option_type['type'] = 'typeahead' if sg_option_type['type'] == 'multiTypeahead'
943
+ sg_option_type['fieldLabel'] = 'Security Group' if sg_option_type['fieldLabel'] == 'Security Groups'
944
+ sg_option_type['required'] = true
937
945
  end
938
946
  end
947
+ has_security_groups = !!sg_option_type
939
948
  if options[:security_groups]
949
+ available_security_groups = []
950
+ if sg_option_type && sg_option_type['optionSource']
951
+ sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params, sg_option_type['optionSourceType'])
952
+ available_security_groups = sg_option_results['data'].collect do |it|
953
+ {"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
954
+ end
955
+ end
940
956
  # work with id or names, API expects ids though.
941
957
  payload['securityGroups'] = options[:security_groups].collect {|sg_id|
942
958
  found_sg = available_security_groups.find {|it| sg_id && (sg_id.to_s == it['id'].to_s || sg_id.to_s == it['name'].to_s) }
@@ -982,7 +982,7 @@ EOT
982
982
  # print_description_list(config.keys, config)
983
983
  # end
984
984
  # Option Types
985
- if record['optionTypes'] && record['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.size > 0
985
+ if record['optionTypes'] && record['optionTypes'].size > 0
986
986
  print_h2 "Option Types", options
987
987
  print format_option_types_table(record['optionTypes'], options, rest_object_key)
988
988
  end
@@ -673,9 +673,9 @@ module Morpheus
673
673
  if input.empty? && default_value
674
674
  input = default_value.to_s
675
675
  end
676
- matched_option = select_options.find{|it| (!it['value'].nil? && it['value'].to_s == input) || (!it[value_field].nil? && it[value_field].to_s == input) || (it[value_field].nil? && input.empty?)}
676
+ matched_option = (select_options || []).find{|it| (!it['value'].nil? && it['value'].to_s == input) || (!it[value_field].nil? && it[value_field].to_s == input) || (it[value_field].nil? && input.empty?)}
677
677
  if matched_option.nil?
678
- matched_options = select_options.select {|it| it['name'] == input } # should probably be case insensitive
678
+ matched_options = (select_options || []).select {|it| it['name'] == input } # should probably be case insensitive
679
679
  if matched_options.size > 1
680
680
  print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{input}]\n\n", Term::ANSIColor.reset
681
681
  print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
@@ -699,7 +699,7 @@ module Morpheus
699
699
 
700
700
  if input == '?'
701
701
  help_prompt(option_type)
702
- display_select_options(option_type, select_options, paging)
702
+ display_select_options(option_type, (select_options || []), paging)
703
703
  if paging
704
704
  paging[:cur_page] = (paging[:cur_page] + 1) * paging[:page_size] < paging[:total] ? paging[:cur_page] + 1 : 0
705
705
  end
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "6.2.2"
4
+ VERSION = "6.2.3"
5
5
  end
6
6
  end
@@ -94,9 +94,12 @@ module Morpheus::Logging
94
94
  end
95
95
  msg.gsub!(/password\"\: "[^"]+/, 'password": "************') # json properties ending with password
96
96
  msg.gsub!(/Password\"\: "[^"]+/, 'Password": "************') # json properties ending with Password
97
- msg.gsub!(/password\"\s?\=\>\s?\"[^"]+/i, 'password"=>"************')
98
- msg.gsub!(/password\=\"[^"]+/i, 'password="************')
99
- msg.gsub!(/password\=[^"'&]+/i, 'password=************') # buggy, wont work with ampersand or quotes in passwords! heh
97
+ msg.gsub!(/password\"\s?\=\>\s?\"[^"]+/, 'password"=>"************')
98
+ msg.gsub!(/Password\"\s?\=\>\s?\"[^"]+/, 'Password"=>"************')
99
+ msg.gsub!(/password\=\"[^"]+/, 'password="************')
100
+ msg.gsub!(/Password\=\"[^"]+/, 'Password="************')
101
+ msg.gsub!(/password\=[^"'&]+/, 'password=************') # buggy, wont work with ampersand or quotes in passwords! heh
102
+ msg.gsub!(/Password\=[^"'&]+/, 'Password=************')
100
103
  msg.gsub!(/passwordConfirmation\=[^" ]+/i, 'passwordConfirmation="************')
101
104
  msg.gsub!(/passwordConfirmation\=[^" ]+/i, 'passwordConfirmation=************')
102
105
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.2
4
+ version: 6.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-09-13 00:00:00.000000000 Z
14
+ date: 2023-10-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -291,8 +291,10 @@ files:
291
291
  - lib/morpheus/api/network_pools_interface.rb
292
292
  - lib/morpheus/api/network_proxies_interface.rb
293
293
  - lib/morpheus/api/network_routers_interface.rb
294
+ - lib/morpheus/api/network_security_server_types_interface.rb
294
295
  - lib/morpheus/api/network_security_servers_interface.rb
295
296
  - lib/morpheus/api/network_server_groups_interface.rb
297
+ - lib/morpheus/api/network_server_types_interface.rb
296
298
  - lib/morpheus/api/network_servers_interface.rb
297
299
  - lib/morpheus/api/network_services_interface.rb
298
300
  - lib/morpheus/api/network_static_routes_interface.rb
@@ -391,6 +393,7 @@ files:
391
393
  - lib/morpheus/cli/commands/cloud_folders_command.rb
392
394
  - lib/morpheus/cli/commands/cloud_resource_pools_command.rb
393
395
  - lib/morpheus/cli/commands/clouds.rb
396
+ - lib/morpheus/cli/commands/clouds_types.rb
394
397
  - lib/morpheus/cli/commands/clusters.rb
395
398
  - lib/morpheus/cli/commands/coloring_command.rb
396
399
  - lib/morpheus/cli/commands/containers_command.rb
@@ -469,7 +472,10 @@ files:
469
472
  - lib/morpheus/cli/commands/network_pools_command.rb
470
473
  - lib/morpheus/cli/commands/network_proxies_command.rb
471
474
  - lib/morpheus/cli/commands/network_routers_command.rb
475
+ - lib/morpheus/cli/commands/network_security_server_types.rb
472
476
  - lib/morpheus/cli/commands/network_server_groups_command.rb
477
+ - lib/morpheus/cli/commands/network_server_types_command.rb
478
+ - lib/morpheus/cli/commands/network_servers_command.rb
473
479
  - lib/morpheus/cli/commands/network_services_command.rb
474
480
  - lib/morpheus/cli/commands/network_static_routes_command.rb
475
481
  - lib/morpheus/cli/commands/network_transport_zones_command.rb
@@ -552,10 +558,12 @@ files:
552
558
  - lib/morpheus/cli/mixins/load_balancers_helper.rb
553
559
  - lib/morpheus/cli/mixins/logs_helper.rb
554
560
  - lib/morpheus/cli/mixins/monitoring_helper.rb
561
+ - lib/morpheus/cli/mixins/networks_helper.rb
555
562
  - lib/morpheus/cli/mixins/operations_helper.rb
556
563
  - lib/morpheus/cli/mixins/option_source_helper.rb
557
564
  - lib/morpheus/cli/mixins/print_helper.rb
558
565
  - lib/morpheus/cli/mixins/processes_helper.rb
566
+ - lib/morpheus/cli/mixins/prompt_helper.rb
559
567
  - lib/morpheus/cli/mixins/provisioning_helper.rb
560
568
  - lib/morpheus/cli/mixins/remote_helper.rb
561
569
  - lib/morpheus/cli/mixins/rest_command.rb