morpheus-cli 5.0.0 → 5.2.2

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Dockerfile +1 -1
  4. data/lib/morpheus/api/api_client.rb +16 -0
  5. data/lib/morpheus/api/billing_interface.rb +1 -0
  6. data/lib/morpheus/api/deploy_interface.rb +1 -1
  7. data/lib/morpheus/api/deployments_interface.rb +20 -1
  8. data/lib/morpheus/api/forgot_password_interface.rb +17 -0
  9. data/lib/morpheus/api/instances_interface.rb +16 -2
  10. data/lib/morpheus/api/invoices_interface.rb +12 -3
  11. data/lib/morpheus/api/search_interface.rb +13 -0
  12. data/lib/morpheus/api/servers_interface.rb +14 -0
  13. data/lib/morpheus/api/service_catalog_interface.rb +89 -0
  14. data/lib/morpheus/api/usage_interface.rb +18 -0
  15. data/lib/morpheus/cli.rb +6 -2
  16. data/lib/morpheus/cli/apps.rb +3 -23
  17. data/lib/morpheus/cli/budgets_command.rb +389 -319
  18. data/lib/morpheus/cli/{catalog_command.rb → catalog_item_types_command.rb} +182 -67
  19. data/lib/morpheus/cli/cli_command.rb +51 -10
  20. data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -13
  21. data/lib/morpheus/cli/commands/standard/history_command.rb +9 -3
  22. data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
  23. data/lib/morpheus/cli/containers_command.rb +0 -24
  24. data/lib/morpheus/cli/cypher_command.rb +6 -2
  25. data/lib/morpheus/cli/dashboard_command.rb +260 -20
  26. data/lib/morpheus/cli/deploy.rb +199 -90
  27. data/lib/morpheus/cli/deployments.rb +341 -28
  28. data/lib/morpheus/cli/deploys.rb +206 -41
  29. data/lib/morpheus/cli/error_handler.rb +7 -0
  30. data/lib/morpheus/cli/forgot_password.rb +133 -0
  31. data/lib/morpheus/cli/groups.rb +1 -1
  32. data/lib/morpheus/cli/health_command.rb +59 -2
  33. data/lib/morpheus/cli/hosts.rb +271 -39
  34. data/lib/morpheus/cli/instances.rb +228 -129
  35. data/lib/morpheus/cli/invoices_command.rb +100 -20
  36. data/lib/morpheus/cli/jobs_command.rb +94 -92
  37. data/lib/morpheus/cli/library_option_lists_command.rb +1 -1
  38. data/lib/morpheus/cli/library_option_types_command.rb +10 -5
  39. data/lib/morpheus/cli/logs_command.rb +9 -6
  40. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -1
  41. data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
  42. data/lib/morpheus/cli/mixins/print_helper.rb +13 -27
  43. data/lib/morpheus/cli/mixins/provisioning_helper.rb +108 -5
  44. data/lib/morpheus/cli/option_types.rb +271 -22
  45. data/lib/morpheus/cli/remote.rb +35 -10
  46. data/lib/morpheus/cli/reports_command.rb +99 -30
  47. data/lib/morpheus/cli/roles.rb +193 -155
  48. data/lib/morpheus/cli/search_command.rb +182 -0
  49. data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
  50. data/lib/morpheus/cli/setup.rb +1 -1
  51. data/lib/morpheus/cli/shell.rb +33 -11
  52. data/lib/morpheus/cli/tasks.rb +29 -32
  53. data/lib/morpheus/cli/usage_command.rb +64 -11
  54. data/lib/morpheus/cli/version.rb +1 -1
  55. data/lib/morpheus/cli/virtual_images.rb +429 -254
  56. data/lib/morpheus/cli/whoami.rb +6 -6
  57. data/lib/morpheus/cli/workflows.rb +33 -40
  58. data/lib/morpheus/formatters.rb +75 -18
  59. data/lib/morpheus/terminal.rb +6 -2
  60. metadata +10 -4
  61. data/lib/morpheus/cli/mixins/catalog_helper.rb +0 -66
