Coverage for src/birdplan/bird_config/sections/protocols/ospf/area/__init__.py: 97%

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"""BIRD OSPF area configuration.""" 

20 

21# pylint: disable=too-many-lines 

22 

23from typing import Any 

24 

25from ......exceptions import BirdPlanError 

26from .....globals import BirdConfigGlobals 

27from ....bird_attributes import SectionBirdAttributes 

28from ....constants import SectionConstants 

29from ....functions import SectionFunctions 

30from ....tables import SectionTables 

31from ...base import SectionProtocolBase 

32from ..ospf_attributes import OSPFAttributes 

33from .area_attributes import OSPFAreaAttributes 

34from .interface import ProtocolOSPFAreaInterface 

35from .ospf_area_types import OSPFAreaConfig 

36 

37__all__ = ["ProtocolOSPFArea"] 

38 

39 

40OSPFAreaInterfaceConfig = dict[str, Any] 

41OSPFAreaInterfaces = dict[str, ProtocolOSPFAreaInterface] 

42 

43 

44class ProtocolOSPFArea(SectionProtocolBase): # pylint: disable=too-many-public-methods 

45 """BIRD OSPF area configuration.""" 

46 

47 # OSPF attributes 

48 _ospf_attributes: OSPFAttributes 

49 

50 # OSPF area attributes 

51 _area_attributes: OSPFAreaAttributes 

52 

53 # OSPF interfaces belonging to this area 

54 _interfaces: OSPFAreaInterfaces 

55 

56 def __init__( # noqa: PLR0913,PLR0917 

57 self, 

58 birdconfig_globals: BirdConfigGlobals, 

59 birdattributes: SectionBirdAttributes, 

60 constants: SectionConstants, 

61 functions: SectionFunctions, 

62 tables: SectionTables, 

63 ospf_attributes: OSPFAttributes, 

64 area_name: str, 

65 area_config: OSPFAreaConfig, 

66 ) -> None: 

67 """Initialize the object.""" 

68 super().__init__(birdconfig_globals, birdattributes, constants, functions, tables) 

69 

70 # Setup OSPF attributes 

71 self._ospf_attributes = ospf_attributes 

72 

73 # Setup OSPF area attributes 

74 self._area_attributes = OSPFAreaAttributes() 

75 

76 # Interfaces 

77 self._interfaces = {} 

78 

79 # Set area name 

80 self.name = str(area_name) 

81 

82 if area_config: 

83 raise BirdPlanError("THIS SHOULD NOT HAPPEN UNTIL WE HAVE AREA CONFIG") 

84 

85 def configure(self) -> None: 

86 """Configure the OSPF area.""" 

87 

88 # Don't re-render the configuration, we're called twice for v4 and V6 

89 if self.conf.items: 

90 return 

91 

92 super().configure() 

93 

94 # Blank the OSPF area state 

95 if "ospf" not in self.birdconfig_globals.state: 

96 self.birdconfig_globals.state["ospf"] = {} 

97 if "areas" not in self.birdconfig_globals.state["ospf"]: 

98 self.birdconfig_globals.state["ospf"]["areas"] = {} 

99 if self.name not in self.birdconfig_globals.state["ospf"]["areas"]: 

100 self.birdconfig_globals.state["ospf"]["areas"][self.name] = {} 

101 if "interfaces" not in self.birdconfig_globals.state["ospf"]["areas"][self.name]: 

102 self.birdconfig_globals.state["ospf"]["areas"][self.name]["interfaces"] = {} 

103 

104 # Add area config block 

105 self.conf.add(f" area {self.name} {{") 

106 # Add interfaces 

107 for _, interface in sorted(self.interfaces.items()): 

108 self.conf.add(interface) 

109 # Close area config block 

110 self.conf.add(" };") 

111 

112 def add_interface(self, interface_name: str, interface_config: OSPFAreaConfig) -> ProtocolOSPFAreaInterface: 

113 """Add interface to OSPF.""" 

114 

115 # Make sure area interface doesn't exist 

116 if interface_name in self.interfaces: 

117 raise BirdPlanError(f"OSPF area '{self.name}'' interface '{interface_name}' already exists") 

118 

119 # Create OSPF area interface object 

120 interface = ProtocolOSPFAreaInterface( 

121 self.birdconfig_globals, 

122 self.birdattributes, 

123 self.constants, 

124 self.functions, 

125 self.tables, 

126 self.area_attributes, 

127 interface_name, 

128 interface_config, 

129 ) 

130 

131 # Add interface to the area 

132 self.interfaces[interface_name] = interface 

133 

134 return interface 

135 

136 @property 

137 def area_attributes(self) -> OSPFAreaAttributes: 

138 """OSPF area attributes.""" 

139 return self._area_attributes 

140 

141 @property 

142 def name(self) -> str: 

143 """Area name.""" 

144 return self.area_attributes.name 

145 

146 @name.setter 

147 def name(self, name: str) -> None: 

148 """Area name.""" 

149 self.area_attributes.name = name 

150 

151 @property 

152 def interfaces(self) -> OSPFAreaInterfaces: 

153 """OSPF area interfaces.""" 

154 return self._interfaces