morpheus-cli 5.2.4.1 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +1 -3
  4. data/lib/morpheus/api/api_client.rb +48 -14
  5. data/lib/morpheus/api/certificate_types_interface.rb +14 -0
  6. data/lib/morpheus/api/certificates_interface.rb +9 -0
  7. data/lib/morpheus/api/integration_types_interface.rb +14 -0
  8. data/lib/morpheus/api/integrations_interface.rb +7 -22
  9. data/lib/morpheus/api/network_services_interface.rb +14 -0
  10. data/lib/morpheus/api/read_interface.rb +23 -0
  11. data/lib/morpheus/api/rest_interface.rb +12 -10
  12. data/lib/morpheus/api/roles_interface.rb +7 -0
  13. data/lib/morpheus/api/servers_interface.rb +7 -0
  14. data/lib/morpheus/api/user_settings_interface.rb +38 -18
  15. data/lib/morpheus/api/vdi_allocations_interface.rb +9 -0
  16. data/lib/morpheus/api/vdi_apps_interface.rb +9 -0
  17. data/lib/morpheus/api/vdi_gateways_interface.rb +9 -0
  18. data/lib/morpheus/api/vdi_interface.rb +28 -0
  19. data/lib/morpheus/api/vdi_pools_interface.rb +19 -0
  20. data/lib/morpheus/cli.rb +9 -2
  21. data/lib/morpheus/cli/activity_command.rb +7 -4
  22. data/lib/morpheus/cli/apps.rb +59 -75
  23. data/lib/morpheus/cli/catalog_item_types_command.rb +13 -13
  24. data/lib/morpheus/cli/certificates_command.rb +575 -0
  25. data/lib/morpheus/cli/cli_command.rb +61 -6
  26. data/lib/morpheus/cli/clouds.rb +1 -0
  27. data/lib/morpheus/cli/clusters.rb +5 -2
  28. data/lib/morpheus/cli/commands/standard/history_command.rb +4 -5
  29. data/lib/morpheus/cli/commands/standard/man_command.rb +4 -5
  30. data/lib/morpheus/cli/dashboard_command.rb +3 -3
  31. data/lib/morpheus/cli/execution_request_command.rb +15 -5
  32. data/lib/morpheus/cli/hosts.rb +245 -224
  33. data/lib/morpheus/cli/instances.rb +150 -167
  34. data/lib/morpheus/cli/integrations_command.rb +588 -41
  35. data/lib/morpheus/cli/invoices_command.rb +23 -46
  36. data/lib/morpheus/cli/login.rb +7 -0
  37. data/lib/morpheus/cli/mixins/option_source_helper.rb +15 -16
  38. data/lib/morpheus/cli/mixins/print_helper.rb +36 -18
  39. data/lib/morpheus/cli/mixins/provisioning_helper.rb +3 -3
  40. data/lib/morpheus/cli/mixins/vdi_helper.rb +246 -0
  41. data/lib/morpheus/cli/network_domains_command.rb +2 -2
  42. data/lib/morpheus/cli/network_routers_command.rb +22 -9
  43. data/lib/morpheus/cli/networks_command.rb +2 -2
  44. data/lib/morpheus/cli/option_types.rb +34 -33
  45. data/lib/morpheus/cli/remote.rb +3 -2
  46. data/lib/morpheus/cli/reports_command.rb +5 -2
  47. data/lib/morpheus/cli/roles.rb +215 -55
  48. data/lib/morpheus/cli/service_plans_command.rb +4 -1
  49. data/lib/morpheus/cli/subnets_command.rb +11 -2
  50. data/lib/morpheus/cli/user_settings_command.rb +268 -57
  51. data/lib/morpheus/cli/vdi_allocations_command.rb +159 -0
  52. data/lib/morpheus/cli/vdi_apps_command.rb +317 -0
  53. data/lib/morpheus/cli/vdi_command.rb +359 -0
  54. data/lib/morpheus/cli/vdi_gateways_command.rb +290 -0
  55. data/lib/morpheus/cli/vdi_pools_command.rb +571 -0
  56. data/lib/morpheus/cli/version.rb +1 -1
  57. data/lib/morpheus/rest_client.rb +30 -0
  58. data/lib/morpheus/terminal.rb +15 -7
  59. metadata +18 -2
