Commit 36e02cad authored by Andrii Salnikov's avatar Andrii Salnikov
Browse files

Code for EGI API VOMS info querying

parent f2efa1d7
Pipeline #9745 canceled with stages
FROM python:3-alpine
RUN pip install flask
COPY egi-voinfo-proxy.py /app/egi-voinfo-proxy.py
CMD ["/app/egi-voinfo-proxy.py"]
# EGI VOMS Info
Query authenticated EGI API to get VOMSes information and return to the public
\ No newline at end of file
Query authenticated EGI API to get VOMSes information and return to the public
## Running the service
Set the ``EGI_API_TOKEN`` environment variable and run the code (optionally and preferably in the container).
Token can be obtained following https://operations-portal.egi.eu/api-documentation
Optional settings are:
* ``CACHE_DIR`` (default is ``/tmp/voms-data``)
* ``CACHE_TTL`` (default is 86400 seconds)
## Using public API
Service provides API for getting VOMS data for VOs:
* ``/api/<VO name>/lsc`` - returns JSON array of VOMS List of Certificates (a.k.a LSCs for server side configuration)
* ``/api/<VO name>/vomses`` - returns JSON array of VOMSes strngs (client configuration)
Return codes other than ``200`` indicates an error. E.g. ``404`` stands for no invormation found for supplied VO name.
#!/usr/local/bin/python
import sys
import os
import flask
import http.client
import time
import json
import logging
# settings
token = None
cache_dir = '/tmp/voms-data'
cache_ttl = 86400
# logging
logger = logging.getLogger('ARC.VOInfo.Proxy')
logger.setLevel(logging.INFO)
log_handler_stderr = logging.StreamHandler()
log_handler_stderr.setFormatter(
logging.Formatter('[%(asctime)s] [%(name)s] [%(levelname)s] [%(process)d] [%(message)s]'))
logger.addHandler(log_handler_stderr)
# get settings from environment
if 'EGI_API_TOKEN' in os.environ:
token = os.environ['EGI_API_TOKEN']
else:
logger.fatal('No EGI_API_TOKEN provided. Execution aborted.')
sys.exit(1)
if 'CACHE_DIR' in os.environ:
cache_dir = os.environ['CAHCE_DIR']
if 'CACHE_TTL' in os.environ:
cache_ttl = int(os.environ['CAHCE_TTL'])
# EGI API
def get_egi_vo_data(name):
conn = http.client.HTTPSConnection('operations-portal.egi.eu', 443)
db_data = {}
vo_data = {
'status': True,
'vomses': [],
'lscs': []
}
try:
headers = {'X-API-Key': token}
conn.request('GET', '/api/vo-idcard/{}'.format(name), '', headers)
resp = conn.getresponse()
if resp.status != 200:
logger.error('Failed to get information from EGI database. Error code %s returned: %s',
str(resp.status), resp.reason)
vo_data['status'] = False
vo_data['http_code'] = int(resp.status)
else:
db_data = json.loads(resp.read().decode('utf8'))
except Exception as e:
logger.error('Failed to get information from EGI database. Error: %s', str(e))
vo_data['status'] = False
conn.close()
if vo_data['status'] and 'data' in db_data:
# process data to get VOMSes info
for d in db_data['data']:
if 'Vo' not in d:
continue
for v in d['Vo']:
if 'Registries' not in v:
continue
for vdata in v['Registries']:
if 'VoVomsServer' not in vdata:
continue
port = None
hostname = None
DN = None
CA_DN = None
if 'vomses_port' in vdata:
port = vdata['vomses_port']
for voms in vdata['VoVomsServer']:
if 'hostname' in voms:
hostname = voms['hostname'][0]
elif 'X509Cert' in voms:
for i in voms['X509Cert']:
if 'DN' in i:
DN = i['DN'][0]
elif 'CA_DN' in i:
CA_DN = i['CA_DN'][0]
if port is not None and hostname and DN:
vo_data['vomses'].append('"{0}" "{1}" "{2}" "{3}" "{0}"'.format(name, hostname, port, DN))
vo_data['lscs'].append({
'name': '{}.lsc'.format(hostname),
'dn': DN,
'ca': CA_DN
})
else:
logger.error('Failed to parse necessary info form VoVomsServer data provided by EGI')
if not vo_data['vomses']:
vo_data['status'] = False
return vo_data
# data with cache
def get_vo_data(name):
data = {}
date_now = int(time.time())
# get from cache
cache_file = os.path.join(cache_dir, name)
if os.path.exists(cache_file):
with open(cache_file, 'r') as c_f:
data = json.load(c_f)
# check TTL
if 'timestamp' in data:
if ( date_now - int(data['timestamp']) ) < cache_ttl:
return data
# else fetch from EGI
data = get_egi_vo_data(name)
if data['status']:
# dump to cache
data['timestamp'] = date_now
with open(cache_file, 'w') as c_f:
json.dump(data, c_f)
# and return
return data
return data
# setup cache dir
if not os.path.exists(cache_dir):
logger.info('Creating cahce dir at %s', cache_dir)
os.makedirs(cache_dir, mode=0o755)
# setup Flask app
app = flask.Flask(__name__)
app.config["DEBUG"] = False
@app.route('/api/<name>/lsc', methods=['GET'])
def restart(name):
data = get_vo_data(name)
if not data['status'] or not data['lscs']:
http_code = data['http_code'] if 'http_code' in data else 404
flask.abort(http_code)
return flask.jsonify(data['lscs'])
@app.route('/api/<name>/vomses', methods=['GET'])
def vomses(name):
data = get_vo_data(name)
if not data['status'] or not data['vomses']:
http_code = data['http_code'] if 'http_code' in data else 404
flask.abort(http_code)
return flask.jsonify(data['vomses'])
app.run(host='0.0.0.0')
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment