Coverage for src/birdplan/plugins/cmdline/bgp/peer/summary.py: 50%
66 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-25 07:38 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-25 07:38 +0000
1#
2# SPDX-License-Identifier: GPL-3.0-or-later
3#
4# Copyright (c) 2019-2025, AllWorldIT
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
19"""BirdPlan commandline options for BGP peer summary."""
21import argparse
22import io
23from typing import TYPE_CHECKING, Any
25from .....cmdline import BirdPlanCommandLine, BirdPlanCommandlineResult
26from .....console.colors import colored
27from .....exceptions import BirdPlanUsageError
28from ...cmdline_plugin import BirdPlanCmdlinePluginBase
30if TYPE_CHECKING:
31 from ..... import BirdPlanBGPPeerSummary
33__all__ = ["BirdPlanCmdlineBGPPeerShow"]
36class BirdPlanCmdlineBGPPeerShowResult(BirdPlanCommandlineResult):
37 """BirdPlan BGP peer show result."""
39 def as_text(self) -> str:
40 """
41 Return data in text format.
43 Returns
44 -------
45 str
46 Return data in text format.
48 """
50 ob = io.StringIO()
52 # Write out header
53 ob.write(f"+{'=' * 130}+\n")
54 ob.write(f"| {'BGP Peer Summary'.center(128)} |\n")
55 ob.write(f"+{'-' * 34}+{'-' * 10}+{'-' * 10}+{'-' * 21}+{'-' * 51}+\n")
56 ob.write(
57 f"| {'Peer Name'.center(32)} "
58 f"| {'Proto'.center(8)} "
59 f"| {'Status'.center(8)} "
60 f"| {'Since'.center(19)} "
61 f"| {'Info'.center(49)} |\n"
62 )
63 ob.write(f"+{'-' * 34}+{'-' * 10}+{'-' * 10}+{'-' * 21}+{'-' * 51}+\n")
65 # Loop with each protocol
66 for peer_name, peer in self.data.items():
67 # Loop with each family
68 for ipv, protocol in peer["protocols"].items():
69 protocol_status = protocol["status"]
71 # Start with plain strings with no color
72 state: str = protocol_status["state"]
73 info: str = protocol_status["info"]
74 since: str = protocol_status["since"]
76 # NK - Update in peer_arg show too
77 # Check how we're going to color entries based on their state and info
78 state_out = f"{state[:8]}".center(8)
79 info_out = f"{info[:49]}".center(49)
80 if protocol_status["state"] == "down":
81 state_out = colored(f"{state[:8]}".center(8), "red")
82 if "info_extra" in protocol_status:
83 info += " - " + protocol_status["info_extra"]
84 info_out = colored(f"{info[:49]}".center(49), "red")
85 elif protocol_status["state"] == "up":
86 if protocol_status["info"] == "established":
87 state_out = colored(f"{state[:8]}".center(8), "green")
88 info_out = colored(f"{info[:49]}".center(49), "green")
90 # Center some columns
91 ipv_out = f"{ipv[:8]}".center(8)
93 # Write out info line
94 ob.write(f"| {peer_name[:32]:<32} | {ipv_out} | {state_out} | {since[:19]:<19} | {info_out} |\n")
96 # Write out footer
97 ob.write(f"+{'=' * 130}+\n")
99 return ob.getvalue()
102class BirdPlanCmdlineBGPPeerShow(BirdPlanCmdlinePluginBase):
103 """BirdPlan "bgp peer summary" command."""
105 def __init__(self) -> None:
106 """Initialize object."""
108 super().__init__()
110 # Plugin setup
111 self.plugin_description = "birdplan bgp peer summary"
112 self.plugin_order = 20
114 def register_parsers(self, args: dict[str, Any]) -> None:
115 """
116 Register commandline parsers.
118 Parameters
119 ----------
120 args : Dict[str, Any]
121 Method argument(s).
123 """
125 plugins = args["plugins"]
127 parent_subparsers = plugins.call_plugin("birdplan.plugins.cmdline.bgp.peer", "get_subparsers", {})
129 # CMD: bgp peer summary
130 subparser = parent_subparsers.add_parser("summary", help="BGP peer summary commands")
131 subparser.add_argument(
132 "--action",
133 action="store_const",
134 const="bgp_peer_summary",
135 default="bgp_peer_summary",
136 help=argparse.SUPPRESS,
137 )
139 subparser.add_argument(
140 "--only",
141 nargs=1,
142 default=None,
143 metavar="ONLY",
144 help="Limit output to: AS<NUMBER>",
145 )
147 # Set our internal subparser property
148 self._subparser = subparser
149 self._subparsers = None
151 def cmd_bgp_peer_summary(self, args: dict[str, Any]) -> BirdPlanCmdlineBGPPeerShowResult: # pylint: disable=unused-argument
152 """
153 Commandline handler for "bgp peer summary" action.
155 Parameters
156 ----------
157 args : Dict[str, Any]
158 Method argument(s).
160 """
162 if not self._subparser: # pragma: no cover
163 raise RuntimeError
165 cmdline: BirdPlanCommandLine = args["cmdline"]
167 # Validate extra options
168 arg_only = None
169 if cmdline.args.only:
170 if cmdline.args.only[0][0:2] != "AS":
171 raise BirdPlanUsageError("Invalid value for --only, must be AS<NUMBER>")
172 if int(cmdline.args.only[0]) < 1:
173 raise BirdPlanUsageError("Invalid value for --only, must be AS<NUMBER>")
174 # Save the arg for later
175 arg_only = cmdline.args.only[0]
177 # Grab Bird control socket
178 bird_socket = cmdline.args.bird_socket[0]
180 # Suppress info output
181 cmdline.birdplan.birdconf.birdconfig_globals.suppress_info = True
183 # Load BirdPlan configuration using the cache
184 cmdline.birdplan_load_config(ignore_irr_changes=True, ignore_peeringdb_changes=True, use_cached=True)
186 # Grab peer list
187 peer_list: BirdPlanBGPPeerSummary = cmdline.birdplan.state_bgp_peer_summary(bird_socket=bird_socket)
189 # Check if we're filtering on a specific AS
190 if arg_only and arg_only[0:2] == "AS":
191 peer_list = {k: v for k, v in peer_list.items() if v["asn"] == int(arg_only[2:])}
193 return BirdPlanCmdlineBGPPeerShowResult(peer_list)