@@ -140,32 +140,32 @@ class Morpheus::Cli::InvoicesCommand
140
140
  # construct params
141
141
  params.merge!(parse_list_options(options))
142
142
  if options[:clouds]
143
- cloud_ids = parse_cloud_id_list(options[:clouds])
143
+ cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
144
144
  return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
145
145
  params['zoneId'] = cloud_ids
146
146
  end
147
147
  if options[:groups]
148
- group_ids = parse_group_id_list(options[:groups])
148
+ group_ids = parse_group_id_list(options[:groups], {}, false, true)
149
149
  return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
150
150
  params['siteId'] = group_ids
151
151
  end
152
152
  if options[:instances]
153
- instance_ids = parse_instance_id_list(options[:instances])
153
+ instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
154
154
  return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
155
155
  params['instanceId'] = instance_ids
156
156
  end
157
157
  if options[:servers]
158
- server_ids = parse_server_id_list(options[:servers])
158
+ server_ids = parse_server_id_list(options[:servers], {}, false, true)
159
159
  return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
160
160
  params['serverId'] = server_ids
161
161
  end
162
162
  if options[:users]
163
- user_ids = parse_user_id_list(options[:users])
163
+ user_ids = parse_user_id_list(options[:users], {}, false, true)
164
164
  return 1, "users not found for #{options[:users]}" if user_ids.nil?
165
165
  params['userId'] = user_ids
166
166
  end
167
167
  if options[:projects]
168
- project_ids = parse_project_id_list(options[:projects])
168
+ project_ids = parse_project_id_list(options[:projects], {}, false, true)
169
169
  return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
170
170
  params['projectId'] = project_ids
171
171
  end
@@ -636,37 +636,20 @@ Update an invoice.
636
636
  params = {}
637
637
  payload = {}
638
638
  optparse = Morpheus::Cli::OptionParser.new do |opts|
639
- opts.banner = subcommand_usage("[--daily] [--costing] [--current] [-c CLOUD]")
640
- opts.on( '--daily', "Refresh Daily Invoices" ) do
641
- payload[:daily] = true
642
- end
643
- opts.on( '--costing', "Refresh Costing Data" ) do
644
- payload[:costing] = true
645
- end
646
- opts.on( '--current', "Collect the most up to date costing data." ) do
647
- payload[:current] = true
648
- end
649
- opts.on( '--date DATE', String, "Date to collect costing for. By default the cost data is collected for the end of the previous period." ) do |val|
650
- payload[:date] = val.to_s
651
- end
652
- opts.on( '-c', '--cloud CLOUD', "Specify cloud(s) to refresh costing for." ) do |val|
639
+ opts.banner = subcommand_usage("[-c CLOUD]")
640
+ opts.on( '-c', '--clouds CLOUD', "Specify clouds to refresh costing for." ) do |val|
653
641
  payload[:clouds] ||= []
654
642
  payload[:clouds] << val
655
643
  end
656
- opts.on( '--all', "Refresh costing for all clouds." ) do
644
+ opts.on( '--all', "Refresh costing for all clouds. This can be used instead of --clouds" ) do
657
645
  payload[:all] = true
658
646
  end
659
- # opts.on( '-f', '--force', "Force Refresh" ) do
660
- # query_params[:force] = 'true'
661
- # end
647
+ opts.on( '--date DATE', String, "Date to collect costing for. By default the cost data is collected for the end of the previous job interval (hour or day)." ) do |val|
648
+ payload[:date] = val.to_s
649
+ end
662
650
  build_standard_update_options(opts, options, [:query, :auto_confirm])
663
651
  opts.footer = <<-EOT
664
- Refresh invoices.
665
- By default, nothing is changed.
666
- Include --daily to regenerate invoice records.
667
- Include --costing to refresh actual costing data.
668
- Include --current to refresh costing data for the actual current time.
669
- To get the latest invoice costing data, include --daily --costing --current --all
652
+ Refresh invoice costing data for the specified clouds.
670
653
  EOT
671
654
  end
672
655
  optparse.parse!(args)
