Skip to content
Snippets Groups Projects
Commit 5f15bf0a authored by Robert Latta's avatar Robert Latta
Browse files

weeded duplicates and provided option to exclude remaining duplicates

parent aeb57f46
No related branches found
No related tags found
No related merge requests found
...@@ -5,10 +5,46 @@ from collections import OrderedDict ...@@ -5,10 +5,46 @@ from collections import OrderedDict
from inventory_provider import environment from inventory_provider import environment
from inventory_provider.db import ims from inventory_provider.db import ims
from inventory_provider.db.ims import InventoryStatus from inventory_provider.db.ims import InventoryStatus
environment.setup_logging() environment.setup_logging()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Dashboard V3
def lookup_pop_info(ds, hostname):
site_nav_props = [
ims.SITE_PROPERTIES['City'],
ims.SITE_PROPERTIES['SiteAliases'],
ims.SITE_PROPERTIES['Country']
]
node = ds.get_entity_by_name('Node', hostname)
if not node:
return None
site = ds.get_entity_by_id('Site', node['SiteId'], site_nav_props, True)
city = site['City']
abbreviation = ''
try:
abbreviation = site['SiteAliases'][0]['AliasName']
except IndexError:
pass # no alias - ignore silently
eq = {
'equipment-name': node['Name'],
'status': InventoryStatus(node['InventoryStatusId']).name,
'pop': {
'name': site['Name'],
'city': city['Name'],
'country': city['Country']['Name'],
'abbreviation': abbreviation,
'longitude': site['Longitude'],
'latitude': site['Latitude'],
}
}
return eq
# End of Dashboard V3 stuff
INTERNAL_POP_NAMES = { INTERNAL_POP_NAMES = {
'Cambridge OC', 'Cambridge OC',
'DANTE Lab', 'DANTE Lab',
...@@ -81,38 +117,6 @@ def lookup_lg_routers(ds): ...@@ -81,38 +117,6 @@ def lookup_lg_routers(ds):
yield(eq) yield(eq)
def lookup_pop_info(ds, hostname):
site_nav_props = [
ims.SITE_PROPERTIES['City'],
ims.SITE_PROPERTIES['SiteAliases'],
ims.SITE_PROPERTIES['Country']
]
node = ds.get_entity_by_name('Node', hostname)
if not node:
return None
site = ds.get_entity_by_id('Site', node['SiteId'], site_nav_props, True)
city = site['City']
abbreviation = ''
try:
abbreviation = site['SiteAliases'][0]['AliasName']
except IndexError:
pass # no alias - ignore silently
eq = {
'equipment-name': node['Name'],
'status': InventoryStatus(node['InventoryStatusId']).name,
'pop': {
'name': site['Name'],
'city': city['Name'],
'country': city['Country']['Name'],
'abbreviation': abbreviation,
'longitude': site['Longitude'],
'latitude': site['Latitude'],
}
}
return eq
def otrs_get_customer_company_rows(ds): def otrs_get_customer_company_rows(ds):
yield ['customer_id', 'name', 'street', 'zip', 'city', 'country', 'url', yield ['customer_id', 'name', 'street', 'zip', 'city', 'country', 'url',
'comments'] 'comments']
...@@ -215,7 +219,7 @@ def otrs_get_vendor_contacts(ds): ...@@ -215,7 +219,7 @@ def otrs_get_vendor_contacts(ds):
yield t_customer_user yield t_customer_user
def otrs_get_customer_users_rows(ds): def otrs_get_customer_users_rows(ds, return_duplicates=False):
yield ['email', 'username', 'customer_id', 'customer_id_2', 'title', yield ['email', 'username', 'customer_id', 'customer_id_2', 'title',
'firstname', 'lastname', 'phone', 'fax', 'mobile', 'street', 'zip', 'firstname', 'lastname', 'phone', 'fax', 'mobile', 'street', 'zip',
'city', 'country', 'comments'] 'city', 'country', 'comments']
...@@ -229,18 +233,59 @@ def otrs_get_customer_users_rows(ds): ...@@ -229,18 +233,59 @@ def otrs_get_customer_users_rows(ds):
if c['email'] not in yielded_customer_emails: if c['email'] not in yielded_customer_emails:
yield c yield c
sorted_cus = sorted(get_all_cus_user_rows(), key=lambda x: x['email']) def weed_duplicates(duplicates):
# this is here to allow for additional rules
id_rank = {
'geant': 1
}
top_rank = -1
top_ranked = None
for d in duplicates:
rank = id_rank.get(d['customer_id'].lower(), 0)
if rank > top_rank:
top_rank = rank
top_ranked = []
if rank == top_rank:
top_ranked.append(d)
return top_ranked
cus_by_email = {}
duplicate_emails = set() duplicate_emails = set()
previous_email = None for cu in get_all_cus_user_rows():
for cu in sorted_cus: email = cu['email']
if cu['email'] == previous_email: cus_for_email = cus_by_email.get(email, [])
duplicate_emails.add(previous_email) if cus_for_email:
previous_email = cu['email'] duplicate_emails.add(email)
cus_for_email.append(cu)
cus_by_email[email] = cus_for_email
remaining_duplicates = []
if duplicate_emails: if duplicate_emails:
logger.error('Duplicate emails found in OTRS customer-user export: ' logger.info('Duplicate emails found in OTRS customer-user export: '
f'{duplicate_emails}') f'{duplicate_emails} - attempting to weed')
# raise KeyError('Duplicate emails found in OTRS customer-user export: ' # noqa # weeded = []
# f'{duplicate_emails}') for email in duplicate_emails:
weeded = weed_duplicates(cus_by_email.pop(email))
for cu in sorted_cus: if len(weeded) == 1:
yield list(cu.values()) cus_by_email[email] = weeded
else:
remaining_duplicates.extend(
sorted(
[list(w.values()) for w in weeded], key=lambda x: x[2])
)
if remaining_duplicates:
# need guidance what to do if this occurs, should we pick the first
# one for each, or ignore them completely? Ignoring them for now
logger.error('Duplicate emails remain after weeding, '
f'{"including" if return_duplicates else "excluding"}'
' duplicates in returned data: ')
for rd in remaining_duplicates:
logger.debug(rd)
for email, details in sorted(cus_by_email.items()):
yield list(details[0].values())
if return_duplicates:
yield from remaining_duplicates
...@@ -18,16 +18,11 @@ def after_request(resp): ...@@ -18,16 +18,11 @@ def after_request(resp):
return common.after_request(resp) return common.after_request(resp)
def get_otrs_data(fn): def get_otrs_output(result):
ims_config = current_app.config['INVENTORY_PROVIDER_CONFIG']["ims"]
ds = IMS(
ims_config['api'],
ims_config['username'],
ims_config['password'])
with StringIO() as sio: with StringIO() as sio:
writer = csv.writer(sio, delimiter='^') writer = csv.writer(sio, delimiter='^')
writer.writerows(fn(ds)) writer.writerows(result)
data = sio.getvalue() data = sio.getvalue()
return Response( return Response(
response=data, response=data,
...@@ -37,17 +32,24 @@ def get_otrs_data(fn): ...@@ -37,17 +32,24 @@ def get_otrs_data(fn):
@routes.route('customer-companies') @routes.route('customer-companies')
def get_customer_companies_data(): def get_customer_companies_data():
return get_otrs_data(ims_data.otrs_get_customer_company_rows) ims_config = current_app.config['INVENTORY_PROVIDER_CONFIG']["ims"]
ds = IMS(ims_config['api'], ims_config['username'], ims_config['password'])
return get_otrs_output(ims_data.otrs_get_customer_company_rows(ds))
@routes.route('customer-users') @routes.route('customer-users')
def get_customer_users_data(): def get_customer_users_data():
return get_otrs_data(ims_data.otrs_get_customer_users_rows) ims_config = current_app.config['INVENTORY_PROVIDER_CONFIG']["ims"]
ds = IMS(ims_config['api'], ims_config['username'], ims_config['password'])
return_duplicates = request.args.get('duplicates', 'f').lower() == 'true'
return get_otrs_output(ims_data.otrs_get_customer_users_rows(
ds, return_duplicates=return_duplicates))
@routes.route('export') @routes.route('export')
def send_exports(): def send_exports():
files_value = request.args.get('files', None) files_value = request.args.get('files', None)
duplicates = request.args.get('duplicates', 'f').lower() == 'true'
if files_value: if files_value:
try: try:
files_value = int(files_value) files_value = int(files_value)
...@@ -61,7 +63,8 @@ def send_exports(): ...@@ -61,7 +63,8 @@ def send_exports():
response=html.escape(f'Bad value for <files> {files_value}'), response=html.escape(f'Bad value for <files> {files_value}'),
status=requests.codes.bad_request, status=requests.codes.bad_request,
mimetype="text/html") mimetype="text/html")
task = export_data_for_otrs.delay(files_value) task = export_data_for_otrs.delay(
files_to_export=files_value, export_duplicates=duplicates)
return Response( return Response(
response=task.id, response=task.id,
status=requests.codes.ok, status=requests.codes.ok,
......
import html
import requests
from flask import Blueprint, request, Response
from inventory_provider.routes import common
from inventory_provider.tasks.ims_worker import OTRSFiles, export_data_for_otrs
routes = Blueprint("otrs", __name__)
@routes.after_request
def after_request(resp):
return common.after_request(resp)
@routes.route('export')
def send_exports():
files_value = request.args.get('files', None)
if files_value:
try:
files_value = int(files_value)
except ValueError:
return Response(
response=html.escape('<files> should be an Integer'),
status=requests.codes.bad_request,
mimetype="text/html")
if files_value < 0 or files_value > sum(OTRSFiles):
return Response(
response=html.escape(f'Bad value for <files> {files_value}'),
status=requests.codes.bad_request,
mimetype="text/html")
task = export_data_for_otrs.delay(files_value)
return Response(
response=task.id,
status=requests.codes.ok,
mimetype="text/html")
...@@ -47,13 +47,12 @@ class OTRSFiles(IntFlag): ...@@ -47,13 +47,12 @@ class OTRSFiles(IntFlag):
@app.task(base=InventoryTask, bind=True, name='export_data_for_otrs') @app.task(base=InventoryTask, bind=True, name='export_data_for_otrs')
@log_task_entry_and_exit @log_task_entry_and_exit
def export_data_for_otrs(self, files_to_export=None): def export_data_for_otrs(self, files_to_export=None, export_duplicates=False):
if files_to_export: if files_to_export:
files_to_export = OTRSFiles(files_to_export) files_to_export = OTRSFiles(files_to_export)
else: else:
files_to_export = set(OTRSFiles) files_to_export = set(OTRSFiles)
logger.debug('>>> export_data_for_otrs_ims')
ims_config = InventoryTask.config["ims"] ims_config = InventoryTask.config["ims"]
otrs_config = InventoryTask.config["otrs-export"] otrs_config = InventoryTask.config["otrs-export"]
...@@ -78,7 +77,8 @@ def export_data_for_otrs(self, files_to_export=None): ...@@ -78,7 +77,8 @@ def export_data_for_otrs(self, files_to_export=None):
cus_usr_path = temp_path.joinpath(f'{prefix}customer_user.csv') cus_usr_path = temp_path.joinpath(f'{prefix}customer_user.csv')
with open(cus_usr_path, 'w+') as f: with open(cus_usr_path, 'w+') as f:
writer = csv.writer(f, delimiter='^') writer = csv.writer(f, delimiter='^')
writer.writerows(ims_data.otrs_get_customer_users_rows(ds)) writer.writerows(ims_data.otrs_get_customer_users_rows(
ds, return_duplicates=export_duplicates))
command = command_template.format( command = command_template.format(
user=otrs_config['username'], user=otrs_config['username'],
...@@ -88,5 +88,3 @@ def export_data_for_otrs(self, files_to_export=None): ...@@ -88,5 +88,3 @@ def export_data_for_otrs(self, files_to_export=None):
destination=otrs_config['destination'] destination=otrs_config['destination']
) )
subprocess.run(command, shell=True, check=True) subprocess.run(command, shell=True, check=True)
logger.debug('<<< export_data_for_otrs_ims')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment