morpheus-cli 5.3.3 → 5.3.4

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/api_client.rb +12 -0
  4. data/lib/morpheus/api/clouds_interface.rb +4 -11
  5. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  6. data/lib/morpheus/api/load_balancer_profiles_interface.rb +10 -0
  7. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +4 -4
  8. data/lib/morpheus/api/network_routers_interface.rb +21 -0
  9. data/lib/morpheus/api/network_servers_interface.rb +42 -0
  10. data/lib/morpheus/api/rest_interface.rb +2 -1
  11. data/lib/morpheus/api/virtual_servers_interface.rb +9 -0
  12. data/lib/morpheus/cli/cli_command.rb +2 -1
  13. data/lib/morpheus/cli/cloud_resource_pools_command.rb +1 -1
  14. data/lib/morpheus/cli/clouds.rb +22 -40
  15. data/lib/morpheus/cli/hosts.rb +0 -1
  16. data/lib/morpheus/cli/instances.rb +111 -7
  17. data/lib/morpheus/cli/invoices_command.rb +42 -38
  18. data/lib/morpheus/cli/library_option_lists_command.rb +3 -3
  19. data/lib/morpheus/cli/load_balancer_pools.rb +111 -0
  20. data/lib/morpheus/cli/load_balancer_virtual_servers.rb +136 -0
  21. data/lib/morpheus/cli/load_balancers.rb +0 -155
  22. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +2 -2
  23. data/lib/morpheus/cli/mixins/provisioning_helper.rb +32 -11
  24. data/lib/morpheus/cli/mixins/rest_command.rb +53 -37
  25. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +488 -0
  26. data/lib/morpheus/cli/network_routers_command.rb +291 -7
  27. data/lib/morpheus/cli/network_scopes_command.rb +442 -0
  28. data/lib/morpheus/cli/networks_command.rb +2 -2
  29. data/lib/morpheus/cli/option_types.rb +20 -0
  30. data/lib/morpheus/cli/subnets_command.rb +7 -2
  31. data/lib/morpheus/cli/tasks.rb +25 -2
  32. data/lib/morpheus/cli/version.rb +1 -1
  33. data/lib/morpheus/cli/virtual_images.rb +2 -0
  34. data/lib/morpheus/cli.rb +9 -1
  35. metadata +9 -2
@@ -17,6 +17,7 @@ class Morpheus::Cli::NetworkRoutersCommand
17
17
  register_subcommands :add_route, :remove_route, :routes
18
18
  register_subcommands :update_permissions
19
19
  register_subcommands :add_nat, :update_nat, :remove_nat, :nats, :nat
20
+ register_subcommands :add_bgp_neighbor, :update_bgp_neighbor, :remove_bgp_neighbor, :bgp_neighbors, :bgp_neighbor
20
21
 
21
22
  def initialize()
22
23
  end
@@ -313,7 +314,7 @@ class Morpheus::Cli::NetworkRoutersCommand
313
314
  server_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'networkServer', 'type' => 'select', 'fieldLabel' => 'Network Server', 'required' => true, 'optionSource' => 'networkServer'}], options[:options], @api_client, params, nil, true)['networkServer']
314
315
  server = {'id' => server_id}
315
316
  end
316
- router['networkServer'] = {'id' => server['id']}
317
+ params['router']['networkServer'] = router['networkServer'] = {'id' => server['id']}
317
318
  params['networkServerId'] = server['id']
318
319
  else
319
320
  # prompt cloud
@@ -1517,11 +1518,11 @@ class Morpheus::Cli::NetworkRoutersCommand
1517
1518
  options = {}
1518
1519
  query_params = {}
1519
1520
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1520
- opts.banner = subcommand_usage("[router] [rule]")
1521
+ opts.banner = subcommand_usage("[router] [route]")
1521
1522
  build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
1522
1523
  opts.footer = "Delete a network router route.\n" +
1523
- "[router] is required. This is the name or id of an existing network router."
1524
- "[route] is required. This is the name or id of an existing network router route."
1524
+ "[router] is required. This is the name or id of an existing network router."
1525
+ "[route] is required. This is the name or id of an existing network router route."
1525
1526
  end
1526
1527
  optparse.parse!(args)
1527
1528
  if args.count != 2
@@ -1628,11 +1629,11 @@ class Morpheus::Cli::NetworkRoutersCommand
1628
1629
  def nat(args)
1629
1630
  options = {}
1630
1631
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1631
- opts.banner = subcommand_usage("[router] [rule]")
1632
+ opts.banner = subcommand_usage("[router] [nat]")
1632
1633
  build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
1633
1634
  opts.footer = "Display network router firewall rule details." + "\n" +
