Coverage for src/birdplan/plugins/cmdline/ospf/summary.py: 48%

58 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 OSPF summary.""" 

20 

21import argparse 

22import io 

23from typing import Any 

24 

25from ....cmdline import BirdPlanCommandLine, BirdPlanCommandlineResult 

26from ....console.colors import colored 

27from ..cmdline_plugin import BirdPlanCmdlinePluginBase 

28 

29__all__ = ["BirdPlanCmdlineOSPFShow"] 

30 

31 

32class BirdPlanCmdlineOSPFShowResult(BirdPlanCommandlineResult): 

33 """BirdPlan OSPF summary result class.""" 

34 

35 def as_text(self) -> str: 

36 """ 

37 Return data as text. 

38 

39 Returns 

40 ------- 

41 str 

42 Data as text. 

43 

44 """ 

45 

46 ob = io.StringIO() 

47 

48 # Write out header 

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

50 ob.write(f"| {'OSPF Summary'.center(128)} |\n") 

51 ob.write(f"+{'-' * 34}+{'-' * 10}+{'-' * 10}+{'-' * 21}+{'-' * 51}+\n") 

52 ob.write( 

53 f"| {'Name'.center(32)} | {'Proto'.center(8)} | {'Status'.center(8)} | {'Since'.center(19)} | {'Info'.center(49)} |\n" 

54 ) 

55 ob.write(f"+{'-' * 34}+{'-' * 10}+{'-' * 10}+{'-' * 21}+{'-' * 51}+\n") 

56 

57 # Loop with each protocol 

58 for name, protocol_status in self.data.items(): 

59 ipv = "-" 

60 if name.endswith("4"): 

61 ipv = "ipv4" 

62 elif name.endswith("6"): 

63 ipv = "ipv6" 

64 # Start with plain strings with no color 

65 state: str = protocol_status["state"] 

66 info: str = protocol_status["info"] 

67 since: str = protocol_status["since"] 

68 

69 # NK - Update in peer_arg show too 

70 # Check how we're going to color entries based on their state and info 

71 state_out = f"{state[:8]}".center(8) 

72 info_out = f"{info[:49]}".center(49) 

73 if protocol_status["state"] == "down": 

74 state_out = colored(f"{state[:8]}".center(8), "red") 

75 if "info_extra" in protocol_status: 

76 info += " - " + protocol_status["info_extra"] 

77 info_out = colored(f"{info[:49]}".center(49), "red") 

78 elif protocol_status["state"] == "up": 

79 if protocol_status["info"] == "running": 

80 state_out = colored(f"{state[:8]}".center(8), "green") 

81 info_out = colored(f"{info[:49]}".center(49), "green") 

82 

83 # Center some columns 

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

85 

86 # Write out info line 

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

88 

89 # Write out footer 

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

91 

92 return ob.getvalue() 

93 

94 

95class BirdPlanCmdlineOSPFShow(BirdPlanCmdlinePluginBase): 

96 """BirdPlan "ospf summary" command.""" 

97 

98 def __init__(self) -> None: 

99 """Initialize object.""" 

100 

101 super().__init__() 

102 

103 # Plugin setup 

104 self.plugin_description = "birdplan ospf summary" 

105 self.plugin_order = 20 

106 

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

108 """ 

109 Register commandline parsers. 

110 

111 Parameters 

112 ---------- 

113 args : Dict[str, Any] 

114 Method argument(s). 

115 

116 """ 

117 

118 plugins = args["plugins"] 

119 

120 parent_subparsers = plugins.call_plugin("birdplan.plugins.cmdline.ospf", "get_subparsers", {}) 

121 

122 # CMD: ospf summary 

123 subparser = parent_subparsers.add_parser("summary", help="OSPF summary commands") 

124 subparser.add_argument( 

125 "--action", 

126 action="store_const", 

127 const="ospf_summary", 

128 default="ospf_summary", 

129 help=argparse.SUPPRESS, 

130 ) 

131 

132 # Set our internal subparser property 

133 self._subparser = subparser 

134 self._subparsers = None 

135 

136 def cmd_ospf_summary(self, args: dict[str, Any]) -> BirdPlanCmdlineOSPFShowResult: # pylint: disable=unused-argument 

137 """ 

138 Commandline handler for "ospf summary" action. 

139 

140 Parameters 

141 ---------- 

142 args : Dict[str, Any] 

143 Method argument(s). 

144 

145 """ 

146 

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

148 raise RuntimeError 

149 

150 cmdline: BirdPlanCommandLine = args["cmdline"] 

151 

152 # Grab Bird control socket 

153 bird_socket = cmdline.args.bird_socket[0] 

154 

155 # Suppress info output 

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

157 

158 # Load BirdPlan configuration using the cache 

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

160 

161 res = cmdline.birdplan.state_ospf_summary(bird_socket=bird_socket) 

162 

163 return BirdPlanCmdlineOSPFShowResult(res)