diff --git a/environment.yml b/environment.yml index f64d06a7133dbcea3db8ec4b3610aaeffb882891..0b38e3f5d46ac533d6cb8d541b56e3c1d45c0468 100644 --- a/environment.yml +++ b/environment.yml @@ -6,10 +6,12 @@ dependencies: - alembic=1.4 - astropy=4.0 - beautifulsoup4=4.9 + - beaker=1.11.0 - blessings=1.7 - conda-build=3.18 - cx_Oracle=7.2 - fabric=2.5 + - funcsigs=1.0.2 - jxmlease=1.0 - lxml=4.5 - mysqlclient=1.4 @@ -21,7 +23,9 @@ dependencies: - pycapo=0.3.0 - pyopenssl=19.1.0 - pyramid=1.10 + - pyramid_beaker=0.8 - pyramid_debugtoolbar=4.5 + - pyramid_tm=2.2.1 - pysftp=0.2.9 - pytest=5.4 - python=3.8 @@ -29,5 +33,7 @@ dependencies: - simplejson=3.17 - sqlalchemy=1.3 - tqdm=4.46 + - transaction=3.0.0 - waitress=1.4 - - zc.buildout=2.13.2 \ No newline at end of file + - zc.buildout=2.13.2 + - zope.sqlalchemy=1.1 diff --git a/services/workflow/MANIFEST.in b/services/workflow/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..5e84c8812c023a08f88d019026c11f34ebcde103 --- /dev/null +++ b/services/workflow/MANIFEST.in @@ -0,0 +1,5 @@ +include *.txt *.ini *.cfg *.rst *.wsgi *.sh *.spec *.md *.py +recursive-include services *.ico *.png *.svg *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.ttf *.woff *.woff2 +include MANIFEST.in +include README.txt +include workflow/* diff --git a/services/workflow/README.txt b/services/workflow/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..97c634472eac4749d2358fc8b07c3a04e0135f75 --- /dev/null +++ b/services/workflow/README.txt @@ -0,0 +1 @@ +# Workflow: the Workspaces Workflow Service diff --git a/services/workflow/development.ini b/services/workflow/development.ini new file mode 100644 index 0000000000000000000000000000000000000000..005980125efd6aa0ffd4627d40140cf53e7c14cf --- /dev/null +++ b/services/workflow/development.ini @@ -0,0 +1,49 @@ +[app:main] +use = egg:workflow +pyramid.includes = + pyramid_debugtoolbar + pyramid_tm +pyramid.reload_all = true + +session.cookie_expires = true +session.auto = true + +[server:main] +use = egg:waitress#main +listen = 0.0.0.0:3456 + + +[loggers] +keys = root, workflow + +[handlers] +keys = console, filelog + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_workflow] +level = DEBUG +handlers = +qualname = workflow + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[handler_filelog] +class = logging.handlers.TimedRotatingFileHandler +args = ('%(here)s/workflow.log','midnight',1,3) +level = INFO +formatter = generic +# When using the TimedRotatingFileHandler, we probably should set up the rollover time +# and other aspects of the log to strike the balance between disk usage and log history + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/services/workflow/production.ini b/services/workflow/production.ini new file mode 100644 index 0000000000000000000000000000000000000000..d1430a9b8c25dff1eeacadaebf6bd3869bb15e5d --- /dev/null +++ b/services/workflow/production.ini @@ -0,0 +1,22 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:workflow + +session.cookie_expires = true +session.auto = true + +pyramid.reload_templates = false +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = pyramid_tm + + +[server:main] +use = egg:waitress#main +listen = 0.0.0.0:6543 diff --git a/services/workflow/setup.py b/services/workflow/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..fc677861a78142608b9af3e093d063d990f2c4a1 --- /dev/null +++ b/services/workflow/setup.py @@ -0,0 +1,104 @@ +"""A setuptools based setup module. + +See: +https://packaging.python.org/en/latest/distributing.html +https://github.com/pypa/sampleproject +""" +# To use a consistent encoding +from codecs import open +from os import path + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages + +# For matching the version string. +import re + +this_module = 'workflow' +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.txt'), encoding='utf-8') as f: + long_description = f.read() + + +def read(*parts): + with open(path.join(here, *parts), 'r') as fp: + return fp.read() + + +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^___version___ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +requires = [ + 'cornice', + 'pycapo', + 'pyramid', + 'pyramid_beaker', + 'pyramid_debugtoolbar', + 'pyramid_tm', + 'requests', + 'schema', + 'sqlalchemy', + 'waitress', + 'zope.sqlalchemy' +] + +setup( + name=this_module, + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version=find_version('src/' + this_module, '_version.py'), + + description='Workflow: the Workspaces Workflow Service', + long_description=long_description, + + # Author details + author='Daniel Lyons', + author_email='dlyons@nrao.edu', + + # Choose your license + license='GPL', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: GPL License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3.6', + ], + + install_requires=requires, + extras_require={ + 'dev': [ + 'pyramid_debugtoolbar', + ], + }, + package_dir={'': 'src'}, + packages=find_packages(), + entry_points={ + 'paste.app_factory': [ + 'main = workflow:main' + ], + }, +) diff --git a/services/workflow/src/workflow/__init__.py b/services/workflow/src/workflow/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..587758fdfe8269a8930781cc2ae257119b130618 --- /dev/null +++ b/services/workflow/src/workflow/__init__.py @@ -0,0 +1,23 @@ +from schema import create_engine +from pyramid.config import Configurator +from pyramid_beaker import session_factory_from_settings +from sqlalchemy.orm import scoped_session, sessionmaker +from zope.sqlalchemy import ZopeTransactionExtension +from pyramid.renderers import JSONP + +DB = {} + + +def main(global_config, **settings): + # DB['SDM'] = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) + + with Configurator(settings=settings) as config: + session_factory = session_factory_from_settings(settings) + config.include('cornice') + config.set_session_factory(session_factory) + config.add_renderer('jsonp', JSONP(param_name='callback')) + + config.include('pyramid_beaker') + + config.scan('workflow.workflow') + return config.make_wsgi_app() diff --git a/services/workflow/src/workflow/_version.py b/services/workflow/src/workflow/_version.py new file mode 100644 index 0000000000000000000000000000000000000000..f27d146a3f39885ce269bacf9ab4510254147c8d --- /dev/null +++ b/services/workflow/src/workflow/_version.py @@ -0,0 +1,2 @@ +""" Version information for this package, don't put anything else here. """ +___version___ = '4.0.0a1.dev1' diff --git a/services/workflow/src/workflow/workflow.py b/services/workflow/src/workflow/workflow.py new file mode 100644 index 0000000000000000000000000000000000000000..4ebc22599bd9e6e5a14f3a77c3aa21e7baa52a58 --- /dev/null +++ b/services/workflow/src/workflow/workflow.py @@ -0,0 +1,22 @@ +from cornice.resource import resource + + +WORKFLOWS = [{'id': 1, 'name': 'foo'}] + + +@resource(collection_path="/workflows", path="/workflows/{id}") +class Workflow: + def __init__(self, request, context=None): + self.request = request + + def collection_get(self): + return WORKFLOWS + + def collection_post(self): + WORKFLOWS.append(self.request.json_body) + return True + + def get(self): + return WORKFLOWS[int(self.request.matchdict['id'])] + + diff --git a/services/workflow/workflow.wsgi b/services/workflow/workflow.wsgi new file mode 100644 index 0000000000000000000000000000000000000000..d0452ee043312de9e5f3d2a1a85b1b5dced7392d --- /dev/null +++ b/services/workflow/workflow.wsgi @@ -0,0 +1,23 @@ +# workflow.wsgi +from pyramid.paster import get_app, setup_logging +import os + +import socket + +fqdn = socket.getfqdn() +if "mcilroy" in fqdn: + os.environ['CAPO_PROFILE'] = 'dsoc-prod' +elif "wirth" in fqdn: + os.environ['CAPO_PROFILE'] = 'nmtest' + #os.environ['CAPO_PROFILE'] = 'dsoc-dev' +elif "hamilton" in fqdn: + os.environ['CAPO_PROFILE'] = 'dsoc-test' +else: + os.environ['CAPO_PROFILE'] = 'local' + +# os.environ['CAPO_PROFILE'] = 'products' + +ini_path = os.path.dirname(__file__) + '/production.ini' + +setup_logging(ini_path) +application = get_app(ini_path, 'main')