Files
horizon/openstack_dashboard/dashboards/admin/metadata_defs/views.py
Travis Tripp 7e5f4d1594 Base Glance Metadata Definitions Admin UI
Provide a base admin UI for viewing, importing, and associating the
metadata definitions that can be used with various resource types
such as flavors, images, and host aggregates.

In Juno, Glance provided a metadata definitions catalog[1][2] where
users can register the available metadata definitions that can be used
on different types of resources (images, artifacts, volumes, flavors,
aggregates, etc). This includes key / value pairs such as
properties, extra specs, etc. Horizon landed several patches that
read these properties. You can view the functionality in the
"update metadata" action on Flavors, Images, and Host Aggregates.

This specific patch is to bring in the Admin UI for the basic coarse
grained actions on the definitions in the catalog. This includes creating
(importing) a namespace, viewing the overview details about
it, deleting the namespace, and associating the namespace for use with
specific resource types.

Future blueprints will be registered for:
 - CRUD on individual metadata definitions within the namespace
For example, editing the default value of an individual property.

[1] Approved Glance Juno Spec:
https://github.com/openstack/glance-specs/blob/master/specs/juno/metadata-schema-catalog.rst

[2] Glance PTL Juno Feature Overview:
https://www.youtube.com/watch?v=3ptriiw1wK8&t=14m27s

Co-Authored-By: Travis Tripp <travis.tripp@hp.com>
Co-Authored-By: Santiago Baldassin<santiago.b.baldassin@intel.com>
Co-Authored-By: Bartosz Fic <bartosz.fic@intel.com>
Co-Authored-By: Pawel Koniszewski <pawel.koniszewski@intel.com>
Co-Authored-By: Michal Dulko <michal.dulko@intel.com>
DocImpact: Concept awareness
Change-Id: Ie34007f73af7e0941631a52f03841068e509a72c
Implements: blueprint glance-metadata-definitions-base-admin-ui
2014-12-17 16:10:53 -07:00

163 lines
5.9 KiB
Python

# (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# 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 json
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import tables
from horizon import tabs
from horizon.utils import memoized
from openstack_dashboard.api import glance
from openstack_dashboard.dashboards.admin.metadata_defs \
import constants
from openstack_dashboard.dashboards.admin.metadata_defs \
import forms as admin_forms
from openstack_dashboard.dashboards.admin.metadata_defs \
import tables as admin_tables
from openstack_dashboard.dashboards.admin.metadata_defs \
import tabs as admin_tabs
class AdminIndexView(tables.DataTableView):
table_class = admin_tables.AdminNamespacesTable
template_name = constants.METADATA_INDEX_TEMPLATE
def has_prev_data(self, table):
return self._prev
def has_more_data(self, table):
return self._more
def get_data(self):
namespaces = []
prev_marker = self.request.GET.get(
admin_tables.AdminNamespacesTable._meta.prev_pagination_param,
None)
if prev_marker is not None:
sort_dir = 'desc'
marker = prev_marker
else:
sort_dir = 'asc'
marker = self.request.GET.get(
admin_tables.AdminNamespacesTable._meta.pagination_param, None)
try:
namespaces, self._more, self._prev =\
glance.metadefs_namespace_list(self.request,
marker=marker,
paginate=True,
sort_dir=sort_dir)
if prev_marker is not None:
namespaces = sorted(namespaces,
key=lambda ns: getattr(ns, 'namespace'),
reverse=True)
except Exception:
self._prev = False
self._more = False
msg = _('Error getting metadata definitions.')
exceptions.handle(self.request, msg)
return namespaces
class CreateView(forms.ModalFormView):
form_class = admin_forms.CreateNamespaceForm
template_name = constants.METADATA_CREATE_TEMPLATE
context_object_name = 'namespace'
success_url = reverse_lazy(constants.METADATA_INDEX_URL)
class DetailView(tabs.TabView):
redirect_url = constants.METADATA_INDEX_URL
tab_group_class = admin_tabs.NamespaceDetailTabs
template_name = constants.METADATA_DETAIL_TEMPLATE
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context["namespace"] = self.get_data()
return context
@memoized.memoized_method
def get_data(self):
try:
namespace = glance.metadefs_namespace_get(
self.request, self.kwargs['namespace_id'], wrap=True)
except Exception:
url = reverse_lazy(constants.METADATA_INDEX_URL)
exceptions.handle(self.request,
_('Unable to retrieve namespace details.'),
redirect=url)
else:
return namespace
def get_tabs(self, request, *args, **kwargs):
namespace = self.get_data()
return self.tab_group_class(request, namespace=namespace, **kwargs)
class ManageResourceTypes(forms.ModalFormView):
template_name = constants.METADATA_MANAGE_RESOURCES_TEMPLATE
form_class = admin_forms.ManageResourceTypesForm
success_url = reverse_lazy(constants.METADATA_INDEX_URL)
def get_initial(self):
try:
resource_types = glance.metadefs_namespace_resource_types(
self.request, self.kwargs["id"])
except Exception:
resource_types = []
msg = _('Error getting resource type associations.')
exceptions.handle(self.request, msg)
return {'id': self.kwargs["id"],
'resource_types': resource_types}
def get_context_data(self, **kwargs):
context = super(ManageResourceTypes, self).get_context_data(**kwargs)
selected_type_names = [selected_type['name'] for selected_type in
context['form'].initial['resource_types']]
try:
# Set the basic types that aren't already associated
result = [unselected_type for unselected_type in
glance.metadefs_resource_types_list(self.request)
if unselected_type['name'] not in selected_type_names]
except Exception:
result = []
msg = _('Error getting resource type associations.')
exceptions.handle(self.request, msg)
# Add the resource types previously associated, includes prefix, etc
for initial_type in context['form'].initial['resource_types']:
selected_type = initial_type.copy()
selected_type['selected'] = True
result.insert(0, selected_type)
context['id'] = self.kwargs['id']
try:
context["resource_types"] = json.dumps(result)
except Exception:
context["resource_types"] = "[]"
msg = _('Error getting resource type associations.')
exceptions.handle(self.request, msg)
return context