summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Bartosh <ed.bartosh@linux.intel.com>2015-09-28 21:45:22 -0700
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-09-29 13:44:48 +0100
commit84be400237173970716616eeab6a37d776aa011b (patch)
treed9147e34a5fd3a428bda8d28ef39f8c5e2455dc1
parent076945ea026091dc709f7cfea01ef119d0572bf3 (diff)
downloadbitbake-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.py10
-rwxr-xr-xlib/toaster/toastergui/views.py152
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"