morpheus-cli 3.3.2.7 → 3.4.0

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.
@@ -14,6 +14,9 @@ class Morpheus::Cli::Accounts
14
14
  alias_subcommand :details, :get
15
15
  set_default_subcommand :list
16
16
 
17
+ # account-groups is under this namespace for now
18
+ register_subcommands :'groups' => :account_groups
19
+
17
20
  def initialize()
18
21
  @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
19
22
  end
@@ -29,6 +32,10 @@ class Morpheus::Cli::Accounts
29
32
  handle_subcommand(args)
30
33
  end
31
34
 
35
+ def account_groups(args)
36
+ Morpheus::Cli::AccountGroupsCommand.new.handle(args)
37
+ end
38
+
32
39
  def list(args)
33
40
  options = {}
34
41
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -131,6 +138,7 @@ class Morpheus::Cli::Accounts
131
138
  puts "ID: #{account['id']}"
132
139
  puts "Name: #{account['name']}"
133
140
  puts "Description: #{account['description']}"
141
+ puts "Subdomain: #{account['subdomain']}" if !account['subdomain'].to_s.empty?
134
142
  puts "Currency: #{account['currency']}"
135
143
  # puts "# Users: #{account['usersCount']}"
136
144
  # puts "# Instances: #{account['instancesCount']}"
@@ -54,7 +54,7 @@ class Morpheus::Cli::Groups
54
54
  groups = json_response['groups']
55
55
  print_h1 "Morpheus Groups"
56
56
  if groups.empty?
57
- puts yellow,"No groups currently configured.",reset
57
+ print yellow,"No groups currently configured.",reset,"\n"
58
58
  else
59
59
  print_groups_table(groups)
60
60
  print_results_pagination(json_response)
@@ -826,8 +826,9 @@ class Morpheus::Cli::PoliciesCommand
826
826
 
827
827
  def format_tenants(accounts)
828
828
  if accounts && accounts.size > 0
829
- account_ids = accounts.collect {|it| it['id'] }.uniq
830
- account_names = accounts.collect {|it| it['name'] }.uniq
829
+ accounts = accounts.sort {|it| it['name'] }.uniq {|it| it['id'] }
830
+ account_ids = accounts.collect {|it| it['id'] }
831
+ account_names = accounts.collect {|it| it['name'] }
831
832
  "(#{account_ids.join(',')}) #{account_names.join(',')}"
832
833
  else
833
834
  ""
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "3.3.2.7"
4
+ VERSION = "3.4.0"
5
5
  end
6
6
  end
@@ -29,7 +29,7 @@ class Morpheus::Cli::VirtualImages
29
29
 
30
30
  def list(args)
31
31
  options = {}
32
- optparse = OptionParser.new do|opts|
32
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
33
33
  opts.banner = subcommand_usage()
34
34
  opts.on( '-t', '--type IMAGE_TYPE', "Image Type" ) do |val|
35
35
  options[:imageType] = val.downcase
@@ -43,15 +43,14 @@ class Morpheus::Cli::VirtualImages
43
43
  opts.on('--system', "System Images" ) do
44
44
  options[:filterType] = 'System'
45
45
  end
46
- build_common_options(opts, options, [:list, :json, :dry_run, :remote])
46
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
47
+ opts.footer = "List virtual images."
47
48
  end
48
49
  optparse.parse!(args)
49
50
  connect(options)
50
51
  begin
51
52
  params = {}
52
- [:phrase, :offset, :max, :sort, :direction].each do |k|
53
- params[k] = options[k] unless options[k].nil?
54
- end
53
+ params.merge!(parse_list_options(options))
55
54
  if options[:imageType]
56
55
  params[:imageType] = options[:imageType]
57
56
  end
@@ -63,38 +62,50 @@ class Morpheus::Cli::VirtualImages
63
62
  return
64
63
  end
65
64
  json_response = @virtual_images_interface.get(params)
65
+
66
66
  if options[:json]
