diff --git a/faafo/bin/faafo b/faafo/bin/faafo old mode 100644 new mode 100755 index a90f50f..eceee54 --- a/faafo/bin/faafo +++ b/faafo/bin/faafo @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -import copy import json import random import uuid @@ -75,13 +74,19 @@ def get_random_task(): float(CONF.command.max_yb)) task = { - 'uuid': str(uuid.uuid4()), - 'width': width, - 'height': height, - 'iterations': iterations, 'xa': xa, - 'xb': xb, - 'ya': ya, - 'yb': yb + 'data': { + 'type': 'fractal', + 'attributes': { + 'uuid': str(uuid.uuid4()), + 'width': width, + 'height': height, + 'iterations': iterations, + 'xa': xa, + 'xb': xb, + 'ya': ya, + 'yb': yb + } + } } return task @@ -93,25 +98,31 @@ def do_get_fractal(): def do_show_fractal(): LOG.info("showing fractal %s" % CONF.command.uuid) + headers = {'Content-Type': 'application/vnd.api+json', + 'Accept': 'application/vnd.api+json'} result = requests.get("%s/v1/fractal/%s" % - (CONF.endpoint_url, CONF.command.uuid)) + (CONF.endpoint_url, CONF.command.uuid), + headers=headers) + LOG.debug("result: %s" % result.text) + if result.status_code == 200: data = json.loads(result.text) + fractal_data = data['data']['attributes'] output = PrettyTable(["Parameter", "Value"]) output.align["Parameter"] = "l" output.align["Value"] = "l" - output.add_row(["uuid", data['uuid']]) - output.add_row(["duration", "%f seconds" % data['duration']]) + output.add_row(["uuid", fractal_data['uuid']]) + output.add_row(["duration", "%f seconds" % fractal_data['duration']]) output.add_row(["dimensions", "%d x %d pixels" % - (data['width'], data['height'])]) - output.add_row(["iterations", data['iterations']]) - output.add_row(["xa", data['xa']]) - output.add_row(["xb", data['xb']]) - output.add_row(["ya", data['ya']]) - output.add_row(["yb", data['yb']]) - output.add_row(["size", "%d bytes" % data['size']]) - output.add_row(["checksum", data['checksum']]) - output.add_row(["generated_by", data['generated_by']]) + (fractal_data['width'], fractal_data['height'])]) + output.add_row(["iterations", fractal_data['iterations']]) + output.add_row(["xa", fractal_data['xa']]) + output.add_row(["xb", fractal_data['xb']]) + output.add_row(["ya", fractal_data['ya']]) + output.add_row(["yb", fractal_data['yb']]) + output.add_row(["size", "%d bytes" % fractal_data['size']]) + output.add_row(["checksum", fractal_data['checksum']]) + output.add_row(["generated_by", fractal_data['generated_by']]) print(output) else: LOG.error("fractal '%s' not found" % CONF.command.uuid) @@ -123,34 +134,43 @@ def do_list_fractals(): fractals = get_fractals() output = PrettyTable(["UUID", "Dimensions", "Filesize"]) for fractal in fractals: + fractal_data = fractal['attributes'] output.add_row([ - fractal["uuid"], - "%d x %d pixels" % (fractal["width"], fractal["height"]), - "%d bytes" % (fractal["size"] or 0), + fractal_data["uuid"], + "%d x %d pixels" % (fractal_data["width"], fractal_data["height"]), + "%d bytes" % (fractal_data["size"] or 0), ]) print(output) def get_fractals(page=1): - result = requests.get("%s/v1/fractal?page=%d" % - (CONF.endpoint_url, page)) + headers = {'Content-Type': 'application/vnd.api+json', + 'Accept': 'application/vnd.api+json'} + result = requests.get("%s/v1/fractal?page=%d&page[size]=10" % + (CONF.endpoint_url, page), + headers=headers) + LOG.debug("result: %s" % result.text) + fractals = [] if result.status_code == 200: data = json.loads(result.text) - if page < data['total_pages']: - fractals = data['objects'] + get_fractals(page + 1) + if (page * 10) < data['meta']['total']: + fractals = data['data'] + get_fractals(page + 1) else: - return data['objects'] + return data['data'] return fractals def do_delete_fractal(): LOG.info("deleting fractal %s" % CONF.command.uuid) + headers = {'Content-Type': 'application/vnd.api+json', + 'Accept': 'application/vnd.api+json'} result = requests.delete("%s/v1/fractal/%s" % - (CONF.endpoint_url, CONF.command.uuid)) - LOG.debug("result: %s" %result) + (CONF.endpoint_url, CONF.command.uuid), + headers=headers) + LOG.debug("result: %s" % result.text) def do_create_fractal(): @@ -164,11 +184,11 @@ def do_create_fractal(): for i in range(0, number): task = get_random_task() LOG.debug("created task %s" % task) - # NOTE(berendt): only necessary when using requests < 2.4.2 - headers = {'Content-type': 'application/json', - 'Accept': 'text/plain'} - requests.post("%s/v1/fractal" % CONF.endpoint_url, + headers = {'Content-Type': 'application/vnd.api+json', + 'Accept': 'application/vnd.api+json'} + resp = requests.post("%s/v1/fractal" % CONF.endpoint_url, json.dumps(task), headers=headers) + LOG.debug("resp: %s" % resp.text) def add_command_parsers(subparsers): diff --git a/faafo/contrib/install-aws.sh b/faafo/contrib/install-aws.sh old mode 100644 new mode 100755 index 309f916..b7515a5 --- a/faafo/contrib/install-aws.sh +++ b/faafo/contrib/install-aws.sh @@ -107,6 +107,10 @@ if [[ -e /etc/os-release ]]; then if [[ $INSTALL_MESSAGING -eq 1 ]]; then if [[ $ID = 'ubuntu' || $ID = 'debian' ]]; then sudo apt-get install -y rabbitmq-server + # fixes for rabbitmq setup + sudo rabbitmqctl add_user faafo guest + sudo rabbitmqctl set_user_tags faafo administrator + sudo rabbitmqctl set_permissions -p / faafo ".*" ".*" ".*" elif [[ $ID = 'fedora' ]]; then # fedora currently not tested nor supported sudo dnf install -y rabbitmq-server diff --git a/faafo/contrib/install.sh b/faafo/contrib/install.sh old mode 100644 new mode 100755 index 0ac9f8c..b763407 --- a/faafo/contrib/install.sh +++ b/faafo/contrib/install.sh @@ -107,6 +107,10 @@ if [[ -e /etc/os-release ]]; then if [[ $INSTALL_MESSAGING -eq 1 ]]; then if [[ $ID = 'ubuntu' || $ID = 'debian' ]]; then sudo apt-get install -y rabbitmq-server + # fixes for rabbitmq setup + sudo rabbitmqctl add_user faafo guest + sudo rabbitmqctl set_user_tags faafo administrator + sudo rabbitmqctl set_permissions -p / faafo ".*" ".*" ".*" elif [[ $ID = 'fedora' ]]; then # fedora currently not tested nor supported sudo dnf install -y rabbitmq-server diff --git a/faafo/faafo/api/service.py b/faafo/faafo/api/service.py index f0c7178..00f2e98 100644 --- a/faafo/faafo/api/service.py +++ b/faafo/faafo/api/service.py @@ -13,6 +13,7 @@ import base64 import copy import io +import socket from pkg_resources import resource_filename import flask @@ -109,10 +110,11 @@ connection = Connection(CONF.transport_url) @app.route('/index', methods=['GET']) @app.route('/index/', methods=['GET']) def index(page=1): + hostname = socket.gethostname() fractals = Fractal.query.filter( (Fractal.checksum != None) & (Fractal.size != None)).paginate( page=page, per_page=5) - return flask.render_template('index.html', fractals=fractals) + return flask.render_template('index.html', fractals=fractals, hostname=hostname) @app.route('/fractal/', methods=['GET']) @@ -124,8 +126,8 @@ def get_fractal(fractalid): response.status_code = 404 else: image_data = base64.b64decode(fractal.image) - image = Image.open(io.StringIO(image_data)) - output = io.StringIO() + image = Image.open(io.BytesIO(image_data)) + output = io.BytesIO() image.save(output, "PNG") image.seek(0) response = flask.make_response(output.getvalue()) @@ -135,6 +137,7 @@ def get_fractal(fractalid): def generate_fractal(**kwargs): + print("Postprocessor called!" + str(kwargs)) with producers[connection].acquire(block=True) as producer: producer.publish(kwargs['result'], serializer='json', @@ -142,11 +145,22 @@ def generate_fractal(**kwargs): declare=[queues.task_exchange], routing_key='normal') +def convert_image_to_binary(**kwargs): + print("Preprocessor call: " + str(kwargs)) + if 'image' in kwargs['data']['data']['attributes']: + print("Converting image to binary...") + kwargs['data']['data']['attributes']['image'] = str(kwargs['data']['data']['attributes']['image']).encode("ascii") + #print("Preprocessor called!" + str(kwargs)) + #return kwargs def main(): + print("Starting API server - new...") with app.app_context(): - manager.create_api(Fractal, methods=['GET', 'POST', 'DELETE', 'PUT'], - postprocessors={'POST': [generate_fractal]}, + manager.create_api(Fractal, methods=['GET', 'POST', 'DELETE', 'PATCH'], + postprocessors={'POST_RESOURCE': [generate_fractal]}, + preprocessors={'PATCH_RESOURCE': [convert_image_to_binary]}, exclude=['image'], - url_prefix='/v1') - app.run(host=CONF.listen_address, port=CONF.bind_port) + url_prefix='/v1', + allow_client_generated_ids=True) + app.run(host=CONF.listen_address, port=CONF.bind_port, debug=True) + diff --git a/faafo/faafo/api/templates/index.html b/faafo/faafo/api/templates/index.html index cc4a44a..acc946f 100644 --- a/faafo/faafo/api/templates/index.html +++ b/faafo/faafo/api/templates/index.html @@ -57,4 +57,14 @@ yb = {{ fractal.yb }} {% endfor %} {{render_pagination(fractals)}} + +
+ Rendered by server: {{hostname}} +
{% endblock %} diff --git a/faafo/faafo/worker/service.py b/faafo/faafo/worker/service.py index d1bb193..0ab6ce6 100644 --- a/faafo/faafo/worker/service.py +++ b/faafo/faafo/worker/service.py @@ -110,7 +110,8 @@ class Worker(ConsumerMixin): accept=['json'], callbacks=[self.process])] - def process(self, task, message): + def process(self, task_def, message): + task = task_def['data']['attributes'] LOG.info("processing task %s" % task['uuid']) LOG.debug(task) start_time = time.time() @@ -136,21 +137,27 @@ class Worker(ConsumerMixin): LOG.debug("removed temporary file %s" % filename) result = { - 'uuid': task['uuid'], - 'duration': elapsed_time, - 'image': image, - 'checksum': checksum, - 'size': size, - 'generated_by': socket.gethostname() + 'data': { + 'type': 'fractal', + 'id': task['uuid'], + 'attributes': { + 'uuid': task['uuid'], + 'duration': elapsed_time, + 'image': image.decode("ascii"), + 'checksum': checksum, + 'size': size, + 'generated_by': socket.gethostname() + } + } } - # NOTE(berendt): only necessary when using requests < 2.4.2 - headers = {'Content-type': 'application/json', - 'Accept': 'text/plain'} - - requests.put("%s/v1/fractal/%s" % + headers = {'Content-Type': 'application/vnd.api+json', + 'Accept': 'application/vnd.api+json'} + + resp = requests.patch("%s/v1/fractal/%s" % (CONF.endpoint_url, str(task['uuid'])), json.dumps(result), headers=headers) + LOG.debug("Result: %s" % resp.text) message.ack() return result