@@ -1,17 +1,16 @@
1
1
  require 'morpheus/cli/cli_command'
2
2
 
3
3
  # CLI command self service
4
- # UI is Tools: Self Service - Catalog Items
4
+ # UI is Tools: Self Service - Catalog
5
5
  # API is /catalog-item-types and returns catalogItemTypes
6
- class Morpheus::Cli::CatalogCommand
6
+ class Morpheus::Cli::CatalogItemTypesCommand
7
7
  include Morpheus::Cli::CliCommand
8
- include Morpheus::Cli::CatalogHelper
9
8
  include Morpheus::Cli::LibraryHelper
10
9
  include Morpheus::Cli::OptionSourceHelper
11
10
 
12
- # hide until 5.1 when update api is fixed and service-catalog endpoints are available
13
- set_command_hidden
14
- set_command_name :'catalog'
11
+ # set_command_name :'catalog-types'
12
+ set_command_name :'self-service'
13
+ set_command_description "Self Service: View and manage catalog item types"
15
14
 
16
15
  register_subcommands :list, :get, :add, :update, :remove
17
16
 
@@ -38,7 +37,7 @@ class Morpheus::Cli::CatalogCommand
38
37
  params['featured'] = (val.to_s != 'false' && val.to_s != 'off')
39
38
  end
40
39
  build_standard_list_options(opts, options)
41
- opts.footer = "List catalog items."
40
+ opts.footer = "List catalog item types."
42
41
  end
43
42
  optparse.parse!(args)
44
43
  connect(options)
@@ -55,11 +54,14 @@ class Morpheus::Cli::CatalogCommand
55
54
  json_response = @catalog_item_types_interface.list(params)
56
55
  catalog_item_types = json_response[catalog_item_type_list_key]
57
56
  render_response(json_response, options, catalog_item_type_list_key) do
58
- print_h1 "Morpheus Catalog Items", parse_list_subtitles(options), options
57
+ print_h1 "Morpheus Catalog Item Types", parse_list_subtitles(options), options
59
58
  if catalog_item_types.empty?
60
- print cyan,"No catalog items found.",reset,"\n"
59
+ print cyan,"No catalog item types found.",reset,"\n"
61
60
  else
62
61
  list_columns = catalog_item_type_column_definitions.upcase_keys!
62
+ list_columns.delete("Blueprint")
63
+ list_columns.delete("Workflow")
64
+ list_columns.delete("Context")
63
65
  #list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
64
66
  print as_pretty_table(catalog_item_types, list_columns.upcase_keys!, options)
65
67
  print_results_pagination(json_response)
@@ -67,7 +69,7 @@ class Morpheus::Cli::CatalogCommand
67
69
  print reset,"\n"
68
70
  end
69
71
  if catalog_item_types.empty?
70
- return 1, "no catalog items found"
72
+ return 1, "no catalog item types found"
71
73
  else
72
74
  return 0, nil
73
75
  end
@@ -77,17 +79,20 @@ class Morpheus::Cli::CatalogCommand
77
79
  params = {}
78
80
  options = {}
79
81
  optparse = Morpheus::Cli::OptionParser.new do |opts|
80
- opts.banner = subcommand_usage("[catalog item type]")
82
+ opts.banner = subcommand_usage("[type]")
81
83
  opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
82
84
  options[:show_config] = true
83
85
  end
84
- # opts.on('--no-config', "Do not display config content." ) do
86
+ # opts.on('--no-config', "Do not display Config YAML." ) do
85
87
  # options[:no_config] = true
86
88
  # end
89
+ opts.on('--no-content', "Do not display Content." ) do
90
+ options[:no_content] = true
91
+ end
87
92
  build_standard_get_options(opts, options)
88
93
  opts.footer = <<-EOT