1634
1635
  "[router] is required. This is the name or id of a network router.\n" +
1635
- "[rule] is required. This is the name or id of a firewall rule.\n"
1636
+ "[nat] is required. This is the name or id of a NAT.\n"
1636
1637
  end
1637
1638
 
1638
1639
  optparse.parse!(args)
@@ -1887,6 +1888,268 @@ class Morpheus::Cli::NetworkRoutersCommand
1887
1888
  end
1888
1889
  end
1889
1890
 
1891
+ def bgp_neighbors(args)
1892
+ options = {}
1893
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1894
+ opts.banner = subcommand_usage("[router]")
1895
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
1896
+ opts.footer = "List network router BGP neighbors." + "\n" +
1897
+ "[router] is required. This is the name or id of a network router."
1898
+ end
1899
+
1900
+ optparse.parse!(args)
1901
+ connect(options)
1902
+
1903
+ if args.count < 1
1904
+ puts optparse
1905
+ return 1
1906
+ end
1907
+ _bgp_neighbors(args[0], options)
1908
+ end
1909
+
1910
+ def _bgp_neighbors(router_id, options)
1911
+ @network_routers_interface.setopts(options)
1912
+ if options[:dry_run]
1913
+ if args[0].to_s =~ /\A\d{1,}\Z/
1914
+ print_dry_run @network_routers_interface.dry.get(router_id.to_i)
1915
+ else
1916
+ print_dry_run @network_routers_interface.dry.list({name:router_id})
1917
+ end
1918
+ return
1919
+ end
1920
+ router = find_router(router_id)
1921
+ if router.nil?
1922
+ return 1
1923
+ end
1924
+
1925
+ if router['type']['hasBgp']
1926
+ json_response = {'networkRouterBgpNeighbors' => router['bgpNeighbors']}
1927
+ render_response(json_response, options, 'networkRouterBgpNeighbor') do
1928
+ print_h1 "Network Router BGP Neighbors For: #{router['name']}"
1929
+ print cyan
1930
+ print_bgp_neighbors(router)
1931
+ end
1932
+ else
1933
+ print_red_alert "BGP not supported for #{router['type']['name']}"
1934
+ end
1935
+ print reset
1936
+ end
1937
+
1938
+ def bgp_neighbor(args)
1939
+ options = {}
1940
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
1941
+ opts.banner = subcommand_usage("[router] [BGP neighbor]")
1942
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
1943
+ opts.footer = "Display details on network router BGP neighbor." + "\n" +
1944
+ "[router] is required. This is the name or id of a network router.\n" +
1945
+ "[BGP neighbor] is required. This is the id of a BGP neighbor.\n"
1946
+ end
1947
+
1948
+ optparse.parse!(args)
1949
+ connect(options)
1950
+
1951
+ if args.count < 2
1952
+ puts optparse
1953
+ return 1
1954
+ end
1955
+
1956
+ @network_routers_interface.setopts(options)
1957
+ if options[:dry_run]
1958
+ if args[0].to_s =~ /\A\d{1,}\Z/
1959
+ print_dry_run @network_routers_interface.dry.get(args[0].to_i)
1960
+ else
1961
+ print_dry_run @network_routers_interface.dry.list({name:args[0]})
1962
+ end
1963
+ return
1964
+ end
1965
+ router = find_router(args[0])
1966
+ if router.nil?
1967
+ return 1
1968
+ end
1969
+
1970
+ if router['type']['hasBgp']
1971
+ bgp_neighbor = (router['bgpNeighbors'] || []).find {|it| it['id'] == args[1].to_i}
1972
+
1973
+ if bgp_neighbor
1974
+ json_response = {'networkRouterBgpNeighbor' => bgp_neighbor}
1975
+ render_response(json_response, options, 'networkRouterBgpNeighbor') do
1976
+ print_h1 "Network Router BGP Neighbor Details"
1977
+ print cyan
1978
+
1979
+ description_cols = {
1980
+ "ID" => lambda {|it| it['id']}
1981
+ }
1982
+
1983
+ router['type']['bgpNeighborOptionTypes'].sort_by {|it| it['displayOrder']}.each do |option_type|
1984
+ description_cols[option_type['fieldLabel']] = lambda {|it| Morpheus::Cli::OptionTypes.get_option_value(it, option_type, true)}
1985
+ end
1986
+ print_description_list(description_cols, bgp_neighbor)
1987
+ end
1988
+ else
1989
+ print_red_alert "BGP Neighbors #{args[1]} not found for router #{router['name']}"
1990
+ end
1991
+ else
1992
+ print_red_alert "BGP Neighbors not supported for #{router['type']['name']}"
1993
+ end
1994
+ println reset
1995
+ end
1996
+
1997
+ def add_bgp_neighbor(args)
1998
+ options = {:options=>{}}
1999
+ params = {}
2000
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
2001
+ opts.banner = subcommand_usage("[router]")
2002
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
2003
+ opts.footer = "Create a network router BGP neighbor."
2004
+ end
2005
+ optparse.parse!(args)
2006
+ connect(options)
2007
+ if args.count < 1
2008
+ print_error Morpheus::Terminal.angry_prompt
2009
+ puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
2010
+ return 1
2011
+ end
2012
+
2013
+ router = find_router(args[0])
2014
+
2015
+ if router.nil?
2016
+ return 1
2017
+ end
2018
+
2019
+ if !router['type']['hasNat']
2020
+ print_red_alert "BGP not supported for #{router['type']['name']}"
2021
+ return 1
2022
+ end
2023
+
2024
+ if options[:payload]
2025
+ payload = options[:payload]
2026
+ else
2027
+ option_types = router['type']['bgpNeighborOptionTypes'].sort_by {|it| it['displayOrder']}
2028
+
2029
+ # prompt options
2030
+ option_result = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options].deep_merge({:context_map => {'bgpNeighbor' => ''}}), @api_client, {'networkRouterId' => router['id']}, nil, true)
2031
+ payload = {'networkRouterBgpNeighbor' => params.deep_merge(option_result)}
2032
+ end
2033
+
2034
+ @network_routers_interface.setopts(options)
2035
+ if options[:dry_run]
2036
+ print_dry_run @network_routers_interface.dry.create_bgp_neighbor(router['id'], payload)
2037
+ return
2038
+ end
2039
+
2040
+ json_response = @network_routers_interface.create_bgp_neighbor(router['id'], payload)
2041
+ render_response(json_response, options, 'networkRouterBgpNeighbor') do
2042
+ print_green_success "\nAdded Network Router BGP neighbor #{json_response['id']}\n"
2043
+ _bgp_neighbors(router['id'], options)
2044
+ end
2045
+ end
2046
+
2047
+ def update_bgp_neighbor(args)
2048
+ options = {:options=>{}}
2049
+ params = {}
2050
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
2051
+ opts.banner = subcommand_usage("[router] [BGP neighbor]")
2052
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
2053
+ opts.footer = "Update a network router BGP neighbor.\n" +
2054
+ "[router] is required. This is the name or id of an existing network router.\n" +
2055
+ "[BGP neighbor] is required. This is the id of an existing network router BGP neighbor."
2056
+ end
2057
+ optparse.parse!(args)
2058
+ if args.count != 2
2059
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
2060
+ end
2061
+ connect(options)
2062
+
2063
+ router = find_router(args[0])
2064
+
2065
+ if router.nil?
2066
+ return 1
2067
+ end
2068
+
2069
+ if !router['type']['hasBgp']
2070
+ print_red_alert "BGP not supported for #{router['type']['name']}"
2071
+ return 1
2072
+ end
2073
+
2074
+ bgp_neighbor = router['bgpNeighbors'] ? router['bgpNeighbors'].find {|it| it['id'] == args[1].to_i} : nil
2075
+
2076
+ if !bgp_neighbor
2077
+ print_red_alert "BGP neighbor #{args[1]} not found for router #{router['name']}"
2078
+ exit 1
2079
+ end
2080
+
2081
+ payload = parse_payload(options) || {'networkRouterBgpNeighbor' => params}
2082
+ payload['networkRouterBgpNeighbor'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options] && !payload['networkRouterBgpNeighbor'].nil?
2083
+
2084
+ if payload['networkRouterBgpNeighbor'].empty?
2085
+ option_types = router['type']['bgpNeighborOptionTypes'].sort_by {|it| it['displayOrder']}
2086
+ print_green_success "Nothing to update"
2087
+ println cyan
2088
+ print Morpheus::Cli::OptionTypes.display_option_types_help(
2089
+ option_types,
2090
+ {:include_context => true, :context_map => {'bgpNeighbor' => ''}, :color => cyan, :title => "Available BGP Neighbor Options"}
2091
+ )
2092
+ exit 1
2093
+ end
2094
+
2095
+ @network_routers_interface.setopts(options)
2096
+ if options[:dry_run]
2097
+ print_dry_run @network_routers_interface.dry.update_bgp_neighbor(router['id'], bgp_neighbor['id'], payload)
2098
+ return
2099
+ end
2100
+
2101
+ json_response = @network_routers_interface.update_bgp_neighbor(router['id'], bgp_neighbor['id'], payload)
2102
+ render_response(json_response, options, 'networkRouterBgpNeighbor') do
2103
+ print_green_success "\nUpdated Network Router BGP Neighbor #{bgp_neighbor['id']}\n"
2104
+ _bgp_neighbors(router['id'], options)
2105
+ end
2106
+ end
2107
+
2108
+ def remove_bgp_neighbor(args)
2109
+ options = {}
2110
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
2111
+ opts.banner = subcommand_usage("[router] [BGP neighbor]")
2112
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
2113
+ opts.footer = "Delete a network router BGP neighbor.\n" +
2114
+ "[router] is required. This is the name or id of an existing network router."
2115
+ "[BGP neighbor] is required. This is the id of an existing network router BGP neighbor."
2116
+ end
2117
+ optparse.parse!(args)
2118
+ if args.count != 2
2119
+ raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args}\n#{optparse}"
2120
+ end
2121
+ connect(options)
2122
+
2123
+ router = find_router(args[0])
2124
+ return if !router
2125
+
2126
+ if !router['type']['hasBgp']
2127
+ print_red_alert "BGP not supported for #{router['type']['name']}"
2128
+ return 1
2129
+ end
2130
+
2131
+ bgp_neighbor = router['bgpNeighbors'] ? router['bgpNeighbors'].find {|it| it['id'] == args[1].to_i} : nil
2132
+
2133
+ if !bgp_neighbor
2134
+ print_red_alert "BGP neighbor #{args[1]} not found for router #{router['name']}"
2135
+ exit 1
2136
+ end
2137
+
2138
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the BGP neighbor '#{bgp_neighbor['id']}' from router '#{router['name']}'?", options)
2139
+ return 9, "aborted command"
2140
+ end
2141
+ @network_routers_interface.setopts(options)
2142
+ if options[:dry_run]
2143
+ print_dry_run @network_routers_interface.dry.destroy_bgp_neighbor(router['id'], bgp_neighbor['id'])
2144
+ return
2145
+ end
2146
+ json_response = @network_routers_interface.destroy_bgp_neighbor(router['id'], bgp_neighbor['id'])
2147
+ render_response(json_response, options, 'networkRouterBgpNeighbor') do
2148
+ print_green_success "\nDeleted Network Router BGP Neighbor #{bgp_neighbor['id']}\n"
2149
+ _bgp_neighbors(router['id'], options)
2150
+ end
2151
+ end
2152
+
1890
2153
  def types(args)
