Module: Morpheus::Cli::RestCommand

Included in:
LoadBalancerPools, LoadBalancerTypes, LoadBalancerVirtualServers, LoadBalancers
Defined in:
lib/morpheus/cli/mixins/rest_command.rb

Overview

RestCommand is a mixin for Morpheus::Cli command classes. Provides basic CRUD commands: list, get, add, update, remove Currently the command class must also include Morpheus::Cli::CliCommand The command class can define a few variables to dictate what the resource is called and the the api interface used to fetch the records. The command class or helper must also provide several methods to provide the default behavior. In the example below, the command (helper) defines the following methods:

* load_balancer_object_key() - Key name of object returned by the "get" api endpoint.
* load_balancer_list_key() - Key name of array of records returned by the "list" api endpoint.
* load_balancer_column_definitions() - Column definitions for the "get" command display output.
* load_balancer_list_column_definitions() - Column definitions for the "list" command display output.

Example of a RestCommand for ‘morpheus load-balancers`.

class Morpheus::Cli::LoadBalancers

include Morpheus::Cli::CliCommand
include Morpheus::Cli::RestCommand
include Morpheus::Cli::LoadBalancersHelper

# All of the example settings below are redundant
# and would be the default values if not set.
set_rest_name :load_balancers
set_rest_label "Load Balancer"
set_rest_label_plural "Load Balancers"
set_rest_object_key "load_balancer"
set_rest_has_type true
set_rest_type "load_balancer_types"
register_interfaces :load_balancers, :load_balancer_types

end

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



34
35
36
37
38
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 34

def self.included(base)
  #puts "including RestCommand for #{base}"
  #base.send :include, Morpheus::Cli::CliCommand
  base.extend ClassMethods
end

Instance Method Details

#_get(id, params, options) ⇒ Object



473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 473

def _get(id, params, options)
  if id !~ /\A\d{1,}\Z/
    record = rest_find_by_name_or_id(id)
    if record.nil?
      raise_command_error "#{rest_label} not found for name '#{id}'"
    end
    id = record['id']
  end
  rest_interface.setopts(options)
  if options[:dry_run]
    print_dry_run rest_interface.dry.get(id, params)
    return
  end
  json_response = rest_interface.get(id, params)
  render_response_for_get(json_response, options)
  return 0, nil
end

#add(args) ⇒ Object



506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 506

def add(args)
  record_type_id = nil
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    if rest_has_type
      opts.banner = subcommand_usage("[#{rest_arg}] -t TYPE")
      opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
        record_type_id = val
      end
    else
      opts.banner = subcommand_usage("[#{rest_arg}]")
    end
    # if defined?(add_#{rest_key}_option_types)
    #   build_option_type_options(opts, options, add_#{rest_key}_option_types)
    # end
    build_standard_add_options(opts, options)
    opts.footer = "Create a new \#{rest_label.downcase}.\n[\#{rest_arg}] is required. This is the name of the new \#{rest_label.downcase}.\n"
  end
  optparse.parse!(args)
  # todo: make supporting args[0] optional and more flexible
  # for now args[0] is assumed to be the 'name'
  record_name = nil
  if args[0] # && rest_has_name
    record_name = args[0]
  end
  verify_args!(args:args, optparse:optparse, min:0, max: 1)
  # todo: maybe need a flag to make this required, it could be an option type too, so
  if rest_has_type
    if record_type_id.nil?
      raise_command_error "#{rest_type_label} is required.\n#{optparse}"
    end
  end
  connect(options)
  if rest_has_type
    record_type = rest_type_find_by_name_or_id(record_type_id)
    if record_type.nil?
      raise_command_error "#{rest_type_label} not found for '#{record_type_id}'.\n#{optparse}"
    end
  end
  passed_options = parse_passed_options(options)
  payload = {}
  if options[:payload]
    payload = options[:payload]
    payload.deep_merge!({rest_object_key => passed_options})
  else
    record_payload = {}
    if record_name
      record_payload['name'] = record_name
      options[:options]['name'] = record_name # injected for prompt
    end
    if rest_has_type && record_type
      # record_payload['type'] = {'code' => record_type['code']}
      record_payload['type'] = record_type['code']
      options[:options]['type'] = record_type['code'] # injected for prompt
    end
    record_payload.deep_merge!(passed_options)
    # options by type
    my_option_types = record_type ? record_type['optionTypes'] : nil
    if my_option_types && !my_option_types.empty?
      # remove redundant fieldContext
      my_option_types.each do |option_type| 
        if option_type['fieldContext'] == rest_object_key
          option_type['fieldContext'] = nil
        end
      end
      v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
      v_prompt.deep_compact!
      v_prompt.booleanize! # 'on' => true
      record_payload.deep_merge!(v_prompt)
    end
    payload[rest_object_key] = record_payload
  end
  rest_interface.setopts(options)
  if options[:dry_run]
    print_dry_run rest_interface.dry.create(payload)
    return
  end      
  json_response = rest_interface.create(payload)
  render_response(json_response, options, rest_object_key) do
    record = json_response[rest_object_key]
    print_green_success "Added #{rest_label.downcase} #{record['name'] || record['id']}"
    return _get(record["id"], {}, options)
  end
  return 0, nil
end

#connect(options) ⇒ Object

standard connect method to establish @api_client and @name_interface variables for each registered interface.



398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 398

def connect(options)
  @api_client = establish_remote_appliance_connection(options)
  self.class.registered_interfaces.each do |interface_name|
    if interface_name.is_a?(String) || interface_name.is_a?(Symbol)
      instance_variable_set("@#{interface_name}_interface", @api_client.send(interface_name))
    elsif interface_name.is_a?(Hash)
      interface_name.each do |k,v|
        instance_variable_set("#{k}_interface", @api_client.send(v))
      end
    end
  end
end

#get(args) ⇒ Object



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 452

def get(args)
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[#{rest_arg}]")
    build_standard_get_options(opts, options)
    opts.footer = "Get details about \#{a_or_an(rest_label)} \#{rest_label.downcase}.\n[\#{rest_arg}] is required. This is the name or id of \#{a_or_an(rest_label)} \#{rest_label.downcase}.\n"
  end
  optparse.parse!(args)
  verify_args!(args:args, optparse:optparse, min:1)
  connect(options)
  params.merge!(parse_query_options(options))
  id_list = parse_id_list(args)
  return run_command_for_each_arg(id_list) do |arg|
    _get(arg, params, options)
  end
end

#handle(args) ⇒ Object



411
412
413
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 411

def handle(args)
  handle_subcommand(args)
end

#list(args) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 415

def list(args)
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[search]")
    build_standard_list_options(opts, options)
          opts.footer = "List \#{rest_label_plural.downcase}.\n[search] is optional. This is a search phrase to filter the results.\n"
  end
  optparse.parse!(args)
  connect(options)
  if args.count > 0
    options[:phrase] = args.join(" ")
  end
  params.merge!(parse_list_options(options))
  rest_interface.setopts(options)
  if options[:dry_run]
    print_dry_run rest_interface.dry.list(params)
    return
  end
  json_response = rest_interface.list(params)
  render_response(json_response, options, rest_list_key) do
    records = json_response[rest_list_key]
    print_h1 "Morpheus #{rest_label_plural}"
    if records.nil? || records.empty?
      print cyan,"No #{rest_label_plural.downcase} found.",reset,"\n"
    else
      print as_pretty_table(records, rest_list_column_definitions.upcase_keys!, options)
      print_results_pagination(json_response) if json_response['meta']
    end
    print reset,"\n"
  end
  return 0, nil
end

#registered_interfacesObject



392
393
394
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 392

def registered_interfaces
  self.class.registered_interfaces
end

#remove(args) ⇒ Object



637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 637

def remove(args)
  id = args[0]
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[#{rest_arg}]")
    build_standard_remove_options(opts, options)
    opts.footer = "Delete an existing \#{rest_label.downcase}.\n[\#{rest_arg}] is required. This is the name or id of \#{a_or_an(rest_label)} \#{rest_label.downcase}.\n"
  end
  optparse.parse!(args)
  verify_args!(args:args, optparse:optparse, count:1)
  connect(options)
  params.merge!(parse_query_options(options))
  record = rest_find_by_name_or_id(id)
  if record.nil?
    return 1, "#{rest_name} not found for '#{id}'"
  end
  unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the #{rest_label.downcase} #{record['name'] || record['id']}?")
    return 9, "aborted"
  end
  rest_interface.setopts(options)
  if options[:dry_run]
    print_dry_run rest_interface.dry.destroy(record['id'])
    return 0, nil
  end
  json_response = rest_interface.destroy(record['id'], params)
  render_response(json_response, options) do
    print_green_success "Removed #{rest_label.downcase} #{record['name'] || record['id']}"
  end
  return 0, nil
end

#render_response_for_get(json_response, options) ⇒ Object



491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 491

def render_response_for_get(json_response, options)
  render_response(json_response, options, rest_object_key) do
    record = json_response[rest_object_key]
    print_h1 rest_label, [], options
    print cyan
    print_description_list(rest_column_definitions, record, options)
    # show config settings...
    if record['optionTypes'] && record['optionTypes'].size > 0
      print_h2 "Option Types", options
      print format_option_types_table(record['optionTypes'], options, rest_object_key)
    end
    print reset,"\n"
  end
end

#rest_argObject



296
297
298
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 296

def rest_arg
  self.class.rest_arg
end

#rest_column_definitionsObject



326
327
328
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 326

def rest_column_definitions
  self.send("#{rest_key}_column_definitions")
end

#rest_find_by_name_or_id(name) ⇒ Object



334
335
336
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 334

def rest_find_by_name_or_id(name)
  return self.send("find_#{rest_key}_by_name_or_id", name)
end

#rest_has_typeObject



338
339
340
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 338

def rest_has_type
  self.class.rest_has_type
end

#rest_interfaceObject

returns the default rest interface, allows using rest_interface_name = “your” or override this method to return @your_interface if needed



314
315
316
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 314

def rest_interface
  instance_variable_get("@#{rest_interface_name}_interface")
end

#rest_interface_nameObject



308
309
310
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 308

def rest_interface_name
  self.class.rest_interface_name
end

#rest_keyObject



292
293
294
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 292

def rest_key
  self.class.rest_key
end

#rest_labelObject



300
301
302
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 300

def rest_label
  self.class.rest_label
end

#rest_label_pluralObject



304
305
306
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 304

def rest_label_plural
  self.class.rest_label_plural
end

#rest_list_column_definitionsObject



330
331
332
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 330

def rest_list_column_definitions
  self.send("#{rest_key}_list_column_definitions")
end

#rest_list_keyObject



322
323
324
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 322

def rest_list_key
  self.send("#{rest_key}_list_key")
end

#rest_nameObject



288
289
290
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 288

def rest_name
  self.class.rest_name
end

#rest_object_keyObject



318
319
320
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 318

def rest_object_key
  self.send("#{rest_key}_object_key")
end

#rest_type_argObject



352
353
354
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 352

def rest_type_arg
  self.class.rest_type_arg
end

#rest_type_column_definitionsObject



380
381
382
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 380

def rest_type_column_definitions
  self.send("#{rest_type_key}_column_definitions")
end

#rest_type_find_by_name_or_id(name) ⇒ Object



388
389
390
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 388

def rest_type_find_by_name_or_id(name)
  return self.send("find_#{rest_type_key}_by_name_or_id", name)
end

#rest_type_interfaceObject



368
369
370
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 368

def rest_type_interface
  instance_variable_get("@#{rest_type_interface_name}_interface")
end

#rest_type_interface_nameObject



364
365
366
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 364

def rest_type_interface_name
  self.class.rest_type_interface_name # || "@#{rest_type_name}_interface"
end

#rest_type_keyObject



348
349
350
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 348

def rest_type_key
  self.class.rest_type_key
end

#rest_type_labelObject



356
357
358
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 356

def rest_type_label
  self.class.rest_type_label
end

#rest_type_label_pluralObject



360
361
362
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 360

def rest_type_label_plural
  self.class.rest_type_label_plural
end

#rest_type_list_column_definitionsObject



384
385
386
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 384

def rest_type_list_column_definitions
  self.send("#{rest_type_key}_list_column_definitions")
end

#rest_type_list_keyObject



376
377
378
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 376

def rest_type_list_key
  self.send("#{rest_type_key}_list_key")
end

#rest_type_nameObject

duplicated the rest_* settings with rest_type, for the types resource



344
345
346
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 344

def rest_type_name
  self.class.rest_type_name
end

#rest_type_object_keyObject



372
373
374
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 372

def rest_type_object_key
  self.send("#{rest_type_key}_object_key")
end

#update(args) ⇒ Object



595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 595

def update(args)
  id = args[0]
  options = {}
  params = {}
   = nil
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[#{rest_arg}] [options]")
    build_standard_update_options(opts, options)
    opts.footer = "Update an existing \#{rest_label.downcase}.\n[\#{rest_arg}] is required. This is the name or id of \#{a_or_an(rest_label)} \#{rest_label.downcase}.\n"
  end
  optparse.parse!(args)
  verify_args!(args:args, optparse:optparse, count:1)
  connect(options)
  record = rest_find_by_name_or_id(id)
  passed_options = parse_passed_options(options)
  payload = nil
  if options[:payload]
    payload = options[:payload]
    payload.deep_merge!({rest_object_key => passed_options}) unless passed_options.empty?
  else
    record_payload = passed_options
    if record_payload.empty?
      raise_command_error "Specify at least one option to update.\n#{optparse}"
    end
    payload[rest_object_key] = record_payload
  end
  rest_interface.setopts(options)
  if options[:dry_run]
    print_dry_run rest_interface.dry.update(record['id'], payload)
    return
  end
  json_response = rest_interface.update(record['id'], payload)
  render_response(json_response, options, rest_object_key) do
    print_green_success "Updated #{rest_label.downcase} #{record['name'] || record['id']}"
    _get(record["id"], {}, options)
  end
  return 0, nil
end