89
94
  Get details about a specific catalog item type.
90
- [catalog item type] is required. This is the name or id of a catalog item type.
95
+ [type] is required. This is the name or id of a catalog item type.
91
96
  EOT
92
97
  end
93
98
  optparse.parse!(args)
@@ -131,6 +136,8 @@ EOT
131
136
  print cyan
132
137
  show_columns = catalog_item_type_column_definitions
133
138
  show_columns.delete("Blueprint") unless catalog_item_type['blueprint']
139
+ show_columns.delete("Workflow") unless catalog_item_type['workflow']
140
+ show_columns.delete("Context") unless catalog_item_type['context'] # workflow context
134
141
  print_description_list(show_columns, catalog_item_type)
135
142
 
136
143
  if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
@@ -149,25 +156,62 @@ EOT
149
156
  # print cyan,"No option types found for this catalog item.","\n",reset
150
157
  end
151
158
 
152
- if config && options[:no_config] != true
153
- print_h2 "Config YAML"
154
- #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
155
- #print reset,(as_yaml(config, options) rescue config),"\n",reset
156
- config_string = as_yaml(config, options) rescue config
157
- config_lines = config_string.split("\n")
158
- config_line_count = config_lines.size
159
- max_lines = 10
160
- if config_lines.size > max_lines
161
- config_string = config_lines.first(max_lines).join("\n")
162
- config_string << "\n\n"
163
- config_string << "(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)"
164
- #config_string << "\n"
165
- end
166
- # strip --- yaml header
167
- if config_string[0..3] == "---\n"
168
- config_string = config_string[4..-1]
159
+ item_type_code = catalog_item_type['type'].to_s.downcase
160
+ if options[:no_config] != true
161
+ if item_type_code == 'instance'
162
+ print_h2 "Config YAML"
163
+ if config
164
+ #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
165
+ #print reset,(as_yaml(config, options) rescue config),"\n",reset
166
+ config_string = as_yaml(config, options) rescue config
167
+ config_lines = config_string.split("\n")
168
+ config_line_count = config_lines.size
169
+ max_lines = 10
170
+ if config_lines.size > max_lines
171
+ config_string = config_lines.first(max_lines).join("\n")
172
+ config_string << "\n\n"
173
+ config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
174
+ #config_string << "\n"
175
+ end
176
+ # strip --- yaml header
177
+ if config_string[0..3] == "---\n"
178
+ config_string = config_string[4..-1]
179
+ end
180
+ print reset,config_string.chomp("\n"),"\n",reset
181
+ else
182
+ print reset,"(blank)","\n",reset
183
+ end
184
+ elsif item_type_code == 'blueprint' || item_type_code == 'apptemplate' || item_type_code == 'app'
185
+ print_h2 "App Spec"
186
+ if catalog_item_type['appSpec']
187
+ #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
188
+ #print reset,(as_yaml(config, options) rescue config),"\n",reset
189
+ config_string = catalog_item_type['appSpec'] || ""
190
+ config_lines = config_string.split("\n")
191
+ config_line_count = config_lines.size
192
+ max_lines = 10
193
+ if config_lines.size > max_lines
194
+ config_string = config_lines.first(max_lines).join("\n")
195
+ config_string << "\n\n"
196
+ config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
197
+ #config_string << "\n"
198
+ end
199
+ # strip --- yaml header
200
+ if config_string[0..3] == "---\n"
201
+ config_string = config_string[4..-1]
202
+ end
203
+ print reset,config_string.chomp("\n"),"\n",reset
204
+ else
205
+ print reset,"(blank)","\n",reset
206
+ end
207
+ elsif item_type_code == 'workflow' || item_type_code == 'operationalworkflow' || item_type_code == 'taskset'
169
208
  end