67
- print JSON.pretty_generate(json_response)
67
+ puts as_json(json_response, options, "virtualImages")
68
+ return 0
69
+ elsif options[:yaml]
70
+ puts as_yaml(json_response, options, "virtualImages")
71
+ return 0
72
+ elsif options[:csv]
73
+ puts records_as_csv(json_response["virtualImages"], options)
74
+ return 0
75
+ end
76
+
77
+
78
+ images = json_response['virtualImages']
79
+ title = "Morpheus Virtual Images"
80
+ subtitles = []
81
+ if options[:imageType]
82
+ subtitles << "Image Type: #{options[:imageType]}".strip
83
+ end
84
+ if options[:filterType]
85
+ subtitles << "Image Type: #{options[:filterType]}".strip
86
+ end
87
+ if params[:phrase]
88
+ subtitles << "Search: #{params[:phrase]}".strip
89
+ end
90
+ print_h1 title, subtitles
91
+ if images.empty?
92
+ print yellow,"No virtual images found.",reset,"\n"
68
93
  else
69
- images = json_response['virtualImages']
70
- title = "Morpheus Virtual Images"
71
- subtitles = []
72
- if options[:imageType]
73
- subtitles << "Image Type: #{options[:imageType]}".strip
94
+ rows = images.collect do |image|
95
+ image_type = virtual_image_type_for_name_or_code(image['imageType'])
96
+ image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
97
+ {name: image['name'], id: image['id'], type: image_type_display, source: image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}"), storage: !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default', size: image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}"}
74
98
  end
75
- if options[:filterType]
76
- subtitles << "Image Type: #{options[:filterType]}".strip
77
- end
78
- if params[:phrase]
79
- subtitles << "Search: #{params[:phrase]}".strip
80
- end
81
- print_h1 title, subtitles
82
- if images.empty?
83
- print yellow,"No virtual images found.",reset,"\n"
84
- else
85
- rows = images.collect do |image|
86
- image_type = virtual_image_type_for_name_or_code(image['imageType'])
87
- image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
88
- {name: image['name'], id: image['id'], type: image_type_display, source: image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}"), storage: !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default', size: image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}"}
89
- end
90
- columns = [:id, :name, :type, :storage, :size, :source]
91
- print cyan
92
- print as_pretty_table(rows, columns, options)
93
- print_results_pagination(json_response)
94
- end
95
- print reset,"\n"
99
+ columns = [:id, :name, :type, :storage, :size, :source]
100
+ columns = options[:include_fields] if options[:include_fields]
101
+ print cyan
102
+ print as_pretty_table(rows, columns, options)
103
+ print_results_pagination(json_response)
96
104
  end
97
- rescue RestClient::Exception => e
105
+ print reset,"\n"
106
+
107
+ return 0
108
+ rescue RestClient::Exception => e
98
109
  print_rest_exception(e, options)
99
110
  exit 1
100
111
  end
@@ -102,9 +113,15 @@ class Morpheus::Cli::VirtualImages
102
113
 
103
114
  def get(args)
104
115
  options = {}
105
- optparse = OptionParser.new do|opts|
116
+ show_details = false
117
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
106
118
  opts.banner = subcommand_usage("[name]")
107
- build_common_options(opts, options, [:json, :dry_run, :remote])
119
+ opts.on('--details', "Show more details." ) do
120
+ show_details = true
121
+ end
122
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
123
+ opts.footer = "Get details about a virtual image." + "\n" +
124
+ "[name] is required. This is the name or id of a virtual image."
108
125
  end
109
126
  optparse.parse!(args)
110
127
  if args.count < 1
@@ -126,48 +143,94 @@ class Morpheus::Cli::VirtualImages
126
143
  return 1 if image.nil?
127
144
  # refetch
128
145
  json_response = @virtual_images_interface.get(image['id'])
146
+ if options[:json]
147
+ puts as_json(json_response, options, "virtualImage")
148
+ return 0
149
+ elsif options[:yaml]
150
+ puts as_yaml(json_response, options, "virtualImage")
151
+ return 0
152
+ elsif options[:csv]
153
+ puts records_as_csv([json_response["virtualImage"]], options)
154
+ return 0
155
+ end
156
+
129
157
  image = json_response['virtualImage']
130
158
  image_files = json_response['cloudFiles'] || json_response['files']
131
159
 
