Skip to content

Commit ef3fedc

Browse files
committed
Working on making app storage backends more pluggable
1 parent 0820eda commit ef3fedc

File tree

4 files changed

+103
-62
lines changed

4 files changed

+103
-62
lines changed

tests/unuo_tests.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import unittest
22
import json
33
import logging
4+
import tempfile
5+
import shutil
46

57
from unuo.factories import default_factory
68

@@ -12,10 +14,25 @@
1214
class UnuoTests(unittest.TestCase):
1315

1416
def setUp(self):
17+
from unuo.config import config
18+
self.buildfolder = tempfile.mkdtemp()
19+
logger.info('Created temp build dir %s', self.buildfolder)
20+
self.logfolder = tempfile.mkdtemp()
21+
logger.info('Created temp log dir %s', self.logfolder)
22+
23+
config.builds_folder = self.buildfolder
24+
config.logs_folder = self.logfolder
25+
1526
app = default_factory()
1627
self.app = app.test_client()
1728

29+
def tearDown(self):
30+
logger.info('Removing temp build dir %s', self.buildfolder)
31+
shutil.rmtree(self.buildfolder)
32+
logger.info('Removing temp log dir %s', self.logfolder)
33+
shutil.rmtree(self.logfolder)
34+
1835
def test_profiles(self):
1936
rv = self.app.get('/profile')
2037
j = json.loads(rv.data)
21-
self.assertEquals({u'builds': [u'mynewbuild']}, j)
38+
self.assertEquals({u'builds': []}, j)