170
- print reset,config_string.chomp("\n"),"\n",reset
209
+ end
210
+
211
+ # Content (Wiki Page)
212
+ if !catalog_item_type["content"].to_s.empty? && options[:no_content] != true
213
+ print_h2 "Content"
214
+ print reset,catalog_item_type["content"].chomp("\n"),"\n",reset
171
215
  end
172
216
 
173
217
  print reset,"\n"
@@ -180,6 +224,10 @@ EOT
180
224
  params = {}
181
225
  optparse = Morpheus::Cli::OptionParser.new do |opts|
182
226
  opts.banner = subcommand_usage("[name] [options]")
227
+ # opts.on('-t', '--type [instance|blueprint|workflow]', "Item Type, default is instance.") do |val|
228
+ # # params['type'] = val.to_s.downcase
229
+ # options[:options]['type'] = val.to_s.downcase
230
+ # end
183
231
  build_option_type_options(opts, options, add_catalog_item_type_option_types)
184
232
  opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
185
233
  options[:config_file] = val.to_s
@@ -233,6 +281,8 @@ EOT
233
281
  payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
234
282
  else
235
283
  payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
284
+ # Type prompt first
285
+ #params['type'] = Morpheus::Cli::OptionTypes.no_prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true}], options[:options], @api_client, options[:params])['type']
236
286
  v_prompt = Morpheus::Cli::OptionTypes.prompt(add_catalog_item_type_option_types(), options[:options], @api_client, options[:params])
237
287
  params.deep_merge!(v_prompt)
238
288
  advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_catalog_item_type_advanced_option_types, options[:options], @api_client, options[:params])
@@ -241,13 +291,15 @@ EOT
241
291
  # convert checkbox "on" and "off" to true and false
242
292
  params.booleanize!
243
293
  # convert type to refType until api accepts type
244
- if params['type'] && !params['refType']
245
- if params['type'].to_s.downcase == 'blueprint'
246
- params['refType'] = 'AppTemplate'
247
- else
248
- params['refType'] = 'InstanceType'
249
- end
250
- end
294
+ # if params['type'] && !params['refType']
295
+ # if params['type'].to_s.downcase == 'instance'
296
+ # params['refType'] = 'InstanceType'
297
+ # elsif params['type'].to_s.downcase == 'blueprint'
298
+ # params['refType'] = 'AppTemplate'
299
+ # elsif params['type'].to_s.downcase == 'workflow'
300
+ # params['refType'] = 'OperationalWorkflow'
301
+ # end
302
+ # end
251
303
  # convert config string to a map
252
304
  config = params['config']
253
305
  if config && config.is_a?(String)
@@ -261,14 +313,14 @@ EOT
261
313
  params['config'] = config_map
262
314
  end
263
315
  end
264
- if params['optionTypes']
265
- # todo: move to optionSource, so it will be /api/options/optionTypes lol
266
- prompt_results = prompt_for_option_types(params, options, @api_client)
267
- if prompt_results[:success]
268
- params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
269
- else
270
- return 1
271
- end
316
+ # massage association params a bit
317
+ params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
318
+ params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
319
+ prompt_results = prompt_for_option_types(params, options, @api_client)
320
+ if prompt_results[:success]
321
+ params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
322
+ else
323
+ return 1, "failed to parse optionTypes"
272
324
  end
273
325
  payload[catalog_item_type_object_key].deep_merge!(params)
274
326
  end
@@ -280,7 +332,7 @@ EOT
280
332
  json_response = @catalog_item_types_interface.create(payload)
281
333
  catalog_item_type = json_response[catalog_item_type_object_key]
282
334
  render_response(json_response, options, catalog_item_type_object_key) do
283
- print_green_success "Added catalog item #{catalog_item_type['name']}"
335
+ print_green_success "Added catalog item type #{catalog_item_type['name']}"
284
336
  return _get(catalog_item_type["id"], {}, options)
285
337
  end
286
338
  return 0, nil
@@ -291,7 +343,7 @@ EOT
291
343
  params = {}