1891
2154
  options = {}
1892
2155
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -1989,7 +2252,7 @@ class Morpheus::Cli::NetworkRoutersCommand
1989
2252
  }
1990
2253
  print_description_list(description_cols, router_type)
1991
2254
 
1992
- {'optionTypes' => 'Router', 'ruleOptionTypes' => 'Firewall Rule', 'ruleGroupOptionTypes' => 'Firewall Rule Group', 'natOptionTypes' => 'NAT'}.each_pair do |field, title|
2255
+ {'optionTypes' => 'Router', 'ruleOptionTypes' => 'Firewall Rule', 'ruleGroupOptionTypes' => 'Firewall Rule Group', 'natOptionTypes' => 'NAT', 'bgpNeighborOptionTypes' => 'BGP Neighbor'}.each_pair do |field, title|
1993
2256
  if !router_type[field].nil? && router_type[field].count > 0
1994
2257
  println cyan
1995
2258
  print Morpheus::Cli::OptionTypes.display_option_types_help(
@@ -2187,6 +2450,27 @@ class Morpheus::Cli::NetworkRoutersCommand
2187
2450
  end
2188
2451
  end
2189
2452
 
2453
+ def print_bgp_neighbors(router)
2454
+ if router['type']['hasBgp']
2455
+ if router['bgpNeighbors'].count > 0
2456
+ rows = router['bgpNeighbors'].sort_by {|it| it['id']}.collect do |it|
2457
+ {
2458
+ id: it['id'],
2459
+ ip_address: it['ipAddress'],
2460
+ bfd_enabled: it['bfdEnabled'],
2461
+ remote_as: it['remoteAs'],
2462
+ route_filtering_out: it['routeFilteringOut'],
2463
+ route_filtering_in: it['routeFilteringIn'],
2464
+ allow_as_in: it['allowAsIn']
2465
+ }
2466
+ end
2467
+ puts as_pretty_table(rows, [:id, :ip_address, :bfd_enabled, :remote_as, :route_filtering_out, :route_filtering_in, :allow_as_in])
2468
+ else
2469
+ println "No BGP Neighbors\n"
2470
+ end
2471
+ end
2472
+ end
2473
+
2190
2474
  def format_router_status(router, return_color = cyan)
2191
2475
  status = router['status']
2192
2476
  color = white