Coverage for birdplan/plugins/cmdline/configure.py: 93%
60 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-23 03:27 +0000
1#
2# SPDX-License-Identifier: GPL-3.0-or-later
3#
4# Copyright (c) 2019-2024, 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 "birdplan configure"."""
22import argparse
23import grp
24import os
25import pwd
26from typing import Any, Dict, Optional
28from ...cmdline import BIRD_CONFIG_FILE, BirdPlanCommandLine, BirdPlanCommandlineResult
29from ...exceptions import BirdPlanError
30from .cmdline_plugin import BirdPlanCmdlinePluginBase
32__all__ = ["BirdPlanCmdlineConfigure"]
35class BirdPlanCmdlineConfigure(BirdPlanCmdlinePluginBase):
36 """BirdPlan "configure" command."""
38 # Output config file
39 _config_filename: Optional[str]
41 def __init__(self) -> None:
42 """Initialize object."""
44 super().__init__()
46 # Plugin setup
47 self.plugin_description = "birdplan configure"
48 self.plugin_order = 10
50 self._config_filename = None
52 def register_parsers(self, args: Dict[str, Any]) -> None:
53 """
54 Register commandline parsers.
56 Parameters
57 ----------
58 args : Dict[str, Any]
59 Method argument(s).
61 """
63 root_parser = args["root_parser"]
65 # CMD: configure
66 subparser = root_parser.add_parser("configure", help="Create BIRD configuration")
68 subparser.add_argument(
69 "--action",
70 action="store_const",
71 const="configure",
72 default="configure",
73 help=argparse.SUPPRESS,
74 )
76 # Output filename
77 subparser.add_argument(
78 "-o",
79 "--output-file",
80 nargs=1,
81 metavar="BIRD_CONFIG_FILE",
82 default=[BIRD_CONFIG_FILE],
83 help=f"BIRD config file to output, using '-' will output to stdout (default: {BIRD_CONFIG_FILE})",
84 )
86 # Ignore IRR changes
87 subparser.add_argument(
88 "--ignore-irr-changes", action="store_true", default=False, help="Ignore IRR changes between last run and this run"
89 )
91 # Ignore PeeringDB changes
92 subparser.add_argument(
93 "--ignore-peeringdb-changes",
94 action="store_true",
95 default=False,
96 help="Ignore PeeringDB changes between last run and this run",
97 )
99 # Use last cached data
100 subparser.add_argument(
101 "--use-cached",
102 action="store_true",
103 default=False,
104 help="Use cached IRR and PeeringDB data instead of doing network requests",
105 )
107 # Set our internal subparser property
108 self._subparser = subparser
109 self._subparsers = None
111 def cmd_configure(self, args: Any) -> Any:
112 """
113 Commandline handler for "configure" action.
115 Parameters
116 ----------
117 args : Dict[str, Any]
118 Method argument(s).
120 """
122 cmdline: BirdPlanCommandLine = args["cmdline"]
124 # Load BirdPlan configuration
125 cmdline.birdplan_load_config(
126 ignore_irr_changes=cmdline.args.ignore_irr_changes,
127 ignore_peeringdb_changes=cmdline.args.ignore_peeringdb_changes,
128 use_cached=cmdline.args.use_cached,
129 )
130 # Generate BIRD configuration
131 bird_config = cmdline.birdplan.configure()
133 # Commit BirdPlan state
134 cmdline.birdplan_commit_state()
136 # Save the output filename
137 self.config_filename = cmdline.args.output_file[0]
139 # If we're outputting to file, write it here
140 if self.config_filename and self.config_filename != "-":
141 self._write_config_file(bird_config)
142 return BirdPlanCommandlineResult(bird_config, has_console_output=False)
144 return BirdPlanCommandlineResult(bird_config)
146 def _write_config_file(self, data: Any) -> None:
147 """
148 Write out configuration file with data.
150 Parameters
151 ----------
152 data : str
153 Bird configuration
155 """
157 if not self.config_filename:
158 raise RuntimeError("Attribute 'config_filename' must be set")
160 # Get birdplan user id
161 try:
162 birdplan_uid = pwd.getpwnam("birdplan").pw_uid
163 except KeyError:
164 birdplan_uid = -1
166 # Get bird group id
167 try:
168 bird_gid = grp.getgrnam("bird").gr_gid
169 except KeyError:
170 bird_gid = None
172 # Write out config file
173 try:
174 fd = os.open(self.config_filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o640)
175 # If we have a bird group, set it
176 if bird_gid:
177 os.fchown(fd, birdplan_uid, bird_gid)
178 # Write out config
179 with os.fdopen(fd, "w") as config_file:
180 config_file.write(data)
181 except OSError as err: # pragma: no cover
182 raise BirdPlanError(f"Failed to open '{self.config_filename}' for writing: {err}") from None
184 @property
185 def config_filename(self) -> Optional[str]:
186 """Config file name to write out."""
187 return self._config_filename
189 @config_filename.setter
190 def config_filename(self, config_filename: str) -> None:
191 """Config file name to write out."""
192 self._config_filename = config_filename