diff --git a/django-openstack/django_openstack/api.py b/django-openstack/django_openstack/api.py index 6446909b7..07a293439 100644 --- a/django-openstack/django_openstack/api.py +++ b/django-openstack/django_openstack/api.py @@ -378,6 +378,16 @@ def image_get(request, image_id): def image_list_detailed(request): return [Image(i) for i in glance_api(request).get_images_detailed()] +def snapshot_list_detailed(request): + filters = {} + filters['property-image_type'] = 'snapshot' + filters['is_public'] = 'none' + return [Image(i) for i in glance_api(request) + .get_images_detailed(filters=filters)] + +def snapshot_create(request, instance_id, name): + return extras_api(request).snapshots.create(instance_id, name) + def image_update(request, image_id, image_meta=None): image_meta = image_meta and image_meta or {} diff --git a/django-openstack/django_openstack/dash/urls.py b/django-openstack/django_openstack/dash/urls.py index 7ea5a0fca..f58bcaf3e 100644 --- a/django-openstack/django_openstack/dash/urls.py +++ b/django-openstack/django_openstack/dash/urls.py @@ -23,6 +23,7 @@ from django.conf.urls.defaults import * INSTANCES = r'^(?P[^/]+)/instances/(?P[^/]+)/%s$' IMAGES = r'^(?P[^/]+)/images/(?P[^/]+)/%s$' KEYPAIRS = r'^(?P[^/]+)/keypairs/%s$' +SNAPSHOTS = r'^(?P[^/]+)/snapshots/(?P[^/]+)/%s$' CONTAINERS = r'^(?P[^/]+)/containers/%s$' OBJECTS = r'^(?P[^/]+)/containers/(?P[^/]+)/%s$' @@ -45,6 +46,11 @@ urlpatterns += patterns('django_openstack.dash.views.keypairs', url(KEYPAIRS % 'create', 'create', name='dash_keypairs_create'), ) +urlpatterns += patterns('django_openstack.dash.views.snapshots', + url(r'^(?P[^/]+)/snapshots/$', 'index', name='dash_snapshots'), + url(SNAPSHOTS % 'create', 'create', name='dash_snapshots_create'), +) + # Swift containers and objects. urlpatterns += patterns('django_openstack.dash.views.containers', url(CONTAINERS % '', 'index', name='dash_containers'), diff --git a/django-openstack/django_openstack/dash/views/snapshots.py b/django-openstack/django_openstack/dash/views/snapshots.py new file mode 100644 index 000000000..431f7cc1d --- /dev/null +++ b/django-openstack/django_openstack/dash/views/snapshots.py @@ -0,0 +1,112 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Copyright 2011 Fourth Paradigm Development, 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. + +""" +Views for managing Nova images. +""" + +import datetime +import logging +import re + +from django import http +from django import template +from django.conf import settings +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.shortcuts import redirect, render_to_response +from django.utils.translation import ugettext as _ +from django import shortcuts + +from django_openstack import api +from django_openstack import forms +from openstackx.api import exceptions as api_exceptions +from glance.common import exception as glance_exception + + +LOG = logging.getLogger('django_openstack.dash.views.snapshots') + + +class CreateSnapshot(forms.SelfHandlingForm): + tenant_id = forms.CharField(widget=forms.HiddenInput()) + instance_id = forms.CharField(widget=forms.TextInput(attrs={'readonly':'readonly'})) + name = forms.CharField(max_length="20", label="Snapshot Name") + + def handle(self, request, data): + try: + LOG.info('Creating snapshot "%s"' % data['name']) + snapshot = api.snapshot_create(request, data['instance_id'], data['name']) + messages.info(request, 'Snapshot "%s" created for instance %s' %\ + (data['name'], data['instance_id'])) + return shortcuts.redirect('dash_snapshots', data['tenant_id']) + except api_exceptions.ApiException, e: + LOG.error("ApiException in CreateSnapshot", exc_info=True) + messages.error(request, 'Error Creating Snapshot: %s' % e.message) + return shortcuts.redirect(request.build_absolute_uri()) + + +@login_required +def index(request, tenant_id): + images = [] + try: + images = api.snapshot_list_detailed(request) + except glance_exception.ClientConnectionError, e: + LOG.error("Error connecting to glance", exc_info=True) + messages.error(request, "Error connecting to glance: %s" % str(e)) + except glance_exception.Error, e: + LOG.error("Error retrieving image list", exc_info=True) + messages.error(request, "Error retrieving image list: %s" % str(e)) + except api_exceptions.ApiException, e: + msg = "Unable to retreive image info from glance: %s" % str(e) + LOG.error(msg) + messages.error(request, msg) + + return render_to_response('dash_snapshots.html', { + 'images': images, + }, context_instance=template.RequestContext(request)) + + +@login_required +def create(request, tenant_id, instance_id): + form, handled = CreateSnapshot.maybe_handle(request, + initial={'tenant_id': tenant_id, + 'instance_id': instance_id}) + if handled: + return handled + + try: + instance = api.server_get(request, instance_id) + except api_exceptions.ApiException, e: + msg = "Unable to retreive instance: %s" % str(e) + LOG.error(msg) + messages.error(request, msg) + return shortcuts.redirect('dash_instances', tenant_id) + + valid_states = ['ACTIVE'] + if instance.status not in valid_states: + messages.error(request, "To snapshot, instance state must be\ + one of the following: %s" % + ', '.join(valid_states)) + return shortcuts.redirect('dash_instances', tenant_id) + + return shortcuts.render_to_response('dash_snapshots_create.html', { + 'instance': instance, + 'create_form': form, + }, context_instance=template.RequestContext(request)) diff --git a/openstack-dashboard/dashboard/templates/_dash_sidebar.html b/openstack-dashboard/dashboard/templates/_dash_sidebar.html index 027fcf5bb..fe54cf675 100644 --- a/openstack-dashboard/dashboard/templates/_dash_sidebar.html +++ b/openstack-dashboard/dashboard/templates/_dash_sidebar.html @@ -4,6 +4,7 @@
  • Overview
  • Instances
  • Images
  • +
  • Snapshots
  • Keypairs
  • {% if swift_configured %} diff --git a/openstack-dashboard/dashboard/templates/_instance_list.html b/openstack-dashboard/dashboard/templates/_instance_list.html index a7ca752d6..74dd3ff0b 100644 --- a/openstack-dashboard/dashboard/templates/_instance_list.html +++ b/openstack-dashboard/dashboard/templates/_instance_list.html @@ -39,6 +39,7 @@
  • Log
  • VNC Console
  • Edit
  • +
  • Snapshot
  • diff --git a/openstack-dashboard/dashboard/templates/_snapshot_form.html b/openstack-dashboard/dashboard/templates/_snapshot_form.html new file mode 100644 index 000000000..e7b5df2a9 --- /dev/null +++ b/openstack-dashboard/dashboard/templates/_snapshot_form.html @@ -0,0 +1,13 @@ +
    +
    + {% csrf_token %} + {% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %} + {% for field in form.visible_fields %} + {{ field.label_tag }} + {{ field.errors }} + {{ field }} + {% endfor %} + +
    +
    + diff --git a/openstack-dashboard/dashboard/templates/dash_snapshots.html b/openstack-dashboard/dashboard/templates/dash_snapshots.html new file mode 100644 index 000000000..5f77022c5 --- /dev/null +++ b/openstack-dashboard/dashboard/templates/dash_snapshots.html @@ -0,0 +1,25 @@ +{% extends 'dash_base.html' %} + +{% block sidebar %} + {% with current_sidebar="snapshots" %} + {{block.super}} + {% endwith %} +{% endblock %} + +{% block page_header %} + {% url dash_snapshots request.user.tenant as refresh_link %} + {# to make searchable false, just remove it from the include statement #} + {% include "_page_header.html" with title="Snapshots" refresh_link=refresh_link searchable="true" %} +{% endblock page_header %} + +{% block dash_main %} + {% if images %} + {% include '_image_list.html' %} + {% else %} +
    +

    Info

    +

    There are currently no snapshots. You can create snapshots from running instances. View Running Instances >>

    +
    + {% endif %} +{% endblock %} + diff --git a/openstack-dashboard/dashboard/templates/dash_snapshots_create.html b/openstack-dashboard/dashboard/templates/dash_snapshots_create.html new file mode 100644 index 000000000..bf0d9fd54 --- /dev/null +++ b/openstack-dashboard/dashboard/templates/dash_snapshots_create.html @@ -0,0 +1,37 @@ +{% extends 'dash_base.html' %} + +{% block sidebar %} + {% with current_sidebar="snapshots" %} + {{block.super}} + {% endwith %} +{% endblock %} + +{% block headerjs %} + +{% endblock %} + +{% block page_header %} + {% include "_page_header.html" with title="Create a Snapshot" %} +{% endblock page_header %} + +{% block dash_main %} +
    +
    +

    Choose a name for your snapshot.

    + {% include '_snapshot_form.html' with form=create_form %} +

    << Return to snapshots list

    +
    + +
    +

    Description:

    +

    Snapshots preserve the disk state of a running instance.

    +
    +
     
    +
    +{% endblock %} + +