@@ -677,17 +660,11 @@ EOT
677
660
  payload = options[:payload]
678
661
  end
679
662
  payload.deep_merge!(parse_passed_options(options))
680
- # --clouds
663
+ # --clouds lookup ID for name
681
664
  if payload[:clouds]
682
- payload[:clouds] = parse_id_list(payload[:clouds]).collect {|cloud_id|
683
- if cloud_id.to_s =~ /\A\d{1,}\Z/
684
- cloud_id
685
- else
686
- cloud = find_cloud_option(cloud_id)
687
- return 1 if cloud.nil?
688
- cloud['id']
689
- end
690
- }
665
+ cloud_ids = parse_cloud_id_list(payload[:clouds], {}, false, true)
666
+ return 1, "clouds not found for #{payload[:clouds]}" if cloud_ids.nil?
667
+ payload[:clouds] = cloud_ids
691
668
  end
692
669
  # are you sure?
693
670
  unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to refresh invoices?")
@@ -831,32 +808,32 @@ EOT
831
808
  # construct params
832
809
  params.merge!(parse_list_options(options))
833
810
  if options[:clouds]
834
- cloud_ids = parse_cloud_id_list(options[:clouds])
811
+ cloud_ids = parse_cloud_id_list(options[:clouds], {}, false, true)
835
812
  return 1, "clouds not found for #{options[:clouds]}" if cloud_ids.nil?
836
813
  params['zoneId'] = cloud_ids
837
814
  end
838
815
  if options[:groups]
839
- group_ids = parse_group_id_list(options[:groups])
816
+ group_ids = parse_group_id_list(options[:groups], {}, false, true)
840
817
  return 1, "groups not found for #{options[:groups]}" if group_ids.nil?
841
818
  params['siteId'] = group_ids
842
819
  end
843
820
  if options[:instances]
844
- instance_ids = parse_instance_id_list(options[:instances])
821
+ instance_ids = parse_instance_id_list(options[:instances], {}, false, true)
845
822
  return 1, "instances not found for #{options[:instances]}" if instance_ids.nil?
846
823
  params['instanceId'] = instance_ids
847
824
  end
848
825
  if options[:servers]
849
- server_ids = parse_server_id_list(options[:servers])
826
+ server_ids = parse_server_id_list(options[:servers], {}, false, true)
850
827
  return 1, "servers not found for #{options[:servers]}" if server_ids.nil?
851
828
  params['serverId'] = server_ids
852
829
  end
853
830
  if options[:users]
854
- user_ids = parse_user_id_list(options[:users])
831
+ user_ids = parse_user_id_list(options[:users], {}, false, true)
855
832
  return 1, "users not found for #{options[:users]}" if user_ids.nil?
856
833
  params['userId'] = user_ids
857
834
  end
858
835
  if options[:projects]
859
- project_ids = parse_project_id_list(options[:projects])
836
+ project_ids = parse_project_id_list(options[:projects], {}, false, true)
860
837
  return 1, "projects not found for #{options[:projects]}" if project_ids.nil?
861
838
  params['projectId'] = project_ids
862
839
  end
@@ -36,6 +36,13 @@ class Morpheus::Cli::Login
36
36
  opts.on( '-p', '--password PASSWORD', "Password" ) do |val|
37
37
  password = val
38
38
  end
39
+ opts.on( '--password-file FILE', String, "Password File, read a file containing the password." ) do |val|
40
+ password_file = File.expand_path(val)
41
+ if !File.exists?(password_file) || !File.file?(password_file) # check readable too
42
+ raise ::OptionParser::InvalidOption.new("File not found: #{password_file}")
43
+ end
44
+ password = File.read(password_file) #.to_s.split("\n").first.strip
45
+ end
39
46
  opts.on( '-t', '--test', "Test credentials only, does not update stored credentials for the appliance." ) do
40
47
  options[:test_only] = true
41
48
  end
@@ -178,7 +178,7 @@ module Morpheus::Cli::OptionSourceHelper
178
178
  # todo: some other common ones, accounts (tenants), etc.
179
179
  # todo: a generic set of parse and find methods like
180
180
  # like this:
