Source code for pyfarm.master.api.agent_updates

# No shebang line, this module is meant to be imported
#
# Copyright 2014 Ambient Entertainment Gmbh & Co. KG
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Agent Updates
-------------

The API allows access to agent update packages, possibly through redirects
"""
import re
import tempfile
from os import makedirs
from os.path import join, isfile
from errno import EEXIST

try:
    from httplib import BAD_REQUEST, CREATED, NOT_FOUND
except ImportError:  # pragma: no cover
    from http.client import BAD_REQUEST, CREATED, NOT_FOUND

from flask.views import MethodView
from flask import request, redirect, send_file

from pyfarm.core.logger import getLogger
from pyfarm.master.config import config
from pyfarm.master.utility import jsonify

logger = getLogger("api.agents")

VERSION_REGEX = re.compile("\d+(\.\d+(\.\d+)?)?((-pre\d?)|(-dev\d?)|(-rc?\d?)|"
                           "(-alpha\d?)|(-beta\d?))?$")

UPDATES_DIR = config.get("agent_updates_dir")
UPDATES_WEBDIR = config.get("agent_updates_webdir")


try:
    makedirs(UPDATES_DIR)
except OSError as e:  # pragma: no cover
    if e.errno != EEXIST:
        raise


[docs]class AgentUpdatesAPI(MethodView):
[docs] def put(self, version): """ A ``PUT`` to this endpoint will upload a new version of pyfarm-agent to be used for agent auto-updates. The update must be a zip file. .. http:put:: /api/v1/agents/updates/<string:version> HTTP/1.1 **Request** .. sourcecode:: http PUT /api/v1/agents/updates/1.2.3 HTTP/1.1 Content-Type: application/zip <binary data> **Response** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json :statuscode 201: The update was put in place :statuscode 400: there was something wrong with the request (such as an invalid version number specified or the mime type not being application/zip) """ if request.mimetype != "application/zip": return (jsonify(error="Data for agent updates must be " "application/zip"), BAD_REQUEST) if not VERSION_REGEX.match(version): return (jsonify(error="Version is not an acceptable version number"), BAD_REQUEST) path = join(UPDATES_DIR, "pyfarm-agent-%s.zip" % version) with open(path, "wb+") as zip_file: zip_file.write(request.data) return "", CREATED
[docs] def get(self, version): """ A ``GET`` to this endpoint will return the update package as a zip file the specified version .. http:get:: /api/v1/agents/updates/<string:version> HTTP/1.1 **Request** .. sourcecode:: http PUT /api/v1/agents/updates/1.2.3 HTTP/1.1 Accept: application/zip **Response** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/zip <binary data> :statuscode 200: The update file was found and is returned :statuscode 301: The update can be found under a different URL :statuscode 400: there was something wrong with the request (such as an invalid version number specified or the mime type not being application/zip) """ if not VERSION_REGEX.match(version): return (jsonify(error="Version is not an acceptable version number"), BAD_REQUEST) filename = "pyfarm-agent-%s.zip" % version if UPDATES_WEBDIR: return redirect(join(UPDATES_WEBDIR, filename)) update_file = join(UPDATES_DIR, filename) if not isfile(update_file): return (jsonify(error="Specified update not found"), NOT_FOUND) return send_file(update_file)