292
344
  payload = {}
293
345
  optparse = Morpheus::Cli::OptionParser.new do |opts|
294
- opts.banner = subcommand_usage("[catalog item type] [options]")
346
+ opts.banner = subcommand_usage("[type] [options]")
295
347
  build_option_type_options(opts, options, update_catalog_item_type_option_types)
296
348
  opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
297
349
  options[:config_file] = val.to_s
@@ -333,7 +385,7 @@ EOT
333
385
  build_standard_update_options(opts, options)
334
386
  opts.footer = <<-EOT
335
387
  Update a catalog item type.
336
- [catalog item type] is required. This is the name or id of a catalog item type.
388
+ [type] is required. This is the name or id of a catalog item type.
337
389
  EOT
338
390
  end
339
391
  optparse.parse!(args)
@@ -356,14 +408,7 @@ EOT
356
408
  params.deep_merge!(advanced_config)
357
409
  # convert checkbox "on" and "off" to true and false
358
410
  params.booleanize!
359
- # convert type to refType until api accepts type
360
- if params['type'] && !params['refType']
361
- if params['type'].to_s.downcase == 'blueprint'
362
- params['refType'] = 'AppTemplate'
363
- else
364
- params['refType'] = 'InstanceType'
365
- end
366
- end
411
+
367
412
  # convert config string to a map
368
413
  config = params['config']
369
414
  if config && config.is_a?(String)
@@ -377,6 +422,18 @@ EOT
377
422
  params['config'] = config_map
378
423
  end
379
424
  end
425
+ if params['optionTypes']
426
+ # todo: move to optionSource, so it will be /api/options/optionTypes lol
427
+ prompt_results = prompt_for_option_types(params, options, @api_client)
428
+ if prompt_results[:success]
429
+ params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
430
+ else
431
+ return 1, "failed to parse optionTypes"
432
+ end
433
+ end
434
+ # massage association params a bit
435
+ params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
436
+ params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
380
437
  payload.deep_merge!({catalog_item_type_object_key => params})
381
438
  if payload[catalog_item_type_object_key].empty? # || options[:no_prompt]
382
439
  raise_command_error "Specify at least one option to update.\n#{optparse}"
@@ -390,7 +447,7 @@ EOT
390
447
  json_response = @catalog_item_types_interface.update(catalog_item_type['id'], payload)
391
448
  catalog_item_type = json_response[catalog_item_type_object_key]
392
449
  render_response(json_response, options, catalog_item_type_object_key) do
393
- print_green_success "Updated catalog item #{catalog_item_type['name']}"
450
+ print_green_success "Updated catalog item type #{catalog_item_type['name']}"
394
451
  return _get(catalog_item_type["id"], {}, options)
395
452
  end
396
453
  return 0, nil
@@ -400,11 +457,11 @@ EOT
400
457
  options = {}
401
458
  params = {}
402
459
  optparse = Morpheus::Cli::OptionParser.new do |opts|
403
- opts.banner = subcommand_usage("[catalog item type] [options]")
460
+ opts.banner = subcommand_usage("[type] [options]")
404
461
  build_standard_remove_options(opts, options)
405
462
  opts.footer = <<-EOT
406
- Delete a catalog_item_type.
407
- [catalog item type] is required. This is the name or id of a catalog item type.
463
+ Delete a catalog item type.
464
+ [type] is required. This is the name or id of a catalog item type.
408
465
  EOT
409
466
  end
410
467
  optparse.parse!(args)
@@ -417,12 +474,12 @@ EOT
417
474
  print_dry_run @catalog_item_types_interface.dry.destroy(catalog_item_type['id'], params)
418
475
  return
419
476
  end
420
- unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item #{catalog_item_type['name']}?")
477
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item type #{catalog_item_type['name']}?")
421
478
  return 9, "aborted command"
422
479
  end
423
480
  json_response = @catalog_item_types_interface.destroy(catalog_item_type['id'], params)
