morpheus-cli 3.3.2.7 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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