From baed5a613c9b3563766e1a39f0340300e5a85e1f Mon Sep 17 00:00:00 2001 From: Timur Sufiev Date: Wed, 23 Oct 2013 14:51:34 +0400 Subject: [PATCH] Move 'Images' handling table to a separate panel 'Images'. Change-Id: I626f93d1eaacb4249a342ddf9669d30cf1aede47 --- muranodashboard/dashboard.py | 16 ++++-- muranodashboard/environments/forms.py | 41 --------------- muranodashboard/environments/tables.py | 48 +---------------- muranodashboard/environments/urls.py | 10 ---- muranodashboard/environments/views.py | 47 +---------------- muranodashboard/images/__init__.py | 13 +++++ muranodashboard/images/forms.py | 60 ++++++++++++++++++++++ muranodashboard/images/panel.py | 25 +++++++++ muranodashboard/images/tables.py | 64 +++++++++++++++++++++++ muranodashboard/images/urls.py | 30 +++++++++++ muranodashboard/images/views.py | 71 ++++++++++++++++++++++++++ 11 files changed, 276 insertions(+), 149 deletions(-) create mode 100644 muranodashboard/images/__init__.py create mode 100644 muranodashboard/images/forms.py create mode 100644 muranodashboard/images/panel.py create mode 100644 muranodashboard/images/tables.py create mode 100644 muranodashboard/images/urls.py create mode 100644 muranodashboard/images/views.py diff --git a/muranodashboard/dashboard.py b/muranodashboard/dashboard.py index 19c7f398a..856102852 100644 --- a/muranodashboard/dashboard.py +++ b/muranodashboard/dashboard.py @@ -16,15 +16,21 @@ from django.utils.translation import ugettext_lazy as _ class DeployPanels(horizon.PanelGroup): - slug = "deployment_group" - name = _("Deployment") + slug = 'deployment_group' + name = _('Deployment') panels = ('environments',) +class ManagePanels(horizon.PanelGroup): + slug = 'manage_metadata' + name = _('Manage') + panels = ('images',) + + class Murano(horizon.Dashboard): - name = _("Murano") - slug = "murano" - panels = (DeployPanels,) + name = _('Murano') + slug = 'murano' + panels = (DeployPanels, ManagePanels) default_panel = 'environments' supports_tenants = True diff --git a/muranodashboard/environments/forms.py b/muranodashboard/environments/forms.py index e85a1ff43..a88fa39eb 100644 --- a/muranodashboard/environments/forms.py +++ b/muranodashboard/environments/forms.py @@ -15,10 +15,6 @@ import logging from django import forms from django.utils.translation import ugettext_lazy as _ -from horizon.forms import SelfHandlingForm -from horizon import messages, exceptions -from openstack_dashboard.api import glance -import json from muranodashboard.environments.services import get_service_choices @@ -30,40 +26,3 @@ def ChoiceServiceFormFactory(request): service = forms.ChoiceField(label=_('Service Type'), choices=get_service_choices(request)) return _Class - - -class AddImageForm(SelfHandlingForm): - title = forms.CharField(max_length="255", - label=_("Image Title")) - - image_choices = forms.ChoiceField(label='Images') - - windows_image = ('ws-2012-std', ' Windows Server 2012 Desktop') - demo_image = ('murano_demo', 'Murano Demo Image') - - image_type = forms.ChoiceField(label="Murano Type", - choices=[windows_image, demo_image]) - - def __init__(self, request, *args, **kwargs): - super(AddImageForm, self).__init__(request, *args, **kwargs) - try: - images, _more = glance.image_list_detailed(request) - except Exception: - log.error("Failed to request image list from glance ") - images = [] - exceptions.handle(request, _("Unable to retrieve public images.")) - self.fields['image_choices'].choices = [(image.id, image.name) - for image in images] - - def handle(self, request, data): - log.debug('Adding new murano using data {0}'.format(data)) - murano_properties = {'murano_image_info': json.dumps( - {'title': data['title'], 'type': data['image_type']})} - try: - image = glance.image_update(request, data['image_choices'], - properties=murano_properties) - - messages.success(request, _('Image added to Murano')) - return image - except Exception: - exceptions.handle(request, _('Unable to update image.')) diff --git a/muranodashboard/environments/tables.py b/muranodashboard/environments/tables.py index 1dba63280..f7a27b3c9 100644 --- a/muranodashboard/environments/tables.py +++ b/muranodashboard/environments/tables.py @@ -19,7 +19,6 @@ from django import shortcuts from horizon import exceptions from horizon import tables from horizon import messages -from openstack_dashboard.api import glance from muranodashboard.environments import api from muranodashboard.openstack.common import timeutils @@ -57,15 +56,6 @@ class CreateEnvironment(tables.LinkAction): api.environment_create(request, environment) -class MuranoImages(tables.LinkAction): - name = 'show_images' - verbose_name = _('Murano Images') - url = 'horizon:murano:environments:murano_images' - - def allowed(self, request, environment): - return True - - class DeleteEnvironment(tables.DeleteAction): data_type_singular = _('Environment') data_type_plural = _('Environments') @@ -229,7 +219,7 @@ class EnvironmentsTable(tables.DataTable): verbose_name = _('Environments') row_class = UpdateEnvironmentRow status_columns = ['status'] - table_actions = (CreateEnvironment, MuranoImages) + table_actions = (CreateEnvironment,) row_actions = (ShowEnvironmentServices, DeployEnvironment, EditEnvironment, DeleteEnvironment, ShowDeployments) @@ -314,39 +304,3 @@ class EnvConfigTable(tables.DataTable): class Meta: name = 'environment_configuration' verbose_name = _('Deployed Services') - - -class AddMuranoImage(tables.LinkAction): - name = "add_image" - verbose_name = _("Add Image") - url = "horizon:murano:environments:add_image" - classes = ("ajax-modal", "btn-create") - - def allowed(self, request, image): - return True - - -class RemoveImageMetadata(tables.DeleteAction): - data_type_singular = _('Murano Metadata') - data_type_plural = _('Murano Metadata') - - def delete(self, request, obj_id): - try: - glance.image_update(request, obj_id, properties={}) - messages.success(request, _('Image removed from Murano.')) - except Exception: - exceptions.handle(request, _('Unable to update image.')) - - -class ImagesTable(tables.DataTable): - image_title = tables.Column('title', verbose_name=_('Murano title')) - image_id = tables.Column('id', verbose_name=_('Image id')) - - image_name = tables.Column('name', verbose_name=_('Name in Glance')) - image_type = tables.Column('name', verbose_name=_('Murano Type')) - - class Meta: - name = 'images' - verbose_name = _('Murano Images') - table_actions = (AddMuranoImage, RemoveImageMetadata) - row_actions = (RemoveImageMetadata,) diff --git a/muranodashboard/environments/urls.py b/muranodashboard/environments/urls.py index f0008dd13..7225d714e 100644 --- a/muranodashboard/environments/urls.py +++ b/muranodashboard/environments/urls.py @@ -19,7 +19,6 @@ from views import Services from views import CreateEnvironmentView from views import DetailServiceView from views import DeploymentsView -from views import MuranoImageView, AddMuranoImageView from views import Wizard, EditEnvironmentView from forms import ChoiceServiceFormFactory from services import get_service_checkers @@ -47,15 +46,6 @@ urlpatterns = patterns( url(r'^create_environment$', CreateEnvironmentView.as_view(), name='create_environment'), - url(r'^murano_images$', MuranoImageView.as_view(), - name='murano_images'), - - url(r'^add_image$', AddMuranoImageView.as_view(), - name='add_image'), - - url(r'^remove_image$', MuranoImageView.as_view(), - name='remove_image'), - url(ENVIRONMENT_ID + r'/update_environment$', EditEnvironmentView.as_view(), name='update_environment'), diff --git a/muranodashboard/environments/views.py b/muranodashboard/environments/views.py index 59c144d47..613f8b1f5 100644 --- a/muranodashboard/environments/views.py +++ b/muranodashboard/environments/views.py @@ -14,7 +14,6 @@ import logging import re -import json import copy from django.core.urlresolvers import reverse, reverse_lazy @@ -22,23 +21,19 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.formtools.wizard.views import SessionWizardView from django.http import HttpResponseRedirect -from openstack_dashboard.api import glance - from horizon import exceptions from horizon import tabs from horizon import tables from horizon import workflows from horizon import messages -from horizon.forms.views import ModalFormMixin, ModalFormView +from horizon.forms.views import ModalFormMixin from tables import EnvironmentsTable from tables import ServicesTable from tables import DeploymentsTable from tables import EnvConfigTable -from tables import ImagesTable from workflows import CreateEnvironment, UpdateEnvironment from tabs import ServicesTabs, DeploymentTabs -from forms import AddImageForm import api from muranoclient.common.exceptions import HTTPUnauthorized, \ @@ -378,43 +373,3 @@ class DeploymentDetailsView(tabs.TabbedTableView): return self.tab_group_class(request, deployment=deployment, logs=logs, **kwargs) - - -class MuranoImageView(tables.DataTableView): - table_class = ImagesTable - template_name = 'images/index.html' - - def get_data(self): - images = [] - try: - images, _more = glance.image_list_detailed(self.request) - - except HTTPForbidden: - msg = _('Unable to retrieve list of images') - exceptions.handle( - self.request, msg, - redirect=reverse("horizon:murano:environments:index")) - murano_images = [] - for image in images: - murano_property = image.properties.get('murano_image_info') - if murano_property: - try: - murano_json = json.loads(murano_property) - except ValueError: - LOG.warning("JSON in image metadata is not valid. " - "Check it in glance.") - messages.error(self.request, - _("Invalid murano image metadata")) - else: - image.title = murano_json.get('title', 'No title') - image.type = murano_json.get('type', 'No title') - - murano_images.append(image) - return murano_images - - -class AddMuranoImageView(ModalFormView): - form_class = AddImageForm - template_name = 'images/add.html' - context_object_name = 'image' - success_url = reverse_lazy("horizon:murano:environments:murano_images") diff --git a/muranodashboard/images/__init__.py b/muranodashboard/images/__init__.py new file mode 100644 index 000000000..7d93825c6 --- /dev/null +++ b/muranodashboard/images/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013 Mirantis, 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. diff --git a/muranodashboard/images/forms.py b/muranodashboard/images/forms.py new file mode 100644 index 000000000..e67cf5403 --- /dev/null +++ b/muranodashboard/images/forms.py @@ -0,0 +1,60 @@ +# Copyright (c) 2013 Mirantis, 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 +import json +from django import forms +from django.utils.translation import ugettext_lazy as _ +from horizon.forms import SelfHandlingForm +from horizon import messages, exceptions +from openstack_dashboard.api import glance + + +log = logging.getLogger(__name__) + + +class AddImageForm(SelfHandlingForm): + title = forms.CharField(max_length="255", + label=_("Image Title")) + + image_choices = forms.ChoiceField(label='Images') + + windows_image = ('ws-2012-std', ' Windows Server 2012 Desktop') + demo_image = ('murano_demo', 'Murano Demo Image') + + image_type = forms.ChoiceField(label="Murano Type", + choices=[windows_image, demo_image]) + + def __init__(self, request, *args, **kwargs): + super(AddImageForm, self).__init__(request, *args, **kwargs) + try: + images, _more = glance.image_list_detailed(request) + except Exception: + log.error("Failed to request image list from glance ") + images = [] + exceptions.handle(request, _("Unable to retrieve public images.")) + self.fields['image_choices'].choices = [(image.id, image.name) + for image in images] + + def handle(self, request, data): + log.debug('Adding new murano using data {0}'.format(data)) + murano_properties = {'murano_image_info': json.dumps( + {'title': data['title'], 'type': data['image_type']})} + try: + image = glance.image_update(request, data['image_choices'], + properties=murano_properties) + + messages.success(request, _('Image added to Murano')) + return image + except Exception: + exceptions.handle(request, _('Unable to update image.')) diff --git a/muranodashboard/images/panel.py b/muranodashboard/images/panel.py new file mode 100644 index 000000000..20e617aa3 --- /dev/null +++ b/muranodashboard/images/panel.py @@ -0,0 +1,25 @@ +# Copyright (c) 2013 Mirantis, 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 horizon +from django.utils.translation import ugettext_lazy as _ +from muranodashboard import dashboard + + +class Images(horizon.Panel): + name = _("Images") + slug = 'images' + + +dashboard.Murano.register(Images) diff --git a/muranodashboard/images/tables.py b/muranodashboard/images/tables.py new file mode 100644 index 000000000..450938477 --- /dev/null +++ b/muranodashboard/images/tables.py @@ -0,0 +1,64 @@ +# Copyright (c) 2013 Mirantis, 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. +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import tables +from horizon import messages +from openstack_dashboard.api import glance + + +class MuranoImages(tables.LinkAction): + name = 'show_images' + verbose_name = _('Murano Images') + url = 'horizon:murano:images:murano_images' + + def allowed(self, request, environment): + return True + + +class AddMuranoImage(tables.LinkAction): + name = "add_image" + verbose_name = _("Add Image") + url = "horizon:murano:images:add_image" + classes = ("ajax-modal", "btn-create") + + def allowed(self, request, image): + return True + + +class RemoveImageMetadata(tables.DeleteAction): + data_type_singular = _('Murano Metadata') + data_type_plural = _('Murano Metadata') + + def delete(self, request, obj_id): + try: + glance.image_update(request, obj_id, properties={}) + messages.success(request, _('Image removed from Murano.')) + except Exception: + exceptions.handle(request, _('Unable to update image.')) + + +class ImagesTable(tables.DataTable): + image_title = tables.Column('title', verbose_name=_('Murano title')) + image_id = tables.Column('id', verbose_name=_('Image id')) + + image_name = tables.Column('name', verbose_name=_('Name in Glance')) + image_type = tables.Column('name', verbose_name=_('Murano Type')) + + class Meta: + name = 'images' + verbose_name = _('Murano Images') + table_actions = (AddMuranoImage, RemoveImageMetadata) + row_actions = (RemoveImageMetadata,) diff --git a/muranodashboard/images/urls.py b/muranodashboard/images/urls.py new file mode 100644 index 000000000..cd3383153 --- /dev/null +++ b/muranodashboard/images/urls.py @@ -0,0 +1,30 @@ +# Copyright (c) 2013 Mirantis, 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. + +from django.conf.urls.defaults import patterns, url + +from .views import MuranoImageView, AddMuranoImageView + + +urlpatterns = patterns( + '', + url(r'^$', MuranoImageView.as_view(), + name='index'), + + url(r'^add_image$', AddMuranoImageView.as_view(), + name='add_image'), + + url(r'^remove_image$', MuranoImageView.as_view(), + name='remove_image'), +) diff --git a/muranodashboard/images/views.py b/muranodashboard/images/views.py new file mode 100644 index 000000000..43c78ea6f --- /dev/null +++ b/muranodashboard/images/views.py @@ -0,0 +1,71 @@ +# Copyright (c) 2013 Mirantis, 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 +import json + +from django.core.urlresolvers import reverse, reverse_lazy +from django.utils.translation import ugettext_lazy as _ + +from openstack_dashboard.api import glance +from horizon import exceptions +from horizon import tables +from horizon import messages +from horizon.forms.views import ModalFormView +from tables import ImagesTable + +from forms import AddImageForm +from muranoclient.common.exceptions import HTTPForbidden + +LOG = logging.getLogger(__name__) + + +class MuranoImageView(tables.DataTableView): + table_class = ImagesTable + template_name = 'images/index.html' + + def get_data(self): + images = [] + try: + images, _more = glance.image_list_detailed(self.request) + + except HTTPForbidden: + msg = _('Unable to retrieve list of images') + exceptions.handle( + self.request, msg, + redirect=reverse("horizon:murano:images:index")) + murano_images = [] + for image in images: + murano_property = image.properties.get('murano_image_info') + if murano_property: + try: + murano_json = json.loads(murano_property) + except ValueError: + LOG.warning("JSON in image metadata is not valid. " + "Check it in glance.") + messages.error(self.request, + _("Invalid murano image metadata")) + else: + image.title = murano_json.get('title', 'No title') + image.type = murano_json.get('type', 'No title') + + murano_images.append(image) + return murano_images + + +class AddMuranoImageView(ModalFormView): + form_class = AddImageForm + template_name = 'images/add.html' + context_object_name = 'image' + success_url = reverse_lazy("horizon:murano:images:index")