Skip to content

Commit d75e460

Browse files
committed
initial commit
Signed-off-by: hwassman <[email protected]>
1 parent d0d6183 commit d75e460

File tree

3 files changed

+193
-44
lines changed

3 files changed

+193
-44
lines changed

source/confParser.py

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ def checkCAsettings(args):
9393

9494
def getSettings(argv):
9595
settings = {}
96-
defaults = ConfigManager().defaults
9796
args, msg = parse_cmd_args(argv)
97+
customFile = vars(args).get('configFile', None)
98+
defaults = ConfigManager(customFile).defaults
9899
if args and defaults:
99100
settings = merge_defaults_and_args(defaults, args)
100101
elif args:
101-
settings = args
102+
settings = vars(args)
102103
else:
103104
return None, msg
104105
# check application port
@@ -143,41 +144,25 @@ def merge_defaults_and_args(defaults, args):
143144
class ConfigManager(object, metaclass=Singleton):
144145
''' A singleton class managing the application configuration defaults '''
145146

146-
def __init__(self):
147-
self.__sectOptions = {}
147+
def __init__(self, custom_config_file=None):
148148
self.__defaults = {}
149-
self.configFiles = ['config.ini']
150-
151-
@property
152-
def options(self):
153-
if not self.__sectOptions:
154-
self.__sectOptions = self.reload()
155-
return self.__sectOptions
149+
self.customFile = custom_config_file
150+
self.templateFile = self.get_template_path()
156151

157152
@property
158153
def defaults(self):
159154
if not self.__defaults:
160155
self.__defaults = self.parse_defaults()
161156
return self.__defaults
162157

163-
def reload(self):
164-
options = {}
165-
self.__sectOptions = {}
166-
if self.configFiles:
167-
for config in self.configFiles:
168-
options.update(self.readConfigFile(config))
169-
return options
170-
171158
def readConfigFile(self, fileName):
172159
'''parse config file and store values in a dict {section:{ key: value}}'''
173160
options = {}
174-
dirname, filename = os.path.split(os.path.abspath(__file__))
175-
conf_file = os.path.join(dirname, fileName)
176-
if os.path.isfile(conf_file):
161+
if os.path.isfile(fileName):
177162
try:
178163
config = configparser.ConfigParser()
179164
config.optionxform = str
180-
config.read(conf_file)
165+
config.read(fileName)
181166
for sect in config.sections():
182167
options[sect] = {}
183168
for name, value in config.items(sect):
@@ -187,20 +172,48 @@ def readConfigFile(self, fileName):
187172
except Exception as e:
188173
print(f"cannot read config file {fileName} Exception {e}")
189174
else:
190-
print(f"cannot find config file {fileName} in {dirname}")
175+
print(f"cannot find config file {fileName}")
191176
return options
192177

178+
def get_template_path(self):
179+
'''parse config.ini to a simple key:value dict'''
180+
dirname, _ = os.path.split(os.path.abspath(__file__))
181+
return os.path.join(dirname, 'config.ini')
182+
183+
def parse_file(self, file):
184+
'''parse file to a simple key:value dict'''
185+
settings = {}
186+
section_names = set()
187+
sections = self.readConfigFile(file)
188+
if sections:
189+
section_names = set(sections.keys())
190+
for _, sect_values in sections.items():
191+
for name, value in sect_values.items():
192+
settings[name] = value
193+
return section_names, settings
194+
193195
def parse_defaults(self):
194-
'''parse all sections parameters to a simple key:value dict'''
195-
defaults = {}
196-
for sect_name, sect_values in self.options.items():
197-
for name, value in sect_values.items():
198-
defaults[name] = value
196+
"""Retuns a dictionary of parameter names and values parsed from config file
197+
198+
If no custom config file provided the values will be parsed from template
199+
file (.config.ini)
200+
"""
201+
202+
default_sections, defaults = self.parse_file(self.templateFile)
203+
if not self.customFile:
204+
return defaults
205+
206+
custom_sections, customs = self.parse_file(self.customFile)
207+
sect = default_sections.intersection(custom_sections)
208+
if not sect:
209+
return defaults
210+
211+
defaults.update(customs)
199212
return defaults
200213