132
- if options[:json]
133
- puts JSON.pretty_generate(json_response)
134
- else
135
- image_type = virtual_image_type_for_name_or_code(image['imageType'])
136
- image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
137
- print_h1 "Virtual Image Details"
138
- print cyan
139
- description_cols = {
140
- "ID" => 'id',
141
- "Name" => 'name',
142
- "Type" => lambda {|it| image_type_display },
143
- # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
144
- # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
145
- }
146
- print_description_list(description_cols, image)
147
-
148
- if image_files
149
- print_h2 "Files"
150
- image_files.each {|image_file|
151
- pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
152
- print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
153
- }
160
+
161
+ image_type = virtual_image_type_for_name_or_code(image['imageType'])
162
+ image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
163
+ print_h1 "Virtual Image Details"
164
+ print cyan
165
+ description_cols = {
166
+ "ID" => 'id',
167
+ "Name" => 'name',
168
+ "Type" => lambda {|it| image_type_display },
169
+ "Storage" => lambda {|it| !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default' },
170
+ "Size" => lambda {|it| image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}" },
171
+ "Source" => lambda {|it| image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}") },
172
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
173
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
174
+ }
175
+ advanced_description_cols = {
176
+ "OS Type" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
177
+ "Min Memory" => lambda {|it| it['minRam'].to_i != 0 ? Filesize.from("#{it['minRam']} B").pretty : "" },
178
+ "Cloud Init?" => lambda {|it| format_boolean it['osType'] },
179
+ "Install Agent?" => lambda {|it| format_boolean it['osType'] },
180
+ "SSH Username" => lambda {|it| it['sshUsername'] },
181
+ "SSH Password" => lambda {|it| it['sshPassword'] },
182
+ "User Data" => lambda {|it| it['userData'] },
183
+ "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
184
+ "Tenants" => lambda {|it| format_tenants(it['accounts']) },
185
+ "Auto Join Domain?" => lambda {|it| format_boolean it['isAutoJoinDomain'] },
186
+ "VirtIO Drivers Loaded?" => lambda {|it| format_boolean it['virtioSupported'] },
187
+ "VM Tools Installed?" => lambda {|it| format_boolean it['vmToolsInstalled'] },
188
+ "Force Guest Customization?" => lambda {|it| format_boolean it['isForceCustomization'] },
189
+ "Trial Version" => lambda {|it| format_boolean it['trialVersion'] },
190
+ "Sysprep Enabled?" => lambda {|it| format_boolean it['isSysprep'] },
191
+ }
192
+ if show_details
193
+ description_cols.merge!(advanced_description_cols)
194
+ end
195
+ print_description_list(description_cols, image)
196
+
197
+ if image_files
198
+ print_h2 "Files (#{image_files.size})"
199
+ # image_files.each {|image_file|
200
+ # pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
201
+ # print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
202
+ # }
203
+ image_file_rows = image_files.collect do |image_file|
204
+
205
+ {filename: image_file['name'], size: Filesize.from("#{image_file['size']} B").pretty}
154
206
  end
155
- print reset,"\n"
207
+ print cyan
208
+ print as_pretty_table(image_file_rows, [:filename, :size])
209
+ # print reset,"\n"
156
210
  end
211
+ print reset,"\n"
157
212
  rescue RestClient::Exception => e
158
213
  print_rest_exception(e, options)
159
214
  exit 1
160
215
  end
161
216
  end
162
217
 
163
- # JD: I don't think this has ever worked
164
218
  def update(args)
165
219
  image_name = args[0]
166
220
  options = {}
167
- account_name = nil
168
- optparse = OptionParser.new do|opts|
221
+ tenants_list = nil
222
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
169
223
  opts.banner = subcommand_usage("[name] [options]")
170
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
224
+ opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
225
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
226
+ tenants_list = []
227
+ else
228
+ tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
229
+ end
230
+ end
231
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
232
+ opts.footer = "Update a virtual image." + "\n" +
233
+ "[name] is required. This is the name or id of a virtual image."
171
234
  end
172
235
  optparse.parse!(args)
173
236
  if args.count < 1
@@ -176,24 +239,31 @@ class Morpheus::Cli::VirtualImages
176
239
  end
177
240
 
178
241
  connect(options)
179
- begin
180
-
242
+ begin
181
243
  image = find_virtual_image_by_name_or_id(image_name)
182
244
  return 1 if image.nil?
183
245
 
184
- params = options[:options] || {}
185
-
186
- if params.empty?
187
- puts optparse
188
- option_lines = update_virtual_image_option_types().collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
189
- puts "\nAvailable Options:\n#{option_lines}\n\n"
190
- exit 1
246
+ payload = nil
247
+ if options[:payload]
248
+ payload = options[:payload]
249
+ # support -O OPTION switch on top of --payload
250
+ if options[:options]
251
+ payload['virtualImage'] ||= {}
252
+ payload['virtualImage'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
253
+ end
254
+ else
255
+ params = options[:options] || {}
256
+ if params.empty? && tenants_list.nil?
257
+ puts optparse
258
+ option_lines = update_virtual_image_option_types().collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
259
+ puts "\nAvailable Options:\n#{option_lines}\n\n"
260
+ exit 1
261
+ end
262
+ if tenants_list
263
+ params['accounts'] = tenants_list
264
+ end
265
+ payload = {'virtualImage' => params}
191
266
  end
192
-
193
- image_payload = {id: image['id']}
194
- image_payload.merge(params)
195
- # JD: what can be updated?
196
- payload = {virtualImage: image_payload}
197
267
  if options[:dry_run]
198
268
  print_dry_run @virtual_images_interface.dry.update(image['id'], payload)
199
269
  return
@@ -205,7 +275,7 @@ class Morpheus::Cli::VirtualImages
205
275
  exit 1
206
276
  end
207
277
  else
208
- print "\n", cyan, "Task #{response['task']['name']} updated", reset, "\n\n"
278
+ print "\n", cyan, "Virtual Image #{image['name']} updated", reset, "\n\n"
209
279
  end
210
280
  rescue RestClient::Exception => e
211
281
  print_rest_exception(e, options)
@@ -215,7 +285,7 @@ class Morpheus::Cli::VirtualImages
215
285
 
216
286
  def virtual_image_types(args)
217
287
  options = {}
218
- optparse = OptionParser.new do|opts|
288
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
219
289
  opts.banner = subcommand_usage()
220
290
  build_common_options(opts, options, [:json, :dry_run, :remote])
221
291
  end
@@ -254,16 +324,29 @@ class Morpheus::Cli::VirtualImages
254
324
  def add(args)
255
325
  image_type_name = nil
256
326
  file_url = nil
327
+ file_name = nil
328
+ tenants_list = nil
257
329
  options = {}
258
- optparse = OptionParser.new do|opts|
330
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
259
331
  opts.banner = subcommand_usage("[name] -t TYPE")
260
332
  opts.on( '-t', '--type TYPE', "Virtual Image Type" ) do |val|
261
333
  image_type_name = val
262
334
  end
335
+ opts.on( '--filename NAME', "Image File Name. Specify a name for the uploaded file." ) do |val|
336
+ file_name = val
337
+ end
263
338
  opts.on( '-U', '--url URL', "Image File URL. This can be used instead of uploading local files." ) do |val|
264
339
  file_url = val
265
340
  end
341
+ opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
342
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
343
+ tenants_list = []
344
+ else
345
+ tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
346
+ end
347
+ end
266
348
  build_common_options(opts, options, [:options, :json, :dry_run, :remote])
349
+ opts.footer = "Create a virtual image."
267
350
  end
268
351
  optparse.parse!(args)
269
352
  # if args.count < 1
@@ -304,6 +387,7 @@ class Morpheus::Cli::VirtualImages
304
387
  # end
305
388
  # end
306
389
  params = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
390
+ params.deep_compact!
307
391
  virtual_image_payload = {}.merge(params)
308
392
  virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
309
393
  virtual_image_payload['imageType'] = image_type['code']
@@ -311,15 +395,18 @@ class Morpheus::Cli::VirtualImages
311
395
  if !storage_provider_id.to_s.empty?
312
396
  virtual_image_payload['storageProvider'] = {id: storage_provider_id}
313
397
  end
398
+ if tenants_list
399
+ virtual_image_payload['accounts'] = tenants_list
400
+ end
314
401
  payload = {virtualImage: virtual_image_payload}
315
402
 
316
403
  if options[:dry_run]
317
404
  print_dry_run @virtual_images_interface.dry.create(payload)
318
405
  if file_url
319
- print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url)
406
+ print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url, file_name)
320
407
  elsif virtual_image_files && !virtual_image_files.empty?
