#90 click for CLI options instead of os.getenv directly
This commit is contained in:
@@ -4,6 +4,7 @@ import gevent.monkey
|
||||
|
||||
gevent.monkey.patch_all()
|
||||
|
||||
import click
|
||||
import flask
|
||||
import functools
|
||||
import gevent
|
||||
@@ -26,25 +27,14 @@ from .kubernetes import get_kubernetes_clusters
|
||||
from .stores import MemoryStore, RedisStore
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_bool(name: str):
|
||||
return os.getenv(name, '').lower() in ('1', 'true')
|
||||
|
||||
|
||||
DEBUG = get_bool('DEBUG')
|
||||
SERVER_PORT = int(os.getenv('SERVER_PORT', 8080))
|
||||
DEFAULT_CLUSTERS = 'http://localhost:8001/'
|
||||
SERVER_STATUS = {'shutdown': False}
|
||||
AUTHORIZE_URL = os.getenv('AUTHORIZE_URL')
|
||||
APP_URL = os.getenv('APP_URL')
|
||||
MOCK = get_bool('MOCK')
|
||||
REDIS_URL = os.getenv('REDIS_URL')
|
||||
STORE = RedisStore(REDIS_URL) if REDIS_URL else MemoryStore()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.debug = DEBUG
|
||||
app.secret_key = os.getenv('SECRET_KEY', 'development')
|
||||
|
||||
oauth = OAuth(app)
|
||||
|
||||
@@ -88,19 +78,19 @@ def index():
|
||||
# cache busting for local development
|
||||
app_js += '?_={}'.format(time.time())
|
||||
else:
|
||||
logging.error('Could not find JavaScript application bundle app*.js in {}'.format(static_build_path))
|
||||
logger.error('Could not find JavaScript application bundle app*.js in {}'.format(static_build_path))
|
||||
flask.abort(503, 'JavaScript application bundle not found (missing build)')
|
||||
return flask.render_template('index.html', app_js=app_js)
|
||||
|
||||
|
||||
def event(cluster_ids: set):
|
||||
# first sent full data once
|
||||
for cluster_id in (STORE.get('cluster-ids') or []):
|
||||
for cluster_id in (app.store.get('cluster-ids') or []):
|
||||
if not cluster_ids or cluster_id in cluster_ids:
|
||||
cluster = STORE.get(cluster_id)
|
||||
cluster = app.store.get(cluster_id)
|
||||
yield 'event: clusterupdate\ndata: ' + json.dumps(cluster, separators=(',', ':')) + '\n\n'
|
||||
while True:
|
||||
for event_type, event_data in STORE.listen():
|
||||
for event_type, event_data in app.store.listen():
|
||||
# hacky, event_data can be delta or full cluster object
|
||||
if not cluster_ids or event_data.get('cluster_id', event_data.get('id')) in cluster_ids:
|
||||
yield 'event: ' + event_type + '\ndata: ' + json.dumps(event_data, separators=(',', ':')) + '\n\n'
|
||||
@@ -122,16 +112,16 @@ def get_events():
|
||||
def screen_tokens():
|
||||
new_token = None
|
||||
if flask.request.method == 'POST':
|
||||
new_token = STORE.create_screen_token()
|
||||
new_token = app.store.create_screen_token()
|
||||
return flask.render_template('screen-tokens.html', new_token=new_token)
|
||||
|
||||
|
||||
@app.route('/screen/<token>')
|
||||
def redeem_screen_token(token: str):
|
||||
remote_addr = flask.request.headers.get('X-Forwarded-For') or flask.request.remote_addr
|
||||
logging.info('Trying to redeem screen token "{}" for IP {}..'.format(token, remote_addr))
|
||||
logger.info('Trying to redeem screen token "{}" for IP {}..'.format(token, remote_addr))
|
||||
try:
|
||||
STORE.redeem_screen_token(token, remote_addr)
|
||||
app.store.redeem_screen_token(token, remote_addr)
|
||||
except:
|
||||
flask.abort(401)
|
||||
flask.session['auth_token'] = (token, '')
|
||||
@@ -164,32 +154,32 @@ def authorized():
|
||||
return redirect(urljoin(APP_URL, '/'))
|
||||
|
||||
|
||||
def update():
|
||||
def update(clusters: list, store, mock: bool):
|
||||
while True:
|
||||
lock = STORE.acquire_lock()
|
||||
lock = store.acquire_lock()
|
||||
if lock:
|
||||
try:
|
||||
if MOCK:
|
||||
clusters = get_mock_clusters()
|
||||
if mock:
|
||||
_clusters = get_mock_clusters()
|
||||
else:
|
||||
clusters = get_kubernetes_clusters()
|
||||
_clusters = get_kubernetes_clusters(clusters)
|
||||
cluster_ids = []
|
||||
for cluster in clusters:
|
||||
old_data = STORE.get(cluster['id'])
|
||||
for cluster in _clusters:
|
||||
old_data = store.get(cluster['id'])
|
||||
if old_data:
|
||||
# https://pikacode.com/phijaro/json_delta/ticket/11/
|
||||
# diff is extremely slow without array_align=False
|
||||
delta = json_delta.diff(old_data, cluster, verbose=DEBUG, array_align=False)
|
||||
STORE.publish('clusterdelta', {'cluster_id': cluster['id'], 'delta': delta})
|
||||
delta = json_delta.diff(old_data, cluster, verbose=app.debug, array_align=False)
|
||||
store.publish('clusterdelta', {'cluster_id': cluster['id'], 'delta': delta})
|
||||
else:
|
||||
STORE.publish('clusterupdate', cluster)
|
||||
STORE.set(cluster['id'], cluster)
|
||||
store.publish('clusterupdate', cluster)
|
||||
store.set(cluster['id'], cluster)
|
||||
cluster_ids.append(cluster['id'])
|
||||
STORE.set('cluster-ids', cluster_ids)
|
||||
store.set('cluster-ids', cluster_ids)
|
||||
except:
|
||||
logging.exception('Failed to update')
|
||||
logger.exception('Failed to update')
|
||||
finally:
|
||||
STORE.release_lock(lock)
|
||||
store.release_lock(lock)
|
||||
gevent.sleep(5)
|
||||
|
||||
|
||||
@@ -203,14 +193,30 @@ def shutdown():
|
||||
|
||||
|
||||
def exit_gracefully(signum, frame):
|
||||
logging.info('Received TERM signal, shutting down..')
|
||||
logger.info('Received TERM signal, shutting down..')
|
||||
SERVER_STATUS['shutdown'] = True
|
||||
gevent.spawn(shutdown)
|
||||
|
||||
|
||||
def main():
|
||||
@click.command(context_settings={'help_option_names': ['-h', '--help']})
|
||||
@click.option('-p', '--port', type=int, help='HTTP port to listen on (default: 8080)', envvar='SERVER_PORT', default=8080)
|
||||
@click.option('-d', '--debug', is_flag=True, help='Run in debugging mode', envvar='DEBUG')
|
||||
@click.option('-m', '--mock', is_flag=True, help='Mock Kubernetes clusters', envvar='MOCK')
|
||||
@click.option('--secret-key', help='Secret key for session cookies', envvar='SECRET_KEY', default='development')
|
||||
@click.option('--redis-url', help='Redis URL to use for pub/sub and job locking', envvar='REDIS_URL')
|
||||
@click.option('--clusters', help='Comma separated list of Kubernetes API server URLs (default: {})'.format(DEFAULT_CLUSTERS),
|
||||
envvar='CLUSTERS', default=DEFAULT_CLUSTERS)
|
||||
def main(port, debug, mock, secret_key, redis_url, clusters):
|
||||
logging.basicConfig(level=logging.DEBUG if debug else logging.INFO)
|
||||
|
||||
store = RedisStore(redis_url) if redis_url else MemoryStore()
|
||||
|
||||
app.debug = debug
|
||||
app.secret_key = secret_key
|
||||
app.store = store
|
||||
|
||||
signal.signal(signal.SIGTERM, exit_gracefully)
|
||||
http_server = gevent.wsgi.WSGIServer(('0.0.0.0', SERVER_PORT), app)
|
||||
gevent.spawn(update)
|
||||
logging.info('Listening on :{}..'.format(SERVER_PORT))
|
||||
http_server = gevent.wsgi.WSGIServer(('0.0.0.0', port), app)
|
||||
gevent.spawn(update, clusters=clusters.split(','), store=store, mock=mock)
|
||||
logger.info('Listening on :{}..'.format(port))
|
||||
http_server.serve_forever()
|
||||
|
||||
Reference in New Issue
Block a user