424
481
  render_response(json_response, options) do
425
- print_green_success "Removed catalog item #{catalog_item_type['name']}"
482
+ print_green_success "Removed catalog item type #{catalog_item_type['name']}"
426
483
  end
427
484
  return 0, nil
428
485
  end
@@ -436,6 +493,9 @@ EOT
436
493
  "Description" => 'description',
437
494
  "Type" => lambda {|it| format_catalog_type(it) },
438
495
  "Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
496
+ "Workflow" => lambda {|it| it['workflow'] ? it['workflow']['name'] : nil },
497
+ "Context" => lambda {|it| it['context'] },
498
+ # "Content" => lambda {|it| it['content'] },
439
499
  "Enabled" => lambda {|it| format_boolean(it['enabled']) },
440
500
  "Featured" => lambda {|it| format_boolean(it['featured']) },
441
501
  #"Config" => lambda {|it| it['config'] },
@@ -455,6 +515,7 @@ EOT
455
515
  out << (catalog_item_type['type']['name'] || catalog_item_type['type']['code']) rescue catalog_item_type['type'].to_s
456
516
  end
457
517
  else
518
+ # refType is not returned
458
519
  ref_type = catalog_item_type['refType']
459
520
  if ref_type == 'InstanceType'
460
521
  out << "Instance"
@@ -469,18 +530,24 @@ EOT
469
530
  out
470
531
  end
471
532
 
472
- # this is not so simple, need to first choose select instance, host or provider
473
533
  def add_catalog_item_type_option_types
