Skip to content

Commit

Permalink
Remove manual env var parsing from Watchman
Browse files Browse the repository at this point in the history
Use Click arguments instead with environment variable associations
  • Loading branch information
milesgranger committed Jan 11, 2019
1 parent e70db0a commit fbb9a2d
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 46 deletions.
13 changes: 9 additions & 4 deletions gordo_components/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
'''

import logging
import ast
import os
from ast import literal_eval

Expand Down Expand Up @@ -82,9 +83,13 @@ def run_server_cli(host, port):


@click.command('run-watchman')
@click.option('--host', type=str, help='The host to run the server on.')
@click.option('--port', type=int, help='The port to run the server on.')
def run_watchman_cli(host, port):
@click.argument('project-name', envvar='PROJECT_NAME', type=str)
@click.argument('target-names', envvar='TARGET_NAMES', type=ast.literal_eval)
@click.argument('target-names-sanitized', envvar='TARGET_NAMES_SANITIZED', type=ast.literal_eval)
@click.option('--host', type=str, help='The host to run the server on.', default='0.0.0.0')
@click.option('--port', type=int, help='The port to run the server on.', default=5555)
@click.option('--debug', type=bool, help='Run in debug mode', default=False)
def run_watchman_cli(project_name, target_names, target_names_sanitized, host, port, debug):
"""
Start the Gordo Watchman server for this project. Which is responsible
for dynamically comparing expected URLs derived from a project config fle
Expand All @@ -96,7 +101,7 @@ def run_watchman_cli(host, port):
TARGET_NAMES: A list of non-sanitized machine / target names
TARGET_NAMES_SANITIZED: Same list of names, only sanitized
"""
watchman.server.run_server(host, port)
watchman.server.run_server(host, port, debug, project_name, target_names, target_names_sanitized)


gordo.add_command(build)
Expand Down
57 changes: 22 additions & 35 deletions gordo_components/watchman/server.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# -*- coding: utf-8 -*-

import os
import yaml
import ast
import requests
import logging
from typing import Iterable
from flask import Flask, jsonify, make_response
from flask.views import MethodView
from concurrent.futures import ThreadPoolExecutor
Expand All @@ -15,6 +13,8 @@
# Will contain a list of endpoints to expected models via Ambassador
# see _load_endpoints()
ENDPOINTS = None
PROJECT_NAME = None
TARGET_NAMES = None


logger = logging.getLogger(__name__)
Expand All @@ -41,7 +41,7 @@ def get(self):
# List of dicts: [{'endpoint': /path/to/endpoint, 'healthy': bool}]
results = [{'endpoint': futures[f], 'healthy': f.result()} for f in futures]

payload = jsonify({'endpoints': results, 'project_name': os.environ['PROJECT_NAME']})
payload = jsonify({'endpoints': results, 'project_name': PROJECT_NAME})
resp = make_response(payload, 200)
resp.headers['Cache-Control'] = 'max-age=0'
return resp
Expand All @@ -51,48 +51,35 @@ def healthcheck():
"""
Return gordo version, route for Watchman server
"""
payload = jsonify({'version': __version__, 'config': yaml.load(os.environ['TARGET_NAMES'])})
payload = jsonify({'version': __version__, 'config': TARGET_NAMES})
return payload, 200


def build_app():
def build_app(project_name: str, target_names: Iterable[str], target_names_sanitized: Iterable[str]):
"""
Build app and any associated routes
"""
global ENDPOINTS
ENDPOINTS = _load_endpoints()

# Precompute list of expected endpoints from config file and other global env
global ENDPOINTS, PROJECT_NAME, TARGET_NAMES
ENDPOINTS = [f'/gordo/v0/{project_name}/{sanitized_name}/healthcheck'
for sanitized_name in target_names_sanitized]
PROJECT_NAME = project_name
TARGET_NAMES = target_names

# App and routes
app = Flask(__name__)
app.add_url_rule(rule='/healthcheck', view_func=healthcheck, methods=['GET'])
app.add_url_rule(rule='/', view_func=WatchmanApi.as_view('sentinel_api'), methods=['GET'])
return app


def run_server(host: str = '0.0.0.0', port: int = 5555, debug: bool = False):
app = build_app()
app.run(host, port, debug=debug)


def _load_endpoints():
"""
Given the current environment vars of TARGET_NAMES, PROJECT_NAME, AMBASSADORHOST and PORT: build a list
of pre-computed expected endpoints
"""
if 'TARGET_NAMES_SANITIZED' not in os.environ or 'TARGET_NAMES' not in os.environ:
raise EnvironmentError('Need to have TARGET_NAMES_SANITIZED and TARGET_NAMES environment variables set as a'
' list of expected, sanitized and non-sanitized target / machine names.')
if 'PROJECT_NAME' not in os.environ:
raise EnvironmentError('Need to have PROJECT_NAME environment variable set.')

TARGET_NAMES_SANITIZED = ast.literal_eval(os.environ['TARGET_NAMES_SANITIZED'])
_TARGET_NAMES = ast.literal_eval(os.environ['TARGET_NAMES'])
project_name = os.environ["PROJECT_NAME"]

# Precompute list of expected endpoints from config file
endpoints = [f'/gordo/v0/{project_name}/{sanitized_name}/healthcheck'
for sanitized_name in TARGET_NAMES_SANITIZED]
return endpoints
def run_server(host: str,
port: int,
debug: bool,
project_name: str,
target_names: Iterable[str],
target_names_sanitized: Iterable[str]):


if __name__ == '__main__':
run_server()
app = build_app(project_name, target_names, target_names_sanitized)
app.run(host, port, debug=debug)
8 changes: 1 addition & 7 deletions tests/test_watchman.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@

from gordo_components import __version__
from gordo_components.watchman import server
from tests.utils import temp_env_vars


TARGET_NAMES = ['CT-machine-name-456', 'CT-machine-name-123']
TARGET_NAMES_STR = str(TARGET_NAMES)
TARGET_NAMES_SANITIZED = ['ct-machine-name-456-kn209d', 'ct-machine-name-123-ksno0s9f092']
TARGET_NAMES_SANITIZED_STR = str(TARGET_NAMES_SANITIZED)
PROJECT_NAME = 'some-project-name'
AMBASSADORHOST = 'ambassador'
URL_FORMAT = 'http://{host}/gordo/v0/{project_name}/{sanitized_name}/healthcheck'
Expand All @@ -30,20 +27,17 @@ def request_callback(_request):

class WatchmanTestCase(unittest.TestCase):

@temp_env_vars(TARGET_NAMES=TARGET_NAMES_STR, TARGET_NAMES_SANITIZED=TARGET_NAMES_SANITIZED_STR, PROJECT_NAME=PROJECT_NAME)
def setUp(self):
app = server.build_app()
app = server.build_app(project_name=PROJECT_NAME, target_names=TARGET_NAMES, target_names_sanitized=TARGET_NAMES_SANITIZED)
app.testing = True
self.app = app.test_client()

@temp_env_vars(TARGET_NAMES=TARGET_NAMES_STR, TARGET_NAMES_SANITIZED=TARGET_NAMES_SANITIZED_STR, PROJECT_NAME=PROJECT_NAME)
def test_healthcheck(self):
resp = self.app.get('/healthcheck')
self.assertEqual(resp.status_code, 200)
resp = resp.get_json()
self.assertTrue('version' in resp)

@temp_env_vars(TARGET_NAMES=TARGET_NAMES_STR, TARGET_NAMES_SANITIZED=TARGET_NAMES_SANITIZED_STR, PROJECT_NAME=PROJECT_NAME)
@responses.activate
def test_api(self):
"""
Expand Down

0 comments on commit fbb9a2d

Please sign in to comment.