From 3dbb84755b31229eb1de7bc8b56c637ca9dbcfd2 Mon Sep 17 00:00:00 2001 From: Nikolay Stanchev <ns17@it-innovation.soton.ac.uk> Date: Fri, 22 Jun 2018 16:09:49 +0100 Subject: [PATCH] Implements database connectivity using PostgreSQL for the CLMC service --- src/service/clmcservice/__init__.py | 6 ++++ src/service/clmcservice/initialize_db.py | 38 ++++++++++++++++++++++++ src/service/clmcservice/models.py | 28 +++++++++++++++++ src/service/development.ini | 13 ++++++-- src/service/production.ini | 11 +++++-- src/service/setup.py | 6 ++++ 6 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/service/clmcservice/initialize_db.py create mode 100644 src/service/clmcservice/models.py diff --git a/src/service/clmcservice/__init__.py b/src/service/clmcservice/__init__.py index 3f29bc4..69ee81b 100644 --- a/src/service/clmcservice/__init__.py +++ b/src/service/clmcservice/__init__.py @@ -23,6 +23,8 @@ """ from pyramid.config import Configurator +from sqlalchemy import engine_from_config +from clmcservice.models import DBSession, Base from clmcservice.aggregationapi.utilities import validate_conf_file, RUNNING_FLAG, MALFORMED_FLAG, CONF_FILE_ATTRIBUTE, CONF_OBJECT, AGGREGATOR_CONFIG_SECTION @@ -31,6 +33,10 @@ def main(global_config, **settings): This function returns a Pyramid WSGI application. """ + engine = engine_from_config(settings, 'sqlalchemy.') # initialise a database engine by using the 'sqlalchemy' setting in the configuration .ini file + DBSession.configure(bind=engine) # bind the engine to a DB session + Base.metadata.bind = engine # bind the engine to the Base class metadata + # validate and use (if valid) the configuration file conf_file_path = settings[CONF_FILE_ATTRIBUTE] conf = validate_conf_file(conf_file_path) # if None returned here, service is in unconfigured state diff --git a/src/service/clmcservice/initialize_db.py b/src/service/clmcservice/initialize_db.py new file mode 100644 index 0000000..a0b1a09 --- /dev/null +++ b/src/service/clmcservice/initialize_db.py @@ -0,0 +1,38 @@ +import os +import sys +from sqlalchemy import engine_from_config +from pyramid.paster import get_appsettings, setup_logging +from clmcservice.models import DBSession, Base + + +def usage(argv): + """ + A method to be called when the script has been used in an incorrect way. + + :param argv: cmd arguments + """ + + cmd = os.path.basename(argv[0]) + print('usage: %s <config_uri>\n' + '(example: "%s development.ini")' % (cmd, cmd)) + sys.exit(1) + + +def main(argv=sys.argv): + """ + Main method of the script - initialises the database by creating all tables declared in the models.py module + + :param argv: command line arguments - expects a configuration .ini file from which it retrieves the URL with which to connect to postgresql + """ + + if len(argv) != 2: + usage(argv) # in case of wrong usage + + config_uri = argv[1] + setup_logging(config_uri) + + settings = get_appsettings(config_uri) # get application specific settings + engine = engine_from_config(settings, 'sqlalchemy.') # create the db engine from the sqlalchemy setting configured in the .ini file + + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) # creates all model tables diff --git a/src/service/clmcservice/models.py b/src/service/clmcservice/models.py new file mode 100644 index 0000000..840fc08 --- /dev/null +++ b/src/service/clmcservice/models.py @@ -0,0 +1,28 @@ +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import scoped_session, sessionmaker +from zope.sqlalchemy import ZopeTransactionExtension +from sqlalchemy import Column, String, Integer, UniqueConstraint + + +DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) # initialise a ORM session, ought to be reused across the different modules +Base = declarative_base() # initialise a declarative Base instance to use for the web app models + + +class ServiceFunctionEndpoint(Base): + """ + This class defines the main model of the WHOAMI API, declaring the global tags for a specific service function on a specific endpoint. + """ + + __tablename__ = 'sfendpoints' # table name in the PostgreSQL database + + __table_args__ = (UniqueConstraint('sf_i', 'sf_endpoint', 'sr'),) # defines a unique constraint across 3 columns - sf_i, sf_endpoint, sr + + uid = Column(Integer, primary_key=True, autoincrement=True) # a primary key integer field (auto incremented) + + location = Column(String) # cluster label + sfc = Column(String) # service function chain label + sfc_i = Column(String) # service function chain instance identifier + sf = Column(String) # service function label + sf_i = Column(String) # service function identifier (potentially FQDN) + sf_endpoint = Column(String) # service function endpoint (potentially IP address) + sr = Column(String) # service router ID - service router that connects the VM to FLAME diff --git a/src/service/development.ini b/src/service/development.ini index 390e2a5..18e7f24 100644 --- a/src/service/development.ini +++ b/src/service/development.ini @@ -14,9 +14,11 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_debugtoolbar pyramid_exclog exclog.ignore = -## Configuration file path +# Configuration file path configuration_file_path = /etc/flame/clmc/service.conf +# PostgreSQL connection url +sqlalchemy.url = postgresql://clmc:clmc_service@localhost:5432/whoamidb # By default, the toolbar only appears for clients from IP addresses # '127.0.0.1' and '::1'. @@ -36,7 +38,7 @@ listen = localhost:9080 ### [loggers] -keys = root, exc_logger, clmcservice +keys = root, exc_logger, service_logger, sqlalchemy.engine.base.Engine [handlers] keys = console, filelog, exc_handler @@ -48,7 +50,12 @@ keys = generic, exc_formatter level = INFO handlers = console -[logger_clmcservice] +[logger_sqlalchemy.engine.base.Engine] +level = INFO +handlers = +qualname = sqlalchemy.engine.base.Engine + +[logger_service_logger] level = INFO handlers = filelog qualname = service_logger diff --git a/src/service/production.ini b/src/service/production.ini index 3e8876b..8ebe666 100644 --- a/src/service/production.ini +++ b/src/service/production.ini @@ -14,9 +14,11 @@ pyramid.default_locale_name = en pyramid.includes = pyramid_exclog exclog.ignore = -## Configuration file path +# Configuration file path configuration_file_path = /etc/flame/clmc/service.conf +# PostgreSQL connection url +sqlalchemy.url = postgresql://clmc:clmc_service@localhost:5432/whoamidb ### # wsgi server configuration @@ -32,7 +34,7 @@ listen = *:9080 ### [loggers] -keys = root, exc_logger, service_logger +keys = root, exc_logger, service_logger, sqlalchemy.engine.base.Engine [handlers] keys = console, filelog, exc_handler @@ -44,6 +46,11 @@ keys = generic, exc_formatter level = INFO handlers = console +[logger_sqlalchemy.engine.base.Engine] +level = INFO +handlers = +qualname = sqlalchemy.engine.base.Engine + [logger_service_logger] level = INFO handlers = filelog diff --git a/src/service/setup.py b/src/service/setup.py index 4b80091..7bbc332 100644 --- a/src/service/setup.py +++ b/src/service/setup.py @@ -46,6 +46,9 @@ requires = [ 'pyramid_debugtoolbar', 'pyramid_exclog', 'waitress', + 'sqlalchemy', + 'zope.sqlalchemy', + 'psycopg2', 'influxdb', 'pytest', ] @@ -80,5 +83,8 @@ setup( 'paste.app_factory': [ 'main = clmcservice:main', ], + 'console_scripts': [ + 'initialize_clmcservice_db = clmcservice.initialize_db:main', + ] }, ) \ No newline at end of file -- GitLab