Skip to content

Commit

Permalink
hack to redirect to new mongo with auth
Browse files Browse the repository at this point in the history
  • Loading branch information
root committed Nov 27, 2024
1 parent c35f163 commit 6c52bcd
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 19 deletions.
45 changes: 26 additions & 19 deletions conftrak/server/engine.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import absolute_import
from tornado import gen
import tornado.web
import os
import pymongo
import jsonschema
import ujson
from . import utils
from jsonschema.exceptions import ValidationError, SchemaError
from ..exceptions import ConfTrakException

HACK = True

def db_connect(database, mongo_host, mongo_port):
"""Helper function to deal with stateful connections to MongoDB
Expand All @@ -28,25 +30,30 @@ def db_connect(database, mongo_host, mongo_port):
multiple clients and makes no difference for a single client compared
to pymongo
"""
try:
client = pymongo.MongoClient(host=mongo_host, port=mongo_port)
client.list_database_names() # check if the server is really okay.
except (pymongo.errors.ConnectionFailure,
pymongo.errors.ServerSelectionTimeoutError):
raise ConfTrakException("Unable to connect to MongoDB server...")

database = client[database]

database.configuration.create_index([('uid', pymongo.DESCENDING)],
unique=True, background=False)
database.configuration.create_index([('time', pymongo.DESCENDING)],
unique=False, background=True)
database.configuration.create_index([('beamline_id', pymongo.DESCENDING)],
unique=False, background=True,
sparse=True)
database.configuration.create_index([('key', pymongo.DESCENDING)],
unique=False, background=True,
sparse=True)

# TODO: Temporarily hard code mongo client.
if HACK:
client = pymongo.MongoClient(f"mongodb://fmx_write:{os.environ['MONGO_PASSWORD_FMX']}@mongo1.nsls2.bnl.gov,mongo2.nsls2.bnl.gov,mongo3.nsls2.bnl.gov/?authSource=admin")
database = client['fmx-conftrak']
else:
try:
client = pymongo.MongoClient(host=mongo_host, port=mongo_port)
client.list_database_names() # check if the server is really okay.
except (pymongo.errors.ConnectionFailure,
pymongo.errors.ServerSelectionTimeoutError):
raise ConfTrakException("Unable to connect to MongoDB server...")
database = client[database]

database.configuration.create_index([('uid', pymongo.DESCENDING)],
unique=True, background=False)
database.configuration.create_index([('time', pymongo.DESCENDING)],
unique=False, background=True)
database.configuration.create_index([('beamline_id', pymongo.DESCENDING)],
unique=False, background=True,
sparse=True)
database.configuration.create_index([('key', pymongo.DESCENDING)],
unique=False, background=True,
sparse=True)

return database

Expand Down
208 changes: 208 additions & 0 deletions conftrak/server/engine_noindexcreation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
from __future__ import absolute_import
from tornado import gen
import tornado.web
import pymongo
import jsonschema
import ujson
from . import utils
from jsonschema.exceptions import ValidationError, SchemaError
from ..exceptions import ConfTrakException


def db_connect(database, mongo_host, mongo_port):
"""Helper function to deal with stateful connections to MongoDB
Connection established lazily. Connects to the database on request.
Same connection pool is used for all clients per recommended by
tornado developer manual.
Parameters
----------
database: str
The name of database pymongo creates and/or connects
host: str
Name/address of the server that mongo daemon lives
port: int
Port num of the server
Returns pymongo.database.Database
-------
Async server object which comes in handy as server has to juggle
multiple clients and makes no difference for a single client compared
to pymongo
"""
try:
client = pymongo.MongoClient(host=mongo_host, port=mongo_port)
client.list_database_names() # check if the server is really okay.
except (pymongo.errors.ConnectionFailure,
pymongo.errors.ServerSelectionTimeoutError):
raise ConfTrakException("Unable to connect to MongoDB server...")

database = client[database]

#database.configuration.create_index([('uid', pymongo.DESCENDING)],
# unique=True, background=False)
#database.configuration.create_index([('time', pymongo.DESCENDING)],
# unique=False, background=True)
#database.configuration.create_index([('beamline_id', pymongo.DESCENDING)],
# unique=False, background=True,
# sparse=True)
#database.configuration.create_index([('key', pymongo.DESCENDING)],
# unique=False, background=True,
# sparse=True)

return database