321
- virtual_image_files.each do |key, filename|
322
- print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filename})")
408
+ virtual_image_files.each do |key, filepath|
409
+ print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filepath})")
323
410
  end
324
411
  end
325
412
  return
@@ -339,17 +426,17 @@ class Morpheus::Cli::VirtualImages
339
426
  unless options[:quiet]
340
427
  print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
341
428
  end
342
- upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url)
429
+ upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url, file_name)
343
430
  if options[:json]
344
431
  print JSON.pretty_generate(upload_json_response)
345
432
  end
346
433
  elsif virtual_image_files && !virtual_image_files.empty?
347
- virtual_image_files.each do |key, filename|
434
+ virtual_image_files.each do |key, filepath|
348
435
  unless options[:quiet]
349
- print cyan, "Uploading file (#{key}) #{filename} ...", reset, "\n"
436
+ print cyan, "Uploading file (#{key}) #{filepath} ...", reset, "\n"
350
437
  end
351
- image_file = File.new(filename, 'rb')
352
- upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file)
438
+ image_file = File.new(filepath, 'rb')
439
+ upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file, file_name)
353
440
  if options[:json]
354
441
  print JSON.pretty_generate(upload_json_response)
355
442
  end
@@ -369,19 +456,25 @@ class Morpheus::Cli::VirtualImages
369
456
  end