181
- def parse_option_source_id_list(option_source, id_list, api_params={}, refresh=false)
181
+ def parse_option_source_id_list(option_source, id_list, api_params={}, refresh=false, allow_any_id=false)
182
182
  option_source_label = option_source.to_s # .capitalize
183
183
  option_data = load_option_source_data(option_source, api_params, refresh)
184
184
  found_ids = []
@@ -189,9 +189,8 @@ module Morpheus::Cli::OptionSourceHelper
189
189
  # never match blank nil or empty strings
190
190
  print_red_alert "#{option_source_label} cannot be not found by with a blank id!"
191
191
  return nil
192
- # elsif record_id.to_s =~ /\A\d{1,}\Z/
193
- # # always allow any ID for now..
194
- # found_ids << record_id
192
+ elsif allow_any_id && record_id.to_s =~ /\A\d{1,}\Z/
193
+ found_ids << record_id.to_i
195
194
  else
196
195
  # search with in a presedence by value, then name, then id (usually same as value)
197
196
  # exact match on value first.
@@ -228,28 +227,28 @@ module Morpheus::Cli::OptionSourceHelper
228
227
  return found_ids
229
228
  end
230
229
 
231
- def parse_cloud_id_list(id_list, api_params={}, refresh=false)
232
- parse_option_source_id_list('clouds', id_list, api_params, refresh)
230
+ def parse_cloud_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
231
+ parse_option_source_id_list('clouds', id_list, api_params, refresh, allow_any_id)
233
232
  end
234
233
 
235
- def parse_group_id_list(id_list, api_params={}, refresh=false)
236
- parse_option_source_id_list('groups', id_list, api_params, refresh)
234
+ def parse_group_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
235
+ parse_option_source_id_list('groups', id_list, api_params, refresh, allow_any_id)
237
236
  end
238
237
 
239
- def parse_user_id_list(id_list, api_params={}, refresh=false)
240
- parse_option_source_id_list('users', id_list, api_params, refresh)
238
+ def parse_user_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
239
+ parse_option_source_id_list('users', id_list, api_params, refresh, allow_any_id)
241
240
  end
242
241
 
243
- def parse_tenant_id_list(id_list, api_params={}, refresh=false)
244
- parse_option_source_id_list('allTenants', id_list, api_params, refresh)
242
+ def parse_tenant_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
243
+ parse_option_source_id_list('allTenants', id_list, api_params, refresh, allow_any_id)
245
244
  end
246
245
 
247
- # def parse_blueprints_id_list(id_list)
248
- # parse_option_source_id_list('blueprints', id_list, api_params, refresh)
246
+ # def parse_blueprints_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
247
+ # parse_option_source_id_list('blueprints', id_list, api_params, refresh, allow_any_id)
249
248
  # end
250
249
 
251
- def parse_project_id_list(id_list, api_params={}, refresh=false)
252
- parse_option_source_id_list('projects', id_list, api_params, refresh)
250
+ def parse_project_id_list(id_list, api_params={}, refresh=false, allow_any_id=false)
251
+ parse_option_source_id_list('projects', id_list, api_params, refresh, allow_any_id)
253
252
  end
254
253
 
255
254
  end
@@ -228,7 +228,8 @@ module Morpheus::Cli::PrintHelper
228
228
  out << cyan
229
229
  if payload
230
230
  out << "\n"
231
- content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : 'application/x-www-form-urlencoded'
231
+ is_multipart = (payload.is_a?(Hash) && payload[:multipart] == true)
232
+ content_type = (headers && headers['Content-Type']) ? headers['Content-Type'] : (is_multipart ? 'multipart/form-data' : 'application/x-www-form-urlencoded')
232
233
  if content_type == 'application/json'
233
234
  if payload.is_a?(String)
234
235
  begin
@@ -257,12 +258,21 @@ module Morpheus::Cli::PrintHelper
257
258
  out << payload
258
259
  end
259
260
  else
260
- if content_type == 'application/x-www-form-urlencoded'
261
+ if content_type == 'application/x-www-form-urlencoded' || content_type.to_s.include?('multipart')
261
262
  body_str = payload.to_s
262
263
  begin
