-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
921eba0
commit 3ead40f
Showing
3 changed files
with
183 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
if __name__ == "__main__": | ||
from .app import main | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
"""Webservice API.""" | ||
|
||
import logging | ||
import os | ||
import socket | ||
import typing as tp | ||
from pathlib import Path | ||
from urllib.parse import urlsplit, urlunsplit | ||
|
||
from jinja2 import Environment, ChoiceLoader, FileSystemLoader, PackageLoader | ||
from tornado import ioloop, web | ||
from tornado.log import access_log, app_log, gen_log | ||
from traitlets import Dict, Int, List, Unicode, default, validate | ||
from traitlets.config.application import Application | ||
from jupyterhub.utils import url_path_join | ||
|
||
if os.environ.get("JUPYTERHUB_API_TOKEN"): | ||
from jupyterhub.services.auth import HubOAuthCallbackHandler | ||
else: | ||
|
||
class HubOAuthCallbackHandler: | ||
def get(self): | ||
pass | ||
|
||
|
||
HERE = Path(__file__).parent | ||
|
||
|
||
class TljhRepo2Docker(Application): | ||
|
||
name = Unicode("tljh-repo2docker") | ||
|
||
version = "1.0.0" | ||
|
||
port = Int(6789, help="Port of the service", config=True) | ||
|
||
api_prefix = Unicode(help="JupyterHub service prefix", config=True) | ||
|
||
@default("api_prefix") | ||
def _default_api_prefix(self): | ||
return os.environ.get("JUPYTERHUB_SERVICE_PREFIX", "/") | ||
|
||
ip = Unicode( | ||
"localhost", | ||
config=True, | ||
help="The IP address of the service.", | ||
) | ||
|
||
@default("ip") | ||
def _default_ip(self): | ||
"""Return localhost if available, 127.0.0.1 otherwise.""" | ||
s = socket.socket() | ||
try: | ||
s.bind(("localhost", 0)) | ||
except socket.error as e: | ||
self.log.warning( | ||
"Cannot bind to localhost, using 127.0.0.1 as default ip\n%s", e | ||
) | ||
return "127.0.0.1" | ||
else: | ||
s.close() | ||
return "localhost" | ||
|
||
@validate("ip") | ||
def _validate_ip(self, proposal): | ||
value = proposal["value"] | ||
if value == "*": | ||
value = "" | ||
return value | ||
|
||
template_paths = List( | ||
trait=Unicode, | ||
default_value=None, | ||
allow_none=True, | ||
help="Paths to search for jinja templates, before using the default templates.", | ||
config=True, | ||
) | ||
|
||
tornado_settings = Dict( | ||
{}, | ||
config=True, | ||
help="Extra settings to apply to tornado application, e.g. headers, ssl, etc", | ||
) | ||
|
||
@default("log_level") | ||
def _default_log_level(self): | ||
return logging.INFO | ||
|
||
def init_settings(self) -> tp.Dict: | ||
"""Initialize settings for the service application.""" | ||
static_path = str(HERE / "static") | ||
static_url_prefix = self.api_prefix + "static/" | ||
env_opt = {"autoescape": True} | ||
|
||
env = Environment( | ||
loader=PackageLoader("tljh_repo2docker"), | ||
**env_opt, | ||
) | ||
|
||
settings = dict( | ||
log=self.log, | ||
template_path=str(HERE / "templates"), | ||
static_path=static_path, | ||
static_url_prefix=static_url_prefix, | ||
jinja2_env=env, | ||
cookie_secret=os.urandom(32), | ||
) | ||
return settings | ||
|
||
def init_handlers(self) -> tp.List: | ||
"""Initialize handlers for service application.""" | ||
handlers = [] | ||
static_path = str(HERE / "static") | ||
handlers.extend( | ||
[ | ||
( | ||
url_path_join(self.api_prefix, r"/static/(.*)"), | ||
web.StaticFileHandler, | ||
{"path": static_path}, | ||
), | ||
(self.api_prefix + "oauth_callback", HubOAuthCallbackHandler), | ||
] | ||
) | ||
|
||
return handlers | ||
|
||
def make_app(self) -> web.Application: | ||
"""Create the tornado web application. | ||
Returns: | ||
The tornado web application. | ||
""" | ||
|
||
application = web.Application() | ||
application.listen(self.port, self.ip) | ||
return application | ||
|
||
def start(self): | ||
"""Start the server.""" | ||
settings = self.init_settings() | ||
|
||
self.app = web.Application(**settings) | ||
self.app.settings.update(self.tornado_settings) | ||
handlers = self.init_handlers() | ||
self.app.add_handlers(".*$", handlers) | ||
|
||
self.app.listen(self.port, self.ip) | ||
self.ioloop = ioloop.IOLoop.current() | ||
try: | ||
self.log.info( | ||
f"tljh-repo2docker service listening on {self.ip}:{self.port}" | ||
) | ||
self.log.info("Press Ctrl+C to stop") | ||
self.ioloop.start() | ||
except KeyboardInterrupt: | ||
self.log.info("Stopping...") | ||
|
||
|
||
main = TljhRepo2Docker.launch_instance |