# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Nebula, Inc.
#
# 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.
import logging
from collections import defaultdict
from django.conf import settings
from django.core.urlresolvers import reverse
from django.template import defaultfilters as filters
from django.utils.http import urlencode
from django.utils.translation import ugettext_lazy as _
from horizon import tables
from horizon.utils.memoized import memoized
from openstack_dashboard import api
LOG = logging.getLogger(__name__)
[docs]class LaunchImage(tables.LinkAction):
name = "launch_image"
verbose_name = _("Launch")
url = "horizon:project:instances:launch"
classes = ("btn-launch", "ajax-modal")
[docs] def get_link_url(self, datum):
base_url = reverse(self.url)
params = urlencode({"source_type": "image_id",
"source_id": self.table.get_object_id(datum)})
return "?".join([base_url, params])
[docs]class DeleteImage(tables.DeleteAction):
data_type_singular = _("Image")
data_type_plural = _("Images")
[docs] def allowed(self, request, image=None):
if image:
return image.owner == request.user.tenant_id
# Return True to allow table-level bulk delete action to appear.
return True
[docs] def delete(self, request, obj_id):
api.glance.image_delete(request, obj_id)
[docs]class CreateImage(tables.LinkAction):
name = "create"
verbose_name = _("Create Image")
url = "horizon:project:images_and_snapshots:images:create"
classes = ("ajax-modal", "btn-create")
[docs]class EditImage(tables.LinkAction):
name = "edit"
verbose_name = _("Edit")
url = "horizon:project:images_and_snapshots:images:update"
classes = ("ajax-modal", "btn-edit")
[docs] def allowed(self, request, image=None):
if image:
return image.status in ("active",) and \
image.owner == request.user.tenant_id
# We don't have bulk editing, so if there isn't an image that's
# authorized, don't allow the action.
return False
[docs]def filter_tenants():
return getattr(settings, 'IMAGES_LIST_FILTER_TENANTS', [])
@memoized
def filter_tenant_ids():
return map(lambda ft: ft['tenant'], filter_tenants())
[docs]class OwnerFilter(tables.FixedFilterAction):
[docs] def categorize(self, table, images):
user_tenant_id = table.request.user.tenant_id
tenants = defaultdict(list)
for im in images:
categories = get_image_categories(im, user_tenant_id)
for category in categories:
tenants[category].append(im)
return tenants
[docs]def get_image_categories(im, user_tenant_id):
categories = []
if im.is_public:
categories.append('public')
if im.owner == user_tenant_id:
categories.append('project')
elif im.owner in filter_tenant_ids():
categories.append(im.owner)
elif not im.is_public:
categories.append('shared')
return categories
[docs]def get_image_type(image):
return getattr(image, "properties", {}).get("image_type", _("Image"))
[docs]class UpdateRow(tables.Row):
ajax = True
[docs] def get_data(self, request, image_id):
image = api.glance.image_get(request, image_id)
return image
[docs] def load_cells(self, image=None):
super(UpdateRow, self).load_cells(image)
# Tag the row with the image category for client-side filtering.
image = self.datum
my_tenant_id = self.table.request.user.tenant_id
image_categories = get_image_categories(image, my_tenant_id)
for category in image_categories:
self.classes.append('category-' + category)
[docs]class ImagesTable(tables.DataTable):
STATUS_CHOICES = (
("active", True),
("saving", None),
("queued", None),
("pending_delete", None),
("killed", False),
("deleted", False),
)
name = tables.Column("name",
link=("horizon:project:images_and_snapshots:"
"images:detail"),
verbose_name=_("Image Name"))
image_type = tables.Column(get_image_type,
verbose_name=_("Type"),
filters=(filters.title,))
status = tables.Column("status",
filters=(filters.title,),
verbose_name=_("Status"),
status=True,
status_choices=STATUS_CHOICES)
public = tables.Column("is_public",
verbose_name=_("Public"),
empty_value=False,
filters=(filters.yesno, filters.capfirst))
disk_format = tables.Column(get_format, verbose_name=_("Format"))