264
+ payload.delete(:multipart) if payload.is_a?(Hash)
265
+ # puts "grailsifying it!"
266
+ payload = Morpheus::RestClient.grails_params(payload)
267
+ payload.each do |k,v|
268
+ if v.is_a?(File)
269
+ payload[k] = "@#{v.path}"
270
+ payload[k] = v.path
271
+ end
272
+ end
263
273
  body_str = URI.encode_www_form(payload)
264
274
  rescue => ex
265
- # raise ex
275
+ raise ex
266
276
  end
267
277
  if options[:scrub]
268
278
  out << Morpheus::Logging.scrub_message(body_str)
@@ -273,7 +283,7 @@ module Morpheus::Cli::PrintHelper
273
283
  if options[:scrub]
274
284
  out << Morpheus::Logging.scrub_message(payload)
275
285
  else
276
- out << payload
286
+ out << payload.to_s
277
287
  end
278
288
  end
279
289
  end
@@ -327,7 +337,9 @@ module Morpheus::Cli::PrintHelper
327
337
  else
328
338
  out << " -d '#{payload}'"
329
339
  end
340
+ out << "\n"
330
341
  else
342
+ is_multipart = (payload.is_a?(Hash) && payload[:multipart] == true)
331
343
  content_type = headers['Content-Type'] || 'application/x-www-form-urlencoded'
332
344
 
333
345
  if payload.is_a?(File)
@@ -337,21 +349,22 @@ module Morpheus::Cli::PrintHelper
337
349
  out << " -d @#{payload.path}"
338
350
  elsif payload.is_a?(String)
339
351
  out << " -d '#{payload}'"
340
- else
341
- if content_type == 'application/x-www-form-urlencoded'
342
- body_str = payload.to_s
343
- begin
344
- body_str = URI.encode_www_form(payload)
345
- rescue => ex
346
- # raise ex
352
+ elsif payload.respond_to?(:map)
353
+ payload.delete(:multipart) if payload.is_a?(Hash)
354
+ # puts "grailsifying it!"
355
+ payload = Morpheus::RestClient.grails_params(payload)
356
+ payload.each do |k,v|
357
+ if v.is_a?(File)
358
+ out << " -F '#{k}=@#{v.path}"
359
+ else
360
+ out << " -d '#{URI.encode_www_form({(k) => v})}'"
347
361
  end
348
- out << " -d '#{body_str}'"
349
- else
350
- out << " -d '#{payload}'"
362
+ out << "\n"
351
363
  end
364
+ #body_str = URI.encode_www_form(payload)
365
+ # out << " -d '#{body_str}'"
352
366
  end
353
367
  end
354
- out << "\n"
355
368
  else
356
369
  out << "\n"
357
370
  end
@@ -431,12 +444,13 @@ module Morpheus::Cli::PrintHelper
431
444
  out = ""
432
445
  bars = []
433
446
  percent = 0
447
+ percent_sigdig = opts[:percent_sigdig] || 2
434
448
  if max_value.to_i == 0
435
449
  percent = 0
436
450
  else
437
451
  percent = ((used_value.to_f / max_value.to_f) * 100)
438
452
  end
439
- percent_label = ((used_value.nil? || max_value.to_f == 0.0) ? "n/a" : "#{percent.round(2)}%").rjust(6, ' ')
453
+ percent_label = ((used_value.nil? || max_value.to_f == 0.0) ? "n/a" : "#{percent.round(percent_sigdig)}%").rjust(6, ' ')
440
454
  bar_display = ""
441
455
  if percent > 100
442
456
  max_bars.times { bars << "|" }
@@ -674,7 +688,7 @@ module Morpheus::Cli::PrintHelper
674
688
  else
675
689
  # so let's use the passed in column definitions instead of the raw data properties
676
690
  # columns = options[:include_fields]
677
- new_columns = []
691
+ new_columns = {}
678
692
  options[:include_fields].each do |f|
679
693
  matching_column = nil
680
694
  # column definitions vary right now, array of symbols/strings/hashes or perhaps a single hash
@@ -692,7 +706,7 @@ module Morpheus::Cli::PrintHelper
692
706
  matching_column = columns[matching_key]