unuo/blueprints/docker.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,28 @@
33
Contains API methods for kicking off a build profile, adding a build profile,
44
getting a listing of build profiles.
55
"""
6+
import logging
7+
68
from flask import Blueprint
79
from flask import jsonify, request
810
from unuo.errors import ApiError
911

10-
from unuo.filebackend import post_build, run_build, get_build_profile, \
11-
get_all_profiles
12-
1312
docker_bp = Blueprint('docker', __name__)
1413

14+
logger = logging.getLogger('test')
15+
16+
backend = None
17+
18+
19+
def inject_backend(_backend):
20+
global backend
21+
logger.info('Injecting backend %s', _backend)
22+
backend = _backend
23+
24+
# @docker_bp.errorhandler(500)
25+
# def error_ise(error):
26+
# return '{"status_code":500,"description":"oh noes!"}', 500
1527

16-
#@docker_bp.errorhandler(500)
17-
#def error_ise(error):
18-
# return '{"status_code":500,"description":"oh noes!"}', 500
19-
#
2028

2129
@docker_bp.errorhandler(404)
2230
@docker_bp.errorhandler(400)
@@ -30,19 +38,19 @@ def error_json(error):
3038
@docker_bp.route('/build/<name>', methods=['POST'])
3139
def build(name):
3240
"""Run given build."""
33-
return run_build(name)
41+
return backend.run_build(name)
3442

3543

3644
@docker_bp.route('/profile', methods=['GET'])
3745
def list_build_profiles():
3846
"""Responsible for listing known builds."""
39-
builds = get_all_profiles()
47+
builds = backend.get_all_profiles()
4048
return jsonify({"builds": builds})
4149

4250

4351
@docker_bp.route('/profile/<name>', methods=['GET', 'POST'])
4452
def build_container(name):
4553
"""Responsible for creating/updating builds and launching them."""
4654
if request.method == 'POST':
47-
return post_build(name, request.json)
48-
return jsonify(**get_build_profile(name))
55+
return backend.post_build(name, request.json)
56+
return jsonify(**backend.get_build_profile(name))

unuo/factories.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
"""Flask factories for running the app and testing it.
22
"""
3+
import logging
34

45
from flask import Flask
56

67
from unuo.blueprints.docker import docker_bp
8+
from unuo.filebackend import FileBackend
9+
from unuo.config import config
710

11+
logger = logging.getLogger(__name__)
812

9-
def default_factory(config=None):
13+
14+
def default_factory(conf_env=None, conf_dict=None):
15+
from unuo.blueprints.docker import inject_backend
1016
app = Flask(__name__)
1117
app.config.from_object('unuo.config.DefaultConfig')
18+
if conf_dict:
19+
app.config.update(**conf_dict)
20+
if conf_env:
21+
app.config.from_envvar(conf_env)
22+
inject_backend(FileBackend(config.builds_folder))
1223
app.register_blueprint(docker_bp)
1324
return app

unuo/filebackend.py

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,57 @@
1212
from unuo.models import build_schema, Build
1313
from unuo.errors import ApiError
1414
from unuo.docker import do_build
15-
from unuo.config import config
16-
17-
18-
def post_build(name, json):
19-
"""Create or update a build."""
20-
try:
21-
build_schema(json)
22-
except MultipleInvalid as e:
23-
raise ApiError('; '.join([str(i) for i in e.errors]))
24-
build_file = os.path.join(config.builds_folder, name)
25-
exists = os.path.exists(build_file)
26-
with open(build_file, 'w') as fd:
27-
json.dump(json, fd)
28-
if exists:
29-
return "build updated!"
30-
return "build created!"
31-
32-
33-
def get_build_profile(name):
34-
"""Return build profile with given name."""
35-
build_file = os.path.join(config.builds_folder, name)
36-
if not os.path.exists(build_file):
37-
raise ApiError("Build profile '%s' not found" % name, code=404)
38-
with open(build_file, 'r') as fd:
39-
build_json = json.load(fd)
40-
return build_json
41-
42-
43-
def run_build(name):
44-
"""Kick off a build."""
45-
build_json = get_build_profile(name)
46-
build = Build(name, **build_json)
47-
48-
def generate():
49-
for line in do_build(build):
50-
yield line
51-
return Response(generate(), mimetype='text/plain')
52-
53-
54-
def get_all_profiles():
55-
builds = []
56-
print config.builds_folder
57-
for phile in listdir(config.builds_folder):
58-
print phile
59-
fp = os.path.join(config.builds_folder, phile)
60-
if not os.path.isfile(fp):
61-
continue
62-
builds.append(phile)
63-
return builds
15+
16+
17+
class FileBackend(object):
18+
"""A file based backend for Unuo objects"""
19+
20+
def __init__(self, builds_folder):
21+
self.builds_folder = builds_folder
22+
23+
def post_build(self, name, json):
24+
"""Create or update a build."""
25+
try:
26+
build_schema(json)
27+
except MultipleInvalid as e:
28+
raise ApiError('; '.join([str(i) for i in e.errors]))
29+
build_file = os.path.join(self.builds_folder, name)
30+
exists = os.path.exists(build_file)
31+
with open(build_file, 'w') as fd:
32+
json.dump(json, fd)
33+
if exists:
34+
return "build updated!"
35+
return "build created!"
36+
37+
def get_build_profile(self, name):
38+
"""Return build profile with given name."""
39+
build_file = os.path.join(self.builds_folder, name)
40+
if not os.path.exists(build_file):
41+
raise ApiError("Build profile '%s' not found" % name, code=404)
42+
with open(build_file, 'r') as fd:
43+
build_json = json.load(fd)
44+
return build_json
45+
46+
def run_build(self, name):
47+
"""Kick off a build.
48+
49+
Returns a Flask Response generator which allows for streaming console
50+
output back to browser/agent.
51+
"""
52+
build_json = self.get_build_profile(name)
53+
build = Build(name, **build_json)
54+
55+
def generate():
56+
for line in do_build(build):
57+
yield line
58+
return Response(generate(), mimetype='text/plain')
59+
60+
def get_all_profiles(self):
61+
"""Return back a list of the builds."""
62+
builds = []
63+
for phile in listdir(self.builds_folder):
64+
fp = os.path.join(self.builds_folder, phile)
65+
if not os.path.isfile(fp):
66+
continue
67+
builds.append(phile)
68+
return builds

0 commit comments

Comments
 (0)