370
457
 
371
458
  def add_file(args)
372
- image_type_name = nil
373
459
  file_url = nil
460
+ file_name = nil
374
461
  options = {}
375
- optparse = OptionParser.new do|opts|
462
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
376
463
  opts.banner = subcommand_usage("[name] [filepath]")
464
+ opts.on('--filename FILENAME', String, "Filename for uploaded file. Derived from [filepath] by default." ) do |val|
465
+ file_name = val
466
+ end
377
467
  opts.on( '-U', '--url URL', "Image File URL. This can be used instead of [filepath]" ) do |val|
378
468
  file_url = val
379
469
  end
380
470
  build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
471
+ opts.footer = "Upload a virtual image file." + "\n" +
472
+ "[name] is required. This is the name or id of a virtual image." + "\n" +
473
+ "[filepath] or --url is required. This is location of the virtual image file."
381
474
  end
382
475
  optparse.parse!(args)
383
476
  image_name = args[0]
384
- filename = nil
477
+ filepath = nil
385
478
  if file_url
386
479
  if args.count < 1
387
480
  puts optparse
@@ -392,7 +485,7 @@ class Morpheus::Cli::VirtualImages
392
485
  puts optparse
393
486
  exit 1
394
487
  end
395
- filename = args[1]
488
+ filepath = args[1]
396
489
  end
397
490
 
398
491
  connect(options)
@@ -402,13 +495,13 @@ class Morpheus::Cli::VirtualImages
402
495
  return 1 if image.nil?
403
496
  if file_url
404
497
  if options[:dry_run]
405
- print_dry_run @virtual_images_interface.dry.upload_by_url(image['id'], file_url)
498
+ print_dry_run @virtual_images_interface.dry.upload_by_url(image['id'], file_url, file_name)
406
499
  return
407
500
  end
408
501
  unless options[:quiet]
409
502
  print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
410
503
  end
411
- json_response = @virtual_images_interface.upload_by_url(image['id'], file_url)
504
+ json_response = @virtual_images_interface.upload_by_url(image['id'], file_url, file_name)
412
505
  if options[:json]
413
506
  print JSON.pretty_generate(json_response)
414
507
  elsif !options[:quiet]
@@ -416,15 +509,15 @@ class Morpheus::Cli::VirtualImages
416
509
  get([image['id']])
417
510
  end
418
511
  else
419
- image_file = File.new(filename, 'rb')
512
+ image_file = File.new(filepath, 'rb')
420
513
  if options[:dry_run]
421
- print_dry_run @virtual_images_interface.dry.upload(image['id'], image_file)
514
+ print_dry_run @virtual_images_interface.dry.upload(image['id'], image_file, file_name)
422
515
  return
423
516
  end
424
517
  unless options[:quiet]
425
- print cyan, "Uploading file #{filename} ...", reset, "\n"
518
+ print cyan, "Uploading file #{filepath} ...", reset, "\n"
426
519
  end
427
- json_response = @virtual_images_interface.upload(image['id'], image_file)
520
+ json_response = @virtual_images_interface.upload(image['id'], image_file, file_name)
428
521
  if options[:json]
429
522
  print JSON.pretty_generate(json_response)
430
523
  elsif !options[:quiet]
@@ -441,7 +534,7 @@ class Morpheus::Cli::VirtualImages
441
534
 
442
535
  def remove_file(args)
443
536
  options = {}
444
- optparse = OptionParser.new do|opts|
537
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
445
538
  opts.banner = subcommand_usage("[name] [filename]")
446
539
  build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
447
540
  end
@@ -477,7 +570,7 @@ class Morpheus::Cli::VirtualImages
477
570
 
478
571
  def remove(args)
479
572
  options = {}
