Skip to content

Commit 6f68c42

Browse files
committed
adds all new config parsing to include env vars bb-Ricardo#227
1 parent 76e1ac5 commit 6f68c42

30 files changed

+2686
-1223
lines changed

README.md

+89-8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ This ensures stale objects are removed from NetBox keeping an accurate current s
3838
* pyvmomi==7.0.3
3939
* aiodns==2.0.0
4040
* setuptools>=62.00.0
41+
* pyyaml==6.0
4142

4243
### Environment
4344
* NetBox >= 2.9
@@ -113,8 +114,8 @@ Run the containerized application in a kubernetes cluster
113114

114115
```shell
115116
docker build -t netbox-vsphere-sync .
116-
docker image tag netbox-vsphere-sync your-registry.host/netbox-vsphere-sync:v1.2.0
117-
docker image push your-registry.host/netbox-vsphere-sync:v1.2.0
117+
docker image tag netbox-vsphere-sync your-registry.host/netbox-vsphere-sync:latest
118+
docker image push your-registry.host/netbox-vsphere-sync:latest
118119

119120
kubectl create secret generic netbox-vsphere-sync --from-file=settings.ini
120121
kubectl apply -f netbox-vsphere-sync-cronjob.yaml
@@ -132,20 +133,22 @@ A short description can be found [here](https://netbox.readthedocs.io/en/stable/
132133
# Running the script
133134

134135
```
135-
usage: netbox-sync.py [-h] [-c settings.ini]
136+
usage: netbox-sync.py [-h] [-c settings.ini [settings.ini ...]] [-g]
136137
[-l {DEBUG3,DEBUG2,DEBUG,INFO,WARNING,ERROR}] [-n] [-p]
137138
138139
Sync objects from various sources to NetBox
139140
140141
Version: 1.3.0 (2022-09-06)
141142
Project URL: https://github.com/bb-ricardo/netbox-sync
142143
143-
optional arguments:
144+
options:
144145
-h, --help show this help message and exit
145-
-c settings.ini, --config settings.ini
146+
-c settings.ini [settings.ini ...], --config settings.ini [settings.ini ...]
146147
points to the config file to read config data from
147148
which is not installed under the default path
148149
'./settings.ini'
150+
-g, --generate_config
151+
generates default config file.
149152
-l {DEBUG3,DEBUG2,DEBUG,INFO,WARNING,ERROR}, --log_level {DEBUG3,DEBUG2,DEBUG,INFO,WARNING,ERROR}
150153
set log level (overrides config)
151154
-n, --dry_run Operate as usual but don't change anything in NetBox.
@@ -160,9 +163,87 @@ optional arguments:
160163
It is recommended to set log level to `DEBUG2` this way the program should tell you what is happening and why.
161164
Also use the dry run option `-n` at the beginning to avoid changes directly in NetBox.
162165

