Module: Morpheus::Cli::RestCommand

Included in:
LoadBalancerTypes, 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.

# An 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_plural_label "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



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

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



469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 469

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



502
503
504
505
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
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 502

def add(args)
  record_type_id = nil
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    if rest_has_type
      opts.banner = subcommand_usage("[name] -t TYPE")
      opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
        record_type_id = val
      end
    else
      opts.banner = subcommand_usage("[name]")
    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)
  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.



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

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



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 448

def get(args)
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[type]")
    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



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

def handle(args)
  handle_subcommand(args)
end

#list(args) ⇒ Object



414
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
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 414

def list(args)
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage()
    build_standard_list_options(opts, options)
    opts.footer = "List #{rest_plural_label.downcase}."
  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_plural_label}"
    if records.nil? || records.empty?
      print cyan,"No #{rest_plural_label.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



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

def registered_interfaces
  self.class.registered_interfaces
end

#remove(args) ⇒ Object



625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 625

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)
  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



487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 487

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



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

def rest_arg
  self.class.rest_arg
end

#rest_column_definitionsObject



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

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

#rest_find_by_name_or_id(name) ⇒ Object



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

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

#rest_has_typeObject



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

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



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

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

#rest_interface_nameObject



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

def rest_interface_name
  self.class.rest_interface_name
end

#rest_keyObject



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

def rest_key
  self.class.rest_key
end

#rest_labelObject



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

def rest_label
  self.class.rest_label
end

#rest_list_column_definitionsObject



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

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

#rest_list_keyObject



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

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

#rest_nameObject



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

def rest_name
  self.class.rest_name
end

#rest_object_keyObject



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

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

#rest_plural_labelObject



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

def rest_plural_label
  self.class.rest_plural_label
end

#rest_type_argObject



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

def rest_type_arg
  self.class.rest_type_arg
end

#rest_type_column_definitionsObject



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

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

#rest_type_find_by_name_or_id(name) ⇒ Object



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

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



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

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

#rest_type_interface_nameObject



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

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

#rest_type_keyObject



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

def rest_type_key
  self.class.rest_type_key
end

#rest_type_labelObject



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

def rest_type_label
  self.class.rest_type_label
end

#rest_type_list_column_definitionsObject



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

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

#rest_type_list_keyObject



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

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



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

def rest_type_name
  self.class.rest_type_name
end

#rest_type_object_keyObject



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

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

#rest_type_plural_labelObject



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

def rest_type_plural_label
  self.class.rest_type_plural_label
end

#update(args) ⇒ Object



587
588
589
590
591
592
593
594
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
# File 'lib/morpheus/cli/mixins/rest_command.rb', line 587

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)
  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