class DefaultHandler(tornado.web.RequestHandler):
"""DefaultHandler which takes care of CORS. Javascript needs this.
In general, methods on RequestHandler and elsewhere in Tornado
are not thread-safe. In particular, methods such as write(),
finish(), and flush() must only be called from the main thread.
If you use multiple threads it is important to use IOLoop.add_callback
to transfer control back to the main thread before finishing the request.
"""
@gen.coroutine
def set_default_headers(self):
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.set_header('Access-Control-Max-Age', 1000)
self.set_header('Access-Control-Allow-Headers', '*')
self.set_header('Content-type', 'application/json')

def data_received(self, chunk):
"""Abstract method, overwrite potential default"""
pass


class ConfigurationReferenceHandler(DefaultHandler):
"""Handler for ConfigurationReference insert, update, and querying.
A RESTful handler, nothing fancy or stateful about this
Methods
--------
get()
Query 'configuration_referenece' documents given certain parameters.
Pass 'num' in order to obtain the last 'num' configuration references.
post()
Insert 'configuration' documents
put()
Update or Insert if 'configuration' document does not exist.
Update supports both field update and document replacement. If you
would like to replace a document, simply provide a full doc in update
field. Otherwise, provide a dict that holds the new value and field name.
Returns the total number of documents that are updated.
"""
@gen.coroutine
def get(self):
database = self.settings['db']
query = utils.unpack_params(self)
if 'active_only' in query:
filter_active = query.pop('active_only')
if filter_active:
query['active'] = True

num = query.pop("num", None)
try:
if num:
docs = database.configuration.find(query).sort('time',
direction=pymongo.DESCENDING).limit(num)
else:
docs = database.configuration.find(query).sort('time',
direction=pymongo.DESCENDING)
num_docs = database.configuration.count_documents(query)
if docs and num_docs > 0:
utils.return2client(self, docs)
else:
raise utils._compose_err_msg(500, 'No results found!')
except pymongo.errors.PyMongoError:
raise utils._compose_err_msg(500, 'Query on config has failed',
query)


@gen.coroutine
def post(self):
database = self.settings['db']
data = ujson.loads(self.request.body.decode("utf-8"))
uids = []
if isinstance(data, list):
for d in data:
# Ensure the active status on the new Configuration
d['active'] = True
d = utils.default_timeuid(d)
try:
jsonschema.validate(d,
utils.schemas['configuration'])
except (ValidationError, SchemaError):
raise utils._compose_err_msg(400,
"Invalid schema on document(s)", d)
uids.append(d['uid'])
database.configuration.insert_one(d)
elif isinstance(data, dict):
data = utils.default_timeuid(data)
# Ensure the active status on the new Configuration
data['active'] = True
try:
jsonschema.validate(data,
utils.schemas['configuration'])
except (ValidationError, SchemaError):
raise utils._compose_err_msg(400,
"Invalid schema on document(s)", data)
uids.append(data['uid'])
database.configuration.insert_one(data)
else:
raise utils._compose_err_msg(500,
status='ConfigurationHandler expects list or dict')
self.finish(ujson.dumps(uids))

@gen.coroutine
def put(self):
database = self.settings['db']
incoming = ujson.loads(self.request.body)
try:
query = incoming.pop('query')
update = incoming.pop('update')
except KeyError:
raise utils._compose_err_msg(500,
status='filter and update are both required fields')
if any(x in update.keys() for x in ['uid', 'time']):
raise utils._compose_err_msg(500,
status='Time and uid cannot be updated')
res = database.configuration.update_many(filter=query,
update={'$set': update},
upsert=False)
self.finish(ujson.dumps(utils.sanitize_return(res.raw_result)))

@gen.coroutine
def delete(self):
database = self.settings['db']
incoming = utils.unpack_params(self)
#incoming = ujson.loads(self.request.body)
try:
uid_list = incoming.pop('uid_list')
except KeyError:
raise utils._compose_err_msg(500,
status='delete require a list of uids')

if not isinstance(uid_list, (list, tuple)):
uid_list = [uid_list]

res = database.configuration.update_many(filter={'uid': {'$in': uid_list}},
update={'$set': {'active': False}},
upsert=False)
self.finish(ujson.dumps(utils.sanitize_return(res.raw_result)))


class SchemaHandler(DefaultHandler):
"""Provides the json used for schema validation provided collection name"""
@gen.coroutine
def get(self):
col = utils.unpack_params(self)
self.write(utils.schemas[col])
self.finish()

@gen.coroutine
def put(self):
raise utils._compose_err_msg(405,
status='Not allowed on server')

@gen.coroutine
def post(self):
raise utils._compose_err_msg(405,
status='Not allowed on server')

0 comments on commit 6c52bcd

Please sign in to comment.