474
534
  [
535
+ {'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true},
475
536
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
476
537
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
477
- {'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}], 'defaultValue' => 'instance'},
478
538
  {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
479
539
  {'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false},
480
540
  {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true},
481
541
  {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList'},
482
542
  #{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.'},
483
- {'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'JSON or YAML'}
543
+ {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true},
544
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true},
545
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true},
546
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'noParams' => true},
547
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
548
+ [{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
549
+ }, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
550
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item'}
484
551
  ]
485
552
  end
486
553
 
@@ -489,11 +556,13 @@ EOT
489
556
  end
490
557
 
491
558
  def update_catalog_item_type_option_types
492
- add_catalog_item_type_option_types.collect {|it|
559
+ list = add_catalog_item_type_option_types.collect {|it|
493
560
  it.delete('required')
494
561
  it.delete('defaultValue')
495
562
  it
496
563
  }
564
+ list = list.reject {|it| ["type"].include? it['fieldName'] }
565
+ list
497
566
  end
498
567
 
499
568
  def update_catalog_item_type_advanced_option_types
@@ -504,4 +573,50 @@ EOT
504
573
  }
505
574
  end
506
575
 
576
+ def catalog_item_type_object_key
577
+ 'catalogItemType'
578
+ end
579
+
580
+ def catalog_item_type_list_key
581
+ 'catalogItemTypes'
582
+ end
583
+
584
+ def find_catalog_item_type_by_name_or_id(val)
585
+ if val.to_s =~ /\A\d{1,}\Z/
586
+ return find_catalog_item_type_by_id(val)
587
+ else
588
+ return find_catalog_item_type_by_name(val)
589
+ end
590
+ end
591
+
592
+ def find_catalog_item_type_by_id(id)
593
+ begin
594
+ json_response = @catalog_item_types_interface.get(id.to_i)
595
+ return json_response[catalog_item_type_object_key]
596
+ rescue RestClient::Exception => e
597
+ if e.response && e.response.code == 404
598
+ print_red_alert "catalog item type not found by id '#{id}'"
599
+ else
600
+ raise e
601
+ end
602
+ end
603
+ end
604
+
605
+ def find_catalog_item_type_by_name(name)
606
+ json_response = @catalog_item_types_interface.list({name: name.to_s})
607
+ catalog_item_types = json_response[catalog_item_type_list_key]
608
+ if catalog_item_types.empty?
609
+ print_red_alert "catalog item type not found by name '#{name}'"
610
+ return nil
611
+ elsif catalog_item_types.size > 1
612
+ print_red_alert "#{catalog_item_types.size} catalog item types found by name '#{name}'"
613
+ puts_error as_pretty_table(catalog_item_types, [:id, :name], {color:red})
614
+ print_red_alert "Try using ID instead"
615
+ print reset,"\n"
616
+ return nil
617
+ else
618
+ return catalog_item_types[0]
619
+ end
620
+ end
621
+
507
622
  end
@@ -203,7 +203,13 @@ module Morpheus
203
203
  # value_label = 'SELECT'
204
204
  # elsif option['type'] == 'select'
205
205
  end
206
- opts.on("--#{full_field_name} #{value_label}", String, description) do |val|
206
+ full_option = "--#{full_field_name} #{value_label}"
207
+ shorthand_option = option_type['shorthand']
208
+ arg1, arg2 = full_option, String
209
+ if option_type['shorthand']
210
+ arg1, arg2 = full_option, option_type['shorthand']
211
+ end
212
+ opts.on(arg1, arg2, description) do |val|
207
213
  if option_type['type'] == 'checkbox'
208
214
  val = (val.to_s != 'false' && val.to_s != 'off')
209
215
  else
@@ -269,6 +275,11 @@ module Morpheus
269
275
  build_standard_delete_options(opts, options, includes, excludes)
270
276
  end
271
277
 
278
+ # number of decimal places to show with curreny
279
+ def default_sigdig
280
+ 2
281
+ end
282
+
272
283
  # appends to the passed OptionParser all the generic options
273
284
  # @param opts [OptionParser] the option parser object being constructed
274
285
  # @param options [Hash] the output Hash that is to being modified
@@ -309,6 +320,20 @@ module Morpheus
309
320
  opts.add_hidden_option('-a, --account') if opts.is_a?(Morpheus::Cli::OptionParser)
310
321
  opts.add_hidden_option('-A, --account-id') if opts.is_a?(Morpheus::Cli::OptionParser)
311
322
 
323
+ when :details
324
+ opts.on('-a', '--all', "Show all details." ) do
325
+ options[:details] = true
326
+ end
327
+ opts.on('--details', '--details', "Show more details" ) do
328
+ options[:details] = true
329
+ end
330
+ opts.add_hidden_option('--details')
331
+
332
+ when :sigdig
333
+ opts.on('--sigdig DIGITS', "Significant digits to display for prices (currency). Default is #{default_sigdig}.") do |val|
334
+ options[:sigdig] = val.to_i
335
+ end
336
+
312
337
  when :options
313
338
  options[:options] ||= {}
314
339
  opts.on( '-O', '--option OPTION', "Option in the format -O field=\"value\"" ) do |option|
@@ -602,13 +627,13 @@ module Morpheus
602
627
  end
603
628
  # opts.add_hidden_option('-H') if opts.is_a?(Morpheus::Cli::OptionParser)
604
629
  # opts.add_hidden_option('--header') if opts.is_a?(Morpheus::Cli::OptionParser)
605
- opts.add_hidden_option('--headers') if opts.is_a?(Morpheus::Cli::OptionParser)
630
+ opts.add_hidden_option('-H, --header') if opts.is_a?(Morpheus::Cli::OptionParser)
606
631
 
607
632
  #when :timeout
608
633
  opts.on( '--timeout SECONDS', "Timeout for api requests. Default is typically 30 seconds." ) do |val|
609
634
  options[:timeout] = val ? val.to_f : nil
610
635
  end
611
- # opts.add_hidden_option('--timeout') if opts.is_a?(Morpheus::Cli::OptionParser)
636
+ opts.add_hidden_option('--timeout') if opts.is_a?(Morpheus::Cli::OptionParser)
612
637
 
613
638
  when :auto_confirm
614
639
  opts.on( '-y', '--yes', "Auto Confirm" ) do
@@ -715,7 +740,7 @@ module Morpheus
715
740
 
716
741
 
717
742
  when :dry_run
718
- opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do
743
+ opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it.") do
719
744
  # todo: this should print after parsing obv..
720
745
  # need a hook after parse! or a standard_handle(options) { ... } paradigm
721
746
  # either that or hook it up in every command somehow, maybe a hook on connect()
@@ -727,7 +752,7 @@ module Morpheus
727
752
  end
728
753
  options[:dry_run] = true
729
754
  end
730
- opts.on(nil,'--curl', "Dry Run to output API request as a curl command.") do
755
+ opts.on(nil,'--curl', "Curl, print the API request as a curl command instead of executing it.") do
731
756
  # print once and dont munge json
732
757
  if !options[:dry_run] && !options[:json]
733
758
  puts "#{cyan}#{bold}#{dark}DRY RUN#{reset}"
@@ -830,10 +855,18 @@ module Morpheus
830
855
  opts
831
856
  end
832
857
 
858
+ def prog_name
859
+ self.class.prog_name
860
+ end
861
+
833
862
  def command_name
834
863
  self.class.command_name
835
864
  end
836
865
 
866
+ def command_description
867
+ self.class.command_description
868
+ end
869
+
837
870
  def subcommands
838
871
  self.class.subcommands
839
872
  end
@@ -870,14 +903,14 @@ module Morpheus
870
903
 
871
904
  def usage
872
905
  if !subcommands.empty?
873
- "Usage: morpheus #{command_name} [command] [options]"
906
+ "Usage: #{prog_name} #{command_name} [command] [options]"
874
907
  else
875
- "Usage: morpheus #{command_name} [options]"
908
+ "Usage: #{prog_name} #{command_name} [options]"
876
909
  end
877
910
  end
878
911
 
879
912
  def my_help_command
880
- "morpheus #{command_name} --help"
913
+ "#{prog_name} #{command_name} --help"
881
914
  end
882
915
 
883
916
  def subcommand_usage(*extra)
@@ -888,7 +921,7 @@ module Morpheus
888
921
  extra.shift
889
922
  end
890
923
  #extra = ["[options]"] if extra.empty?
891
- "Usage: morpheus #{command_name} #{subcommand_name} #{extra.join(' ')}".squeeze(' ').strip
924
+ "Usage: #{prog_name} #{command_name} #{subcommand_name} #{extra.join(' ')}".squeeze(' ').strip
892
925
  end
893
926
 
894
927
  # a string to describe the usage of your command
@@ -908,6 +941,10 @@ module Morpheus
908
941
  out << "\n"
909
942
  }
910
943
  end
944
+ if command_description
945
+ out << "\n"
946
+ out << "#{command_description}\n"
947
+ end
911
948
  # out << "\n"
912
949
  out
913
950
  end
@@ -939,7 +976,7 @@ module Morpheus
939
976
  end
940
977
  cmd_method = subcommands[subcommand_name]
941
978
  if !cmd_method
942
- error_msg = "'#{command_name} #{subcommand_name}' is not a morpheus command.\n#{full_command_usage}"
979
+ error_msg = "'#{command_name} #{subcommand_name}' is not a #{prog_name} command.\n#{full_command_usage}"
943
980
  raise CommandNotFoundError.new(error_msg)
944
981
  end
945
982
  self.send(cmd_method, args[1..-1])
@@ -1295,6 +1332,10 @@ module Morpheus
1295
1332
 
1296
1333
  module ClassMethods
1297
1334
 
1335
+ def prog_name
1336
+ "morpheus"
1337
+ end
1338
+
1298
1339
  def set_command_name(cmd_name)
1299
1340
  @command_name = cmd_name
1300
1341
  Morpheus::Cli::CliRegistry.add(self, self.command_name)