693
707
  end
694
708
  end
695
- new_columns << (matching_column ? matching_column : f)
709
+ new_columns[f] = matching_column ? matching_column : f
696
710
  end
697
711
  columns = new_columns
698
712
  end
@@ -720,6 +734,7 @@ module Morpheus::Cli::PrintHelper
720
734
  columns.each do |column_def|
721
735
  # r << column_def.display_method.respond_to?(:call) ? column_def.display_method.call(row_data) : get_object_value(row_data, column_def.display_method)
722
736
  value = column_def.display_method.call(row_data)
737
+ value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
723
738
  row << value
724
739
  end
725
740
  rows << row
@@ -802,6 +817,7 @@ module Morpheus::Cli::PrintHelper
802
817
  columns.each do |column_def|
803
818
  # r << column_def.display_method.respond_to?(:call) ? column_def.display_method.call(row_data) : get_object_value(row_data, column_def.display_method)
804
819
  value = column_def.display_method.call(row_data)
820
+ value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
805
821
  row << value
806
822
  end
807
823
  rows << row
@@ -879,6 +895,7 @@ module Morpheus::Cli::PrintHelper
879
895
  label = label.upcase if ALL_LABELS_UPCASE
880
896
  # value = get_object_value(obj, column_def.display_method)
881
897
  value = column_def.display_method.call(obj)
898
+ value = JSON.fast_generate(value) if value.is_a?(Hash) || value.is_a?(Array)
882
899
  if label.size > max_label_width
883
900
  max_label_width = label.size
884
901
  end
@@ -1069,6 +1086,7 @@ module Morpheus::Cli::PrintHelper
1069
1086
  column_defs.each do |column_def|
1070
1087
  label = column_def.label
1071
1088
  value = column_def.display_method.call(obj)
1089
+ value = value.is_a?(String) ? value : JSON.fast_generate(value)
1072
1090
  # value = get_object_value(obj, column_def)
1073
1091
  if do_quotes
1074
1092
  cells << quote_csv_value(value)
@@ -696,7 +696,7 @@ module Morpheus::Cli::ProvisioningHelper
696
696
  # prompt for service plan
697
697
  plan_id = nil
698
698
  service_plan = nil
699
- service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
699
+ service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
700
700
  service_plans = service_plans_json["plans"]
701
701
  if locked_fields.include?('plan.id')
702
702
  plan_id = options[:options]['plan']['id'] rescue nil
@@ -764,7 +764,7 @@ module Morpheus::Cli::ProvisioningHelper
764
764
  # pluck out the resourcePoolId option type to prompt for