163-
## Setup
164-
Copy the [settings-example.ini](https://github.com/bb-Ricardo/netbox-sync/blob/main/settings-example.ini) sample settings file to `settings.ini`.
165-
All options are described in the example file.
166+
## Configuration
167+
There are two ways to define configuration. Any combination of config file(s) and environment variables is possible.
168+
* config files (the [default config](https://github.com/bb-Ricardo/netbox-sync/blob/main/settings-example.ini) file name is set to `./settings.ini`.)
169+
* environment variables
170+
171+
The config from the environment variables will have precedence over the config file definitions.
172+
173+
### Config files
174+
Following config file types are supported:
175+
* ini
176+
* yaml
177+
178+
There is also more than one config file permitted. Example (config file names are also just examples):
179+
```bash
180+
/opt/netbox-sync/netbox-sync.py -c common.ini all-sources.yaml additional-config.yaml
181+
```
182+
183+
All files are parsed in order of the definition and options will overwrite the same options if defined in a
184+
previous config file.
185+
186+
To get config file examples which include descriptions and all default values, the `-g` can be used:
187+
```bash
188+
# this will create an ini example
189+
/opt/netbox-sync/netbox-sync.py -g -c settings-example.ini
190+
191+
# and this will create an example config file in yaml format
192+
/opt/netbox-sync/netbox-sync.py -g -c settings-example.yaml
193+
```
194+
195+
### Environment variables
196+
Each setting which can be defined in a config file can also be defined using an environment variable.
197+
198+
The prefix for all environment variables to be used in netbox-sync is: `NBS`
199+
200+
For configuration in the `common` and `netbox` section a variable is defined like this
201+
```
202+
<PREFIX>_<SECTION_NAME>_<CONFIG_OPTION_KEY>=value
203+
```
204+
205+
Following example represents the same configuration:
206+
```yaml
207+
# yaml config example
208+
common:
209+
log_level: DEBUG2
210+
netbox:
211+
host_fqdn: netbox-host.example.com
212+
prune_enabled: true
213+
```
214+
```bash
215+
# this variable definition is equal to the yaml config sample above
216+
NBS_COMMON_LOG_LEVEL="DEBUG2"
217+
NBS_netbox_host_fqdn="netbox-host.example.com"
218+
NBS_NETBOX_PRUNE_ENABLED="true"
219+
```
220+
221+
This way it is possible to expose for example the `NBS_NETBOX_API_KEY` only via an env variable.
222+
223+
The config definitions for `sources` need to be defined using an index. Following conditions apply:
224+
* a single source needs to use the same index
225+
* the index can be number or a name (but contain any special characters to support env var parsing)
226+
* the source needs to be named with `_NAME` variable
227+
228+
Example of defining a source with config and environment variables.
229+
```ini
230+
; example for a source
231+
[source/example-vcenter]
232+
enabled = True
233+
type = vmware
234+
host_fqdn = vcenter.example.com
235+
username = vcenter-readonly
236+
```
237+
```bash
238+
# define the password on command line
239+
# here we use '1' as index
240+
NBS_SOURCE_1_NAME="example-vcenter"
241+
NBS_SOURCE_1_PASSWORD="super-secret-and-not-saved-to-the-config-file"
242+
NBS_SOURCE_1_custom_dns_servers="10.0.23.23, 10.0.42.42"
243+
```
244+
245+
Even to just define one source variable like `NBS_SOURCE_1_PASSWORD` the `NBS_SOURCE_1_NAME` needs to be defined as
246+
to associate to the according source definition.
166247

167248
## Cron job
168249
In Order to sync all items regularly you can add a cron job like this one

module/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@
66
# This work is licensed under the terms of the MIT license.
77
# For a copy, see file LICENSE.txt included in this
88
# repository or visit: <https://opensource.org/licenses/MIT>.
9+
10+
__version__ = "1.3.0"
11+
__version_date__ = "2022-09-06"
12+
__author__ = "Ricardo Bartels <[email protected]>"
13+
__description__ = "NetBox Sync"
14+
__license__ = "MIT"
15+
__url__ = "https://github.com/bb-ricardo/netbox-sync"

module/common/cli_parser.py

+23-18
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,40 @@
1212
from argparse import ArgumentParser, RawDescriptionHelpFormatter
1313

1414
from module.common.logging import valid_log_levels
15+
from module.config import default_config_file_path
16+
from module import __version__, __version_date__, __url__
1517

1618

17-
def parse_command_line(version=None, self_description=None, version_date=None, url=None, default_config_file_path=None):
19+
def parse_command_line(self_description=None):
1820
"""
1921
parse command line arguments, also add current version and version date to description
2022
2123
Parameters
2224
----------
23-
version: str
24-
version of this program
2525
self_description: str
2626
short self description of this program
27-
version_date: str
28-
release date of this version
29-
url: str
30-
project url
31-
default_config_file_path: str
32-
path to default config file
3327
3428
Returns
3529
-------
3630
ArgumentParser object: with parsed command line arguments
3731
"""
3832

3933
# define command line options
40-
description = f"{self_description}\nVersion: {version} ({version_date})\nProject URL: {url}"
34+
description = f"{self_description}\nVersion: {__version__} ({__version_date__})\nProject URL: {__url__}"
4135

4236
parser = ArgumentParser(
4337
description=description,
4438
formatter_class=RawDescriptionHelpFormatter)
4539

46-
parser.add_argument("-c", "--config", default=default_config_file_path, dest="config_file",
47-
help="points to the config file to read config data from " +
48-
"which is not installed under the default path '" +
49-
default_config_file_path + "'",
50-
metavar="settings.ini")
40+
parser.add_argument("-c", "--config", default=[], dest="config_files", nargs='+',
41+
help=f"points to the config file to read config data from which is not installed "
42+
f"under the default path '{default_config_file_path}'",
43+
metavar=os.path.basename(default_config_file_path))
5144

52-
parser.add_argument("-l", "--log_level", choices=valid_log_levels, dest="log_level",
45+
parser.add_argument("-g", "--generate_config", action="store_true",
46+
help="generates default config file.")
47+
48+
parser.add_argument("-l", "--log_level", choices=valid_log_levels,
5349
help="set log level (overrides config)")
5450

5551
parser.add_argument("-n", "--dry_run", action="store_true",
@@ -63,8 +59,17 @@ def parse_command_line(version=None, self_description=None, version_date=None, u
6359
args = parser.parse_args()
6460

6561
# fix supplied config file path
66-
if args.config_file != default_config_file_path and args.config_file[0] != os.sep:
67-
args.config_file = os.path.realpath(os.getcwd() + os.sep + args.config_file)
62+
fixed_config_files = list()
63+
for config_file in args.config_files:
64+
65+
if len(config_file) == 0:
66+
continue
67+
68+
if config_file != default_config_file_path and config_file[0] != os.sep:
69+
config_file = os.path.realpath(os.getcwd() + os.sep + config_file)
70+
fixed_config_files.append(config_file)
71+
72+
args.config_files = fixed_config_files
6873

6974
return args
7075

module/common/config.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) 2020 - 2022 Ricardo Bartels. All rights reserved.
3+
#
4+
# netbox-sync.py
5+
#
6+
# This work is licensed under the terms of the MIT license.
7+
# For a copy, see file LICENSE.txt included in this
8+
# repository or visit: <https://opensource.org/licenses/MIT>.
9+
10+
11+
from module.config.option import ConfigOption
12+
from module.config.base import ConfigBase
13+
from module.config import common_config_section_name
14+
from module.common.logging import log_file_max_rotation, log_file_max_size_in_mb
15+
16+
17+
class CommonConfig(ConfigBase):
18+
"""Controls the parameters for logging
19+
"""
20+
21+
section_name = common_config_section_name
22+
23+
def __init__(self):
24+
self.options = [
25+
ConfigOption("log_level",
26+
str,
27+
description="""\
28+
Logs will always be printed to stdout/stderr.
29+
Logging can be set to following log levels:
30+
ERROR: Fatal Errors which stops regular a run
31+
WARNING: Warning messages won't stop the syncing process but mostly worth
32+
to have a look at.
33+
INFO: Information about objects that will be create/updated/deleted in NetBox
34+
DEBUG: Will log information about retrieved information, changes in internal
35+
data structure and parsed config
36+
DEBUG2: Will also log information about how/why data is parsed or skipped.
37+
DEBUG3: Logs all source and NetBox queries/results to stdout. Very useful for
38+
troubleshooting, but will log any sensitive data contained within a query.
39+
""",
40+
default_value="INFO"),
41+
42+
ConfigOption("log_to_file",
43+
bool,
44+
description="""Enabling this options will write all
45+
logs to a log file defined in 'log_file'
46+
""",
47+
default_value=False),
48+
49+
ConfigOption("log_file",
50+
str,
51+
description=f"""Destination of the log file if "log_to_file" is enabled.
52+
Log file will be rotated maximum {log_file_max_rotation} times once
53+
the log file reaches size of {log_file_max_size_in_mb} MB
54+
""",
55+
default_value="log/netbox_sync.log")
56+
]
57+
58+
super().__init__()

0 commit comments

Comments
 (0)