201214

202215
class Password(argparse.Action):
203-
defaults = ConfigManager().defaults
216+
# defaults = ConfigManager().defaults
204217

205218
def __call__(self, parser, namespace, values, option_string):
206219
if values is None:
@@ -226,6 +239,8 @@ def parse_cmd_args(argv):
226239
parser.add_argument('-f', '--logFile', action="store", default=None,
227240
help='Name of the log file (Default from config.ini: zserver.log). If no log file name specified \
228241
all traces will be printed out directly on the command line')
242+
parser.add_argument('-F', '--configFile', action="store", default=None,
243+
help='Absolute path to the custom config file that should be used instead of the default config.ini file (optional)')
229244
parser.add_argument('-c', '--logLevel', action="store", type=int, default=None,
230245
help='log level. Available levels: 10 (DEBUG), 15 (MOREINFO), 20 (INFO), 30 (WARN), 40 (ERROR) (Default from config.ini: 15)')
231246
parser.add_argument('-e', '--prometheus', action="store", default=None,

tests/test_configManager.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,59 @@
1+
import os
12
from source.confParser import ConfigManager
23
from source.__version__ import __version__ as version
4+
from nose2.tools.decorators import with_setup
5+
6+
7+
def my_setup():
8+
global path, customConfigFile
9+
path = os.getcwd()
10+
customConfigFile = 'custom.ini'
311

412

513
def test_case01():
614
cm = ConfigManager()
715
result = cm.readConfigFile('config.ini')
816
assert isinstance(result, dict)
17+
if version < "8.0.7":
18+
assert len(result.keys()) > 0
19+
assert 'tls' in result.keys()
20+
else:
21+
assert len(result) == 0
922

1023

1124
def test_case02():
1225
cm = ConfigManager()
13-
result = cm.readConfigFile('config.ini')
26+
file = cm.get_template_path()
27+
result = cm.readConfigFile(file)
28+
assert isinstance(result, dict)
1429
assert len(result.keys()) > 0
30+
assert 'tls' in result.keys()
1531

1632

1733
def test_case03():
1834
cm = ConfigManager()
19-
result = cm.readConfigFile('config.ini')
20-
assert 'tls' in result.keys()
21-
22-
35+
if version < "8.0.7":
36+
result = cm.readConfigFile('config.ini')
37+
connection = result['connection']
38+
assert len(connection) > 0
39+
assert isinstance(connection, dict)
40+
assert len(connection) > 0
41+
if version < "8.0":
42+
assert 'port' in connection.keys()
43+
else:
44+
assert 'port' not in connection.keys()
45+
46+
47+
@with_setup(my_setup)
2348
def test_case04():
49+
customFile = os.path.join(path, "tests", "test_data", customConfigFile)
50+
print(customFile)
2451
cm = ConfigManager()
25-
result = cm.readConfigFile('config.ini')
26-
connection = result['connection']
27-
assert len(connection) > 0
28-
assert isinstance(connection, dict)
29-
assert len(connection) > 0
30-
if version < "8.0":
31-
assert 'port' in connection.keys()
32-
else:
33-
assert 'port' not in connection.keys()
52+
cm.customFile = customFile
53+
print(cm.__dict__)
54+
assert (cm.customFile == customFile)
55+
result = cm.readConfigFile(cm.customFile)
56+
assert 'tls' in result.keys()
3457

3558

3659
def test_case05():

tests/test_data/custom.ini

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
##################### OpenTSDB API Connection Defaults ########################
2+
[opentsdb_plugin]
3+
# Port number the bridge listening on for Grafana data requests over
4+
# OpentTSDB plugin
5+
#
6+
# 4242 - for HTTP connections
7+
# 8443 - for HTTPS connections
8+
# (Default: 4242)
9+
# port = 4242
10+
11+
##################### Prometheus Exporter API Connection Defaults #############
12+
[prometheues_exporter_plugin]
13+
# Port number the bridge listening on for Prometheus server requests;
14+
# prometheus = 9250
15+
16+
# By default, the original values from the platform will be exported alongside
17+
# the timestamps at which they were measured. This can slow down a ZIMON query
18+
# performance.
19+
# Set rawCounters to False to accelerate query execution time. Keep in mind that
20+
# in this case the exposed timestamps will represent the time at which the values
21+
# were added to a bucket.
22+
# Sensors including 'increasing counters' metric types will still run in
23+
# rawCounters mode.
24+
rawCounters = True
25+
26+
##################### API Protocol scheme #####################################
27+
[connection]
28+
# Protocol (http, https)
29+
protocol = http
30+
31+
##################### API Basic Authentication ################################
32+
[basic_auth]
33+
# Basic authentication is enabled by default.
34+
# It is recommended to leave Basic Authentication enabled, especially when
35+
# connecting via HTTP. The bridge will validate the username and password
36+
# from `Authorization` header of every incoming http request.
37+
enabled = True
38+
39+
# user name used for bridge api http/s basic authentication
40+
username = scale_admin
41+
42+
# Base64 encoded password string used for bridge api http/s basic authentication
43+
# Example string encoding via cli:
44+
# $ echo "MyVeryStrongPassw0rd!" |base64
45+
# TXlWZXJ5U3Ryb25nUGFzc3cwcmQhCg==
46+
#
47+
# password = TXlWZXJ5U3Ryb25nUGFzc3cwcmQhCg==
48+
#
49+
# alternatively you can store a Base64 encoded string in a file
50+
# and specify the file location as the basic authentication password, f.e:
51+
# password = /etc/bridge_auth/basic_scale-21
52+
53+
##################### API SSL OAuth ############################################
54+
[tls]
55+
# Directory path of tls key and cert file location
56+
# tlsKeyPath = /etc/bridge_ssl/certs
57+
58+
# Name of tls private key file
59+
# tlsKeyFile = privkey.pem
60+
61+
# Name of tls certificate file
62+
# tlsCertFile = cert.pem
63+
64+
65+
66+
##################### GPFS Server ###############################################
67+
[server]
68+
# The ip address to bind to, empty will bind to all interfaces
69+
server = localhost
70+
71+
# The https port to use
72+
serverPort = 9980
73+
74+
# The sleep time in seconds before attempting to get metaData from the server again.
75+
# This most likely the case if the query was sent to server before it did finish the
76+
# initial startup (maximum 3 attempts)
77+
retryDelay = 60
78+
79+
# The name of REST HTTPS API key name
80+
apiKeyName = scale_grafana
81+
82+
# The REST HTTPS API key value, f.e:
83+
# apiKeyValue = e40960c9-de0a-4c75-bc71-0bcae6db23b2
84+
#
85+
# alternatively you can store a string of 32 hexadecimal digits in a file
86+
# and specify the file location as the REST HTTPS API key value, f.e:
87+
# apiKeyValue = /etc/bridge_ssl/apikey_scale-21
88+
89+
# False or the path to the CA certificate to use.
90+
# On many Linux systems, certs can be found in /etc/ssl/certs.
91+
# In CNSA the service-ca certifcate must be used:
92+
# caCertPath = "/etc/ssl/certs/service-ca.crt"
93+
caCertPath = False
94+
95+
##################### GPFS Server data query settings ############################
96+
[query]
97+
# Use or not the historical data from disk (default: no)
98+
includeDiskData = no
99+
100+
##################### Logging ####################################################
101+
[logging]
102+
# Directory where the bridge can store logs
103+
logPath = /var/log/ibm_bridge_for_grafana
104+
105+
# log level 5 (TRACE) 10 (DEBUG), 15 (MOREINFO), 20 (INFO), 30 (WARN),
106+
# 40 (ERROR) (Default: 15)
107+
logLevel = 15
108+
109+
# Log file name (Default: zserver.log)
110+
# Comment out this setting, if you wish to print out the trace messages directly on the command line
111+
logFile = zserver.log

0 commit comments

Comments
 (0)