765
765
  resource_pool_option_type = option_type_list.find {|opt| ['resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
766
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']
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
768
  resource_pool = resource_pool_options.find {|opt| opt['id'] == options[:resource_pool].to_i} if options[:resource_pool]
769
769
 
770
770
  if resource_pool
@@ -1409,7 +1409,7 @@ module Morpheus::Cli::ProvisioningHelper
1409
1409
  if plan_info['addVolumes']
1410
1410
  volume_index = current_volumes.size
1411
1411
  has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
1412
- add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?"))
1412
+ add_another_volume = has_another_volume || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add data volume?", {:default => false}))
1413
1413
  while add_another_volume do
1414
1414
  #puts "Configure Data #{volume_index} Volume"
1415
1415
 
@@ -0,0 +1,246 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ # Provides common finder methods for VDI Pool management commands
3
+ module Morpheus::Cli::VdiHelper
4
+
5
+ def self.included(klass)
6
+ klass.send :include, Morpheus::Cli::PrintHelper
7
+ end
8
+
9
+ ## VDI Pools
10
+
11
+ def vdi_pools_interface
12
+ raise "#{self.class} has not defined @vdi_pools_interface" if @vdi_pools_interface.nil?
13
+ @vdi_pools_interface
14
+ end
15
+
16
+ def vdi_pool_object_key
17
+ 'vdiPool'
18
+ end
19
+
20
+ def vdi_pool_list_key
21
+ 'vdiPools'
22
+ end
23
+
24
+ def find_vdi_pool_by_name_or_id(val)
25
+ if val.to_s =~ /\A\d{1,}\Z/
26
+ return find_vdi_pool_by_id(val)
27
+ else
28
+ return find_vdi_pool_by_name(val)
29
+ end
30
+ end
31
+
32
+ def find_vdi_pool_by_id(id)
33
+ begin
34
+ json_response = vdi_pools_interface.get(id.to_i)
35
+ return json_response[vdi_pool_object_key]
36
+ rescue RestClient::Exception => e
37
+ if e.response && e.response.code == 404
38
+ print_red_alert "VDI Pool not found by id '#{id}'"
39
+ else
40
+ raise e
41
+ end
42
+ end
43
+ end
44
+
45
+ def find_vdi_pool_by_name(name)
46
+ json_response = vdi_pools_interface.list({name: name.to_s})
47
+ vdi_pools = json_response[vdi_pool_list_key]
48
+ if vdi_pools.empty?
49
+ print_red_alert "VDI Pool not found by name '#{name}'"
50
+ return nil
51
+ elsif vdi_pools.size > 1
52
+ print_red_alert "#{vdi_pools.size} VDI Pools found by name '#{name}'"
53
+ print_error "\n"
54
+ puts_error as_pretty_table(vdi_pools, [:id, :name], {color:red})
55
+ print_red_alert "Try using ID instead"
56
+ print_error reset,"\n"
57
+ return nil
58
+ else
59
+ return vdi_pools[0]
60
+ end
61
+ end
62
+
63
+ def format_vdi_pool_status(vdi_pool, return_color=cyan)
64
+ out = ""
65
+ status_string = vdi_pool['status'].to_s.downcase
66
+ if status_string
67
+ if ['available'].include?(status_string)
68
+ out << "#{green}#{status_string.upcase}"
69
+ elsif ['unavailable'].include?(status_string)
70
+ out << "#{red}#{status_string.upcase}"
71
+ else
72
+ out << "#{return_color}#{status_string.upcase}"
73
+ end
74
+ end
75
+ out + return_color
76
+ end
77
+
78
+ ## VDI Allocations
79
+
80
+ def vdi_allocations_interface
81
+ raise "#{self.class} has not defined @vdi_allocations_interface" if @vdi_allocations_interface.nil?
82
+ @vdi_allocations_interface
83
+ end
84
+
85
+ def vdi_allocation_object_key
86
+ 'vdiAllocation'
87
+ end
88
+
89
+ def vdi_allocation_list_key
90
+ 'vdiAllocations'
91
+ end
92
+
93
+ def find_vdi_allocation_by_id(id)
94
+ begin
95
+ json_response = vdi_allocations_interface.get(id.to_i)
96
+ return json_response[vdi_allocation_object_key]
97
+ rescue RestClient::Exception => e
98
+ if e.response && e.response.code == 404
99
+ print_red_alert "VDI Allocation not found by id '#{id}'"
100
+ else
101
+ raise e
102
+ end
103
+ end
104
+ end
105
+
106
+ def format_vdi_allocation_status(vdi_allocation, return_color=cyan)
107
+ out = ""
108
+ status_string = vdi_allocation['status'].to_s.downcase
109
+ if status_string
110
+ if ['available'].include?(status_string)
111
+ out << "#{green}#{status_string.upcase}"
112
+ # elsif ['preparing'].include?(status_string)
113
+ # out << "#{yellow}#{status_string.upcase}"
114
+ # elsif ['reserved', 'shutdown'].include?(status_string)
115
+ # out << "#{yellow}#{status_string.upcase}"
116
+ elsif ['failed'].include?(status_string)
117
+ out << "#{red}#{status_string.upcase}"
118
+ else
119
+ out << "#{return_color}#{status_string.upcase}"
120
+ end
121
+ end
122
+ out + return_color
123
+ end
124
+
125
+ def get_available_vdi_apps(refresh=false)
126
+ if !@available_vdi_apps || refresh
127
+ @available_vdi_apps = @vdi_apps_interface.list({max:-1})['vdiApps'] # || []
128
+ end
129
+ return @available_vdi_apps
130
+ end
131
+
132
+ def get_vdi_app_by_name_or_code(name)
133
+ return get_available_vdi_apps().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
134
+ end
135
+
136
+ ## VDI Apps
137
+
138
+ def vdi_apps_interface
139
+ raise "#{self.class} has not defined @vdi_apps_interface" if @vdi_apps_interface.nil?
140
+ @vdi_apps_interface
141
+ end
142
+
143
+ def vdi_app_object_key
144
+ 'vdiApp'
145
+ end
146
+
147
+ def vdi_app_list_key
148
+ 'vdiApps'
149
+ end
150
+
151
+ def find_vdi_app_by_name_or_id(val)
152
+ if val.to_s =~ /\A\d{1,}\Z/
153
+ return find_vdi_app_by_id(val)
154
+ else
155
+ return find_vdi_app_by_name(val)
156
+ end
157
+ end
158
+
159
+ def find_vdi_app_by_id(id)
160
+ begin
161
+ json_response = vdi_apps_interface.get(id.to_i)
162
+ return json_response[vdi_app_object_key]
163
+ rescue RestClient::Exception => e
164
+ if e.response && e.response.code == 404
165
+ print_red_alert "VDI App not found by id '#{id}'"
166
+ else
167
+ raise e
168
+ end
169
+ end
170
+ end
171
+
172
+ def find_vdi_app_by_name(name)
173
+ json_response = vdi_apps_interface.list({name: name.to_s})
174
+ vdi_apps = json_response[vdi_app_list_key]
175
+ if vdi_apps.empty?
176
+ print_red_alert "VDI App not found by name '#{name}'"
177
+ return nil
178
+ elsif vdi_apps.size > 1
179
+ print_red_alert "#{vdi_apps.size} VDI App found by name '#{name}'"
180
+ print_error "\n"
181
+ puts_error as_pretty_table(vdi_apps, {"ID" => 'id', "NAME" => 'name'}, {color:red})
182
+ print_red_alert "Try using ID instead"
183
+ print_error reset,"\n"
184
+ return nil
185
+ else
186
+ return vdi_apps[0]
187
+ end
188
+ end
189
+
190
+
191
+ ## VDI Gateways
192
+
193
+ def vdi_gateways_interface
194
+ raise "#{self.class} has not defined @vdi_gateways_interface" if @vdi_gateways_interface.nil?
195
+ @vdi_gateways_interface
196
+ end
197
+
198
+ def vdi_gateway_object_key
199
+ 'vdiGateway'
200
+ end
201
+
202
+ def vdi_gateway_list_key
203
+ 'vdiGateways'
204
+ end
205
+
206
+ def find_vdi_gateway_by_name_or_id(val)
207
+ if val.to_s =~ /\A\d{1,}\Z/
208
+ return find_vdi_gateway_by_id(val)
209
+ else
210
+ return find_vdi_gateway_by_name(val)
211
+ end
212
+ end
213
+
214
+ def find_vdi_gateway_by_id(id)
215
+ begin
216
+ json_response = vdi_gateways_interface.get(id.to_i)
217
+ return json_response[vdi_gateway_object_key]
218
+ rescue RestClient::Exception => e
219
+ if e.response && e.response.code == 404
220
+ print_red_alert "VDI Gateway not found by id '#{id}'"
221
+ else
222
+ raise e
223
+ end
224
+ end
225
+ end
226
+
227
+ def find_vdi_gateway_by_name(name)
228
+ json_response = vdi_gateways_interface.list({name: name.to_s})
229
+ vdi_gateways = json_response[vdi_gateway_list_key]
230
+ if vdi_gateways.empty?
231
+ print_red_alert "VDI Gateway not found by name '#{name}'"
232
+ return nil
233
+ elsif vdi_gateways.size > 1
234
+ print_red_alert "#{vdi_gateways.size} VDI Gateway found by name '#{name}'"
235
+ print_error "\n"
236
+ puts_error as_pretty_table(vdi_gateways, {"ID" => 'id', "NAME" => 'name'}, {color:red})
237
+ print_red_alert "Try using ID instead"
238
+ print_error reset,"\n"
239
+ return nil
240
+ else
241
+ return vdi_gateways[0]
242
+ end
243
+ end
244
+
245
+
246
+ end