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

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/>. 

18 

19"""BirdPlan commandline options for BGP peer summary.""" 

20 

21import argparse 

22import io 

23from typing import TYPE_CHECKING, Any 

24 

25from .....cmdline import BirdPlanCommandLine, BirdPlanCommandlineResult 

26from .....console.colors import colored 

27from .....exceptions import BirdPlanUsageError 

28from ...cmdline_plugin import BirdPlanCmdlinePluginBase 

29 

30if TYPE_CHECKING: 

31 from ..... import BirdPlanBGPPeerSummary 

32 

33__all__ = ["BirdPlanCmdlineBGPPeerShow"] 

34 

35 

36class BirdPlanCmdlineBGPPeerShowResult(BirdPlanCommandlineResult): 

37 """BirdPlan BGP peer show result.""" 

38 

39 def as_text(self) -> str: 

40 """ 

41 Return data in text format. 

42 

43 Returns 

44 ------- 

45 str 

46 Return data in text format. 

47 

48 """ 

49 

50 ob = io.StringIO() 

51 

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

64 

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"] 

70 

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"] 

75 

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

89 

90 # Center some columns 

91 ipv_out = f"{ipv[:8]}".center(8) 

92 

93 # Write out info line 

94 ob.write(f"| {peer_name[:32]:<32} | {ipv_out} | {state_out} | {since[:19]:<19} | {info_out} |\n") 

95 

96 # Write out footer 

97 ob.write(f"+{'=' * 130}+\n") 

98 

99 return ob.getvalue() 

100 

101 

102class BirdPlanCmdlineBGPPeerShow(BirdPlanCmdlinePluginBase): 

103 """BirdPlan "bgp peer summary" command.""" 

104 

105 def __init__(self) -> None: 

106 """Initialize object.""" 

107 

108 super().__init__() 

109 

110 # Plugin setup 

111 self.plugin_description = "birdplan bgp peer summary" 

112 self.plugin_order = 20 

113 

114 def register_parsers(self, args: dict[str, Any]) -> None: 

115 """ 

116 Register commandline parsers. 

117 

118 Parameters 

119 ---------- 

120 args : Dict[str, Any] 

121 Method argument(s). 

122 

123 """ 

124 

125 plugins = args["plugins"] 

126 

127 parent_subparsers = plugins.call_plugin("birdplan.plugins.cmdline.bgp.peer", "get_subparsers", {}) 

128 

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 ) 

138 

139 subparser.add_argument( 

140 "--only", 

141 nargs=1, 

142 default=None, 

143 metavar="ONLY", 

144 help="Limit output to: AS<NUMBER>", 

145 ) 

146 

147 # Set our internal subparser property 

148 self._subparser = subparser 

149 self._subparsers = None 

150 

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. 

154 

155 Parameters 

156 ---------- 

157 args : Dict[str, Any] 

158 Method argument(s). 

159 

160 """ 

161 

162 if not self._subparser: # pragma: no cover 

163 raise RuntimeError 

164 

165 cmdline: BirdPlanCommandLine = args["cmdline"] 

166 

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] 

176 

177 # Grab Bird control socket 

178 bird_socket = cmdline.args.bird_socket[0] 

179 

180 # Suppress info output 

181 cmdline.birdplan.birdconf.birdconfig_globals.suppress_info = True 

182 

183 # Load BirdPlan configuration using the cache 

184 cmdline.birdplan_load_config(ignore_irr_changes=True, ignore_peeringdb_changes=True, use_cached=True) 

185 

186 # Grab peer list 

187 peer_list: BirdPlanBGPPeerSummary = cmdline.birdplan.state_bgp_peer_summary(bird_socket=bird_socket) 

188 

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:])} 

192 

193 return BirdPlanCmdlineBGPPeerShowResult(peer_list)