Skip to content

Commit f8a9687

Browse files
Merge branch 'develop' into issue_2993
2 parents e503b3b + 0d8da1c commit f8a9687

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#!/usr/bin/python3
2+
# reads the main app data from multiple csv files contained in a git repo
3+
# users will reside in ldap groups with standardized names
4+
# only the main responsible person per app is taken from the csv files
5+
# this does not use Tufin RLM any longer as a source
6+
# here app servers will only have ip addresses (no names)
7+
8+
# dependencies:
9+
# a) package python3-git must be installed
10+
# b) requires the following config items in /usr/local/orch/etc/secrets/customizingConfig.json
11+
12+
'''
13+
sample config file /usr/local/orch/etc/secrets/customizingConfig.json
14+
15+
{
16+
"gitRepoUrl": "github.domain.de/CMDB-export",
17+
"gitusername": "gituser1",
18+
"gitpassword": "xxx",
19+
"csvAllOwnerFiles": ["all-apps.csv", "all-infra-services.csv"],
20+
"csvAppServerFiles": ["app-servers.csv", "com-servers.csv"],
21+
"ldapPath": "CN={USERID},OU=Benutzer,DC=DOMAIN,DC=DE"
22+
}
23+
'''
24+
25+
from asyncio.log import logger
26+
import traceback
27+
import requests.packages
28+
import requests
29+
import json
30+
import sys
31+
import argparse
32+
import logging
33+
import os
34+
from pathlib import Path
35+
import git # apt install python3-git # or: pip install git
36+
import csv
37+
38+
39+
baseDir = "/usr/local/fworch/"
40+
baseDirEtc = baseDir + "etc/"
41+
repoTargetDir = baseDirEtc + "cmdb-repo"
42+
defaultConfigFileName = baseDirEtc + "secrets/customizingConfig.json"
43+
importSourceString = "tufinRlm" # change this to "cmdb-csv-export"? or will this break anything?
44+
45+
class ApiLoginFailed(Exception):
46+
"""Raised when login to API failed"""
47+
48+
def __init__(self, message="Login to API failed"):
49+
self.message = message
50+
super().__init__(self.message)
51+
52+
class ApiFailure(Exception):
53+
"""Raised for any other Api call exceptions"""
54+
55+
def __init__(self, message="There was an unclassified error while executing an API call"):
56+
self.message = message
57+
super().__init__(self.message)
58+
59+
class ApiTimeout(Exception):
60+
"""Raised for 502 http error with proxy due to timeout"""
61+
62+
def __init__(self, message="reverse proxy timeout error during API call - try increasing the reverse proxy timeout"):
63+
self.message = message
64+
super().__init__(self.message)
65+
66+
class ApiServiceUnavailable(Exception):
67+
"""Raised for 503 http error Service unavailable"""
68+
69+
def __init__(self, message="API unavailable"):
70+
self.message = message
71+
super().__init__(self.message)
72+
73+
74+
def readConfig(configFilename, keyToGet):
75+
try:
76+
with open(configFilename, "r") as customConfigFH:
77+
customConfig = json.loads(customConfigFH.read())
78+
return customConfig[keyToGet]
79+
80+
except:
81+
logger.error("could not read key '" + keyToGet + "' from config file " + configFilename + ", Exception: " + str(traceback.format_exc()))
82+
sys.exit(1)
83+
84+
85+
def buildDN(userId, ldapPath):
86+
dn = ""
87+
if len(userId)>0:
88+
if '{USERID}' in ldapPath:
89+
dn = ldapPath.replace('{USERID}', userId)
90+
else:
91+
logger.error("could not find {USERID} parameter in ldapPath " + ldapPath)
92+
return dn
93+
94+
95+
def getLogger(debug_level_in=0):
96+
debug_level=int(debug_level_in)
97+
if debug_level>=1:
98+
llevel = logging.DEBUG
99+
else:
100+
llevel = logging.INFO
101+
102+
logger = logging.getLogger('import-fworch-app-data')
103+
# logHandler = logging.StreamHandler(stream=stdout)
104+
logformat = "%(asctime)s [%(levelname)-5.5s] [%(filename)-10.10s:%(funcName)-10.10s:%(lineno)4d] %(message)s"
105+
logging.basicConfig(format=logformat, datefmt="%Y-%m-%dT%H:%M:%S%z", level=llevel)
106+
logger.setLevel(llevel)
107+
108+
#set log level for noisy requests/connectionpool module to WARNING:
109+
connection_log = logging.getLogger("urllib3.connectionpool")
110+
connection_log.setLevel(logging.WARNING)
111+
connection_log.propagate = True
112+
113+
if debug_level>8:
114+
logger.debug ("debug_level=" + str(debug_level) )
115+
return logger
116+
117+
118+
# adds data from csv file to appData
119+
# order of files in important: we only import apps which are included in files 3 and 4 (which only contain active apps)
120+
# so first import files 3 and 4, then import files 1 and 2^
121+
def extractAppDataFromCsvFile(csvFile: str, appData: dict, containsIp: bool):
122+
123+
if containsIp:
124+
appNameColumn = 0
125+
appIdColumn = 2
126+
appOwnerBISOColumn = 4
127+
appOwnerTISOColumn = 5
128+
appServerIpColumn = 12
129+
else:
130+
appNameColumn = 0
131+
appIdColumn = 1
132+
appOwnerBISOColumn = 3
133+
appOwnerTISOColumn = 4
134+
appServerIpColumn = None
135+
136+
appDataFromCsv = []
137+
csvFile = repoTargetDir + '/' + csvFile # add directory to csv files
138+
139+
# read csv file:
140+
try:
141+
with open(csvFile, newline='') as csvFile:
142+
reader = csv.reader(csvFile)
143+
appDataFromCsv += list(reader)[1:]# Skip headers in first line
144+
except:
145+
logger.error("error while trying to read csv file '" + csvFile + "', exception: " + str(traceback.format_exc()))
146+
sys.exit(1)
147+
148+
countSkips = 0
149+
# append all owners from CSV
150+
for line in appDataFromCsv:
151+
appId = line[appIdColumn]
152+
if appId.lower().startswith('app-') or appId.lower().startswith('com-'):
153+
appName = line[appNameColumn]
154+
appMainUser = line[appOwnerTISOColumn]
155+
mainUserDn = buildDN(appMainUser, ldapPath)
156+
bisoDn = buildDN(line[appOwnerBISOColumn], ldapPath)
157+
if mainUserDn=='':
158+
logger.warning('adding app without main user: ' + appId)
159+
if appId not in appData.keys() and not containsIp:
160+
# only add app if it is in file 3 or 4
161+
appData.update({appId: {
162+
"app_id_external": appId,
163+
"name": appName,
164+
"main_user": mainUserDn,
165+
"BISO": bisoDn,
166+
"modellers": [],
167+
"import_source": importSourceString,
168+
"app_servers": [],
169+
} })
170+
elif containsIp and appId in appData.keys():
171+
# add app server ip addresses (but do not add the whole app - it must already exist)
172+
appServerIp = line[appServerIpColumn]
173+
if appServerIp is not None and appServerIp != "" and appServerIp not in appData[appId]['app_servers']:
174+
appData[appId]['app_servers'].append(appServerIp)
175+
else:
176+
# logger.debug(f'ignoring line from csv file: {appId} - empty IP')
177+
countSkips += 1
178+
else:
179+
logger.debug(f'ignoring line from csv file: {appId} - inactive?')
180+
countSkips += 1
181+
else:
182+
logger.info(f'ignoring line from csv file: {appId} - inconclusive appId')
183+
countSkips += 1
184+
logger.info(f"{str(csvFile.name)}: #total lines {str(len(appDataFromCsv))}, skipped: {str(countSkips)}")
185+
186+
187+
if __name__ == "__main__":
188+
parser = argparse.ArgumentParser(
189+
description='Read configuration from FW management via API calls')
190+
parser.add_argument('-c', '--config', default=defaultConfigFileName,
191+
help='Filename of custom config file for modelling imports')
192+
parser.add_argument('-s', "--suppress_certificate_warnings", action='store_true', default = True,
193+
help = "suppress certificate warnings")
194+
parser.add_argument('-l', '--limit', metavar='api_limit', default='150',
195+
help='The maximal number of returned results per HTTPS Connection; default=50')
196+
197+
args = parser.parse_args()
198+
199+
if args.suppress_certificate_warnings:
200+
requests.packages.urllib3.disable_warnings()
201+
202+
logger = getLogger(debug_level_in=2)
203+
204+
# read config
205+
ldapPath = readConfig(args.config, 'ldapPath')
206+
gitRepoUrl = readConfig(args.config, 'ipamGitRepo')
207+
gitUsername = readConfig(args.config, 'ipamGitUser')
208+
gitPassword = readConfig(args.config, 'gitpassword')
209+
csvAllOwnerFiles = readConfig(args.config, 'csvAllOwnerFiles')
210+
csvAppServerFiles = readConfig(args.config, 'csvAppServerFiles')
211+
212+
#############################################
213+
# 1. get CSV files from github repo
214+
repoUrl = "https://" + gitUsername + ":" + gitPassword + "@" + gitRepoUrl
215+
if os.path.exists(repoTargetDir):
216+
# If the repository already exists, open it and perform a pull
217+
repo = git.Repo(repoTargetDir)
218+
origin = repo.remotes.origin
219+
origin.pull()
220+
else:
221+
repo = git.Repo.clone_from(repoUrl, repoTargetDir)
222+
223+
#############################################
224+
# 2. get app data from CSV files
225+
appData = {}
226+
for csvFile in csvAllOwnerFiles:
227+
extractAppDataFromCsvFile(csvFile, appData, False)
228+
for csvFile in csvAppServerFiles:
229+
extractAppDataFromCsvFile(csvFile, appData, True)
230+
231+
#############################################
232+
# 3. write owners to json file
233+
path = os.path.dirname(__file__)
234+
fileOut = path + '/' + Path(os.path.basename(__file__)).stem + ".json"
235+
with open(fileOut, "w") as outFH:
236+
json.dump(appData, outFH, indent=3)
237+
238+
#############################################
239+
# 4. Some statistics
240+
logger.info(f"total #apps: {str(len(appData))}")
241+
appsWithIp = 0
242+
for appId in appData:
243+
appsWithIp += 1 if len(appData[appId]['app_servers']) > 0 else 0
244+
logger.info(f"#apps with ip addresses: {str(appsWithIp)}")
245+
totalIps = 0
246+
for appId in appData:
247+
totalIps += len(appData[appId]['app_servers'])
248+
logger.info(f"#ip addresses in total: {str(totalIps)}")
249+
250+
sys.exit(0)

0 commit comments

Comments
 (0)