diff options
author | Ed Bartosh <ed.bartosh@linux.intel.com> | 2015-09-28 21:45:22 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-09-29 13:44:48 +0100 |
commit | 84be400237173970716616eeab6a37d776aa011b (patch) | |
tree | d9147e34a5fd3a428bda8d28ef39f8c5e2455dc1 | |
parent | 076945ea026091dc709f7cfea01ef119d0572bf3 (diff) | |
download | bitbake-84be400237173970716616eeab6a37d776aa011b.zip |
toaster: Add new ReST API for Image Customisation feature
Implemented xhr_customrecipe API. To create a custom recipe from a
base recipe.
Implemented xhr_customrecipe_packages API to add/remove packages
to/from custom recipe.
co-authored see Signed-off-by
Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: brian avery <avery.brian@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | lib/toaster/toastergui/urls.py | 10 | ||||
-rwxr-xr-x | lib/toaster/toastergui/views.py | 152 |
2 files changed, 159 insertions, 3 deletions
diff --git a/lib/toaster/toastergui/urls.py b/lib/toaster/toastergui/urls.py index 55f325d0..b47a1616 100644 --- a/lib/toaster/toastergui/urls.py +++ b/lib/toaster/toastergui/urls.py @@ -152,6 +152,14 @@ urlpatterns = patterns('toastergui.views', # JS Unit tests url(r'^js-unit-tests/$', 'jsunittests', name='js-unit-tests'), - # default redirection + # image customisation functionality + url(r'^xhr_customrecipe/(?P<recipe_id>\d+)/packages/(?P<package_id>\d+|)$', + 'xhr_customrecipe_packages', name='xhr_customrecipe_packages'), + url(r'^xhr_customrecipe/(?P<recipe_id>\d+)$', 'xhr_customrecipe_id', + name='xhr_customrecipe_id'), + url(r'^xhr_customrecipe/', 'xhr_customrecipe', + name='xhr_customrecipe'), + + # default redirection url(r'^$', RedirectView.as_view( url= 'landing')), ) diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py index 5ea6122a..392e56da 100755 --- a/lib/toaster/toastergui/views.py +++ b/lib/toaster/toastergui/views.py @@ -26,12 +26,12 @@ import operator,re from django.db.models import F, Q, Sum, Count, Max -from django.db import IntegrityError +from django.db import IntegrityError, Error from django.shortcuts import render, redirect from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency from orm.models import Target_Installed_Package, Target_File, Target_Image_File, BuildArtifact -from orm.models import BitbakeVersion +from orm.models import BitbakeVersion, CustomImageRecipe from bldcontrol import bbcontroller from django.views.decorators.cache import cache_control from django.core.urlresolvers import reverse, resolve @@ -2596,7 +2596,155 @@ if True: return HttpResponse(jsonfilter({"error": "ok",}), content_type = "application/json") + @xhr_response + def xhr_customrecipe(request): + """ + Custom image recipe REST API + + Entry point: /xhr_customrecipe/ + Method: POST + + Args: + name: name of custom recipe to create + project: target project id of orm.models.Project + base: base recipe id of orm.models.Recipe + + Returns: + {"error": "ok", + "url": <url of the created recipe>} + or + {"error": <error message>} + """ + # check if request has all required parameters + for param in ('name', 'project', 'base'): + if param not in request.POST: + return {"error": "Missing parameter '%s'" % param} + + # get project and baserecipe objects + params = {} + for name, model in [("project", Project), + ("base", Recipe)]: + value = request.POST[name] + try: + params[name] = model.objects.get(id=value) + except model.DoesNotExist: + return {"error": "Invalid %s id %s" % (name, value)} + + # create custom recipe + try: + recipe = CustomImageRecipe.objects.create( + name=request.POST["name"], + base_recipe=params["base"], + project=params["project"]) + except Error as err: + return {"error": "Can't create custom recipe: %s" % err} + + # Find the package list from the last build of this recipe/target + build = Build.objects.filter(target__target=params['base'].name, + project=params['project']).last() + + if build: + # Copy in every package + # We don't want these packages to be linked to anything because + # that underlying data may change e.g. delete a build + for package in build.package_set.all(): + # Create the duplicate + package.pk = None + package.save() + # Disassociate the package from the build + package.build = None + package.save() + recipe.packages.add(package) + else: + logger.warn("No packages found for this base recipe") + + return {"error": "ok", + "url": reverse('customrecipe', args=(params['project'].pk, + recipe.id))} + + @xhr_response + def xhr_customrecipe_id(request, recipe_id): + """ + Set of ReST API processors working with recipe id. + + Entry point: /xhr_customrecipe/<recipe_id> + + Methods: + GET - Get details of custom image recipe + DELETE - Delete custom image recipe + + Returns: + GET: + {"error": "ok", + "info": dictionary of field name -> value pairs + of the CustomImageRecipe model} + DELETE: + {"error": "ok"} + or + {"error": <error message>} + """ + objects = CustomImageRecipe.objects.filter(id=recipe_id) + if not objects: + return {"error": "Custom recipe with id=%s " + "not found" % recipe_id} + if request.method == 'GET': + values = CustomImageRecipe.objects.filter(id=recipe_id).values() + if values: + return {"error": "ok", "info": values[0]} + else: + return {"error": "Custom recipe with id=%s " + "not found" % recipe_id} + return {"error": "ok", "info": objects.values()[0]} + elif request.method == 'DELETE': + objects.delete() + return {"error": "ok"} + else: + return {"error": "Method %s is not supported" % request.method} + + @xhr_response + def xhr_customrecipe_packages(request, recipe_id, package_id): + """ + ReST API to add/remove packages to/from custom recipe. + Entry point: /xhr_customrecipe/<recipe_id>/packages/ + + Methods: + PUT - Add package to the recipe + DELETE - Delete package from the recipe + + Returns: + {"error": "ok"} + or + {"error": <error message>} + """ + try: + recipe = CustomImageRecipe.objects.get(id=recipe_id) + except CustomImageRecipe.DoesNotExist: + return {"error": "Custom recipe with id=%s " + "not found" % recipe_id} + + if request.method == 'GET' and not package_id: + return {"error": "ok", + "packages": list(recipe.packages.values_list('id'))} + + try: + package = Package.objects.get(id=package_id) + except Package.DoesNotExist: + return {"error": "Package with id=%s " + "not found" % package_id} + + if request.method == 'PUT': + recipe.packages.add(package) + return {"error": "ok"} + elif request.method == 'DELETE': + if package in recipe.packages.all(): + recipe.packages.remove(package) + return {"error": "ok"} + else: + return {"error": "Package '%s' is not in the recipe '%s'" % \ + (package.name, recipe.name)} + else: + return {"error": "Method %s is not supported" % request.method} def importlayer(request, pid): template = "importlayer.html" |