480
- optparse = OptionParser.new do|opts|
573
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
481
574
  opts.banner = subcommand_usage("[name]")
482
575
  build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
483
576
  end
@@ -555,13 +648,14 @@ class Morpheus::Cli::VirtualImages
555
648
  return get_available_virtual_image_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
556
649
  end
557
650
 
558
- def add_virtual_image_option_types(image_type, include_file_selection=true)
559
- image_type_code = image_type['code']
651
+ def add_virtual_image_option_types(image_type = nil, include_file_selection=true)
652
+
560
653
  # todo: make api provide virtualImageType and its optionTypes.
561
654
  tmp_option_types = [
562
655
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
563
656
  #{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2},
564
657
  {'fieldName' => 'osType', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false, 'description' => 'Select OS Type.', 'displayOrder' => 3},
658
+ {'fieldName' => 'minRam', 'fieldLabel' => 'Minimum Memory (MB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (MB)', 'displayOrder' => 4},
565
659
  {'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 4},
566
660
  {'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 4},
567
661
  {'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 5},
@@ -569,36 +663,55 @@ class Morpheus::Cli::VirtualImages
569
663
  {'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 7},
570
664
  {'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
571
665
  {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 40},
572
- {'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'category' => 'advanced', 'displayOrder' => 40},
573
- {'fieldName' => 'virtioSupported', 'fieldLabel' => 'VirtIO Drivers Loaded?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VirtIO Drivers Loaded?', 'category' => 'advanced', 'displayOrder' => 40}
666
+ {'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
667
+ {'fieldName' => 'virtioSupported', 'fieldLabel' => 'VirtIO Drivers Loaded?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VirtIO Drivers Loaded?', 'category' => 'advanced', 'displayOrder' => 40},
668
+ {'fieldName' => 'vmToolsInstalled', 'fieldLabel' => 'VM Tools Installed?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VM Tools Installed?', 'category' => 'advanced', 'displayOrder' => 40},
669
+ {'fieldName' => 'isForceCustomization', 'fieldLabel' => 'Force Guest Customization?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Force Guest Customization?', 'category' => 'advanced', 'displayOrder' => 40},
670
+ {'fieldName' => 'trialVersion', 'fieldLabel' => 'Trial Version', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Trial Version', 'category' => 'advanced', 'displayOrder' => 40},
671
+ {'fieldName' => 'isSysprep', 'fieldLabel' => 'Sysprep Enabled?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Sysprep Enabled?', 'category' => 'advanced', 'displayOrder' => 40}
574
672
  ]
575
673
 
576
- if image_type_code == 'ami'
577
- tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
578
- if include_file_selection
579
- tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
580
- end
581
- elsif image_type_code == 'vmware' || image_type_code == 'vmdk'
582
- if include_file_selection
583
- tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
584
- tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
585
- end
586
- elsif image_type_code == 'pxe'
587
- tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
588
- tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 10}
589
- tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
590
- else
591
- if include_file_selection
592
- tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 10}
674
+ image_type_code = image_type ? image_type['code'] : nil
675
+ if image_type_code
676
+ if image_type_code == 'ami'
677
+ tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
678
+ if include_file_selection
679
+ tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
680
+ end
681
+ elsif image_type_code == 'vmware' || image_type_code == 'vmdk'
682
+ if include_file_selection
683
+ tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
684
+ tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
685
+ end
686
+ elsif image_type_code == 'pxe'
687
+ tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
688
+ tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 10}
689
+ tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
690
+ else
691
+ if include_file_selection
692
+ tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 10}
693
+ end
593
694
  end
594
695
  end
595
696
 
596
697
  return tmp_option_types
597
698
  end
598
699
 
599
- # JD: what can be updated?
600
- def update_virtual_image_option_types
601
- []
700
+ def update_virtual_image_option_types(image_type = nil)
701
+ list = add_virtual_image_option_types(image_type)
702
+ list.each {|it| it['required'] = false }
703
+ list
704
+ end
705
+
706
+ def format_tenants(accounts)
707
+ if accounts && accounts.size > 0
708
+ accounts = accounts.sort {|a,b| a['name'] <=> b['name'] }.uniq {|it| it['id'] }
709
+ account_ids = accounts.collect {|it| it['id'] }
710
+ account_names = accounts.collect {|it| it['name'] }
711
+ "(#{account_ids.join(',')}) #{account_names.join(',')}"
712
+ else
713
+ ""
714
+ end
602
715
  end
603
716
 
604
717
  end