Skip to content

Commit

Permalink
Merge "Adds initial workflow support to Horizon."
Browse files Browse the repository at this point in the history
  • Loading branch information
Jenkins authored and openstack-gerrit committed May 23, 2012
2 parents 1a9a70e + d8affa5 commit b4fa6ba
Show file tree
Hide file tree
Showing 44 changed files with 2,303 additions and 717 deletions.
1 change: 1 addition & 0 deletions docs/source/index.rst
Expand Up @@ -84,6 +84,7 @@ In-depth documentation for Horizon and its APIs.

ref/run_tests
ref/horizon
ref/workflows
ref/tables
ref/tabs
ref/users
Expand Down
33 changes: 33 additions & 0 deletions docs/source/ref/workflows.rst
@@ -0,0 +1,33 @@
=================
Horizon Workflows
=================

.. module:: horizon.workflows

One of the most challenging aspects of building a compelling user experience
is crafting complex multi-part workflows. Horizon's ``workflows`` module
aims to bring that capability within everyday reach.

Workflows
=========

.. autoclass:: Workflow
:members:

Steps
=====

.. autoclass:: Step
:members:

Actions
=======

.. autoclass:: Action
:members:

WorkflowView
============

.. autoclass:: WorkflowView
:members:
8 changes: 5 additions & 3 deletions horizon/api/glance.py
Expand Up @@ -51,14 +51,16 @@ def image_get(request, image_id):
return glanceclient(request).images.get(image_id)


def image_list_detailed(request):
return glanceclient(request).images.list()
def image_list_detailed(request, filters=None):
filters = filters or {}
return glanceclient(request).images.list(filters=filters)


def image_update(request, image_id, **kwargs):
return glanceclient(request).images.update(image_id, **kwargs)


def snapshot_list_detailed(request):
def snapshot_list_detailed(request, extra_filters=None):
filters = {'property-image_type': 'snapshot'}
filters.update(extra_filters or {})
return glanceclient(request).images.list(filters=filters)
3 changes: 2 additions & 1 deletion horizon/api/nova.py
Expand Up @@ -405,7 +405,8 @@ def usage_list(request, start, end):

@memoized
def tenant_quota_usages(request):
"""Builds a dictionary of current usage against quota for the current
"""
Builds a dictionary of current usage against quota for the current
tenant.
"""
# TODO(tres): Make this capture floating_ips and volumes as well.
Expand Down
100 changes: 0 additions & 100 deletions horizon/dashboards/nova/images_and_snapshots/images/forms.py
Expand Up @@ -26,9 +26,6 @@

from django import shortcuts
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.forms import ValidationError
from django.utils.text import normalize_newlines
from django.utils.translation import ugettext_lazy as _

from horizon import api
Expand Down Expand Up @@ -92,100 +89,3 @@ def handle(self, request, data):
except:
exceptions.handle(request, error_updating % image_id)
return shortcuts.redirect(self.get_success_url())


class LaunchForm(forms.SelfHandlingForm):
name = forms.CharField(max_length=80, label=_("Server Name"))
image_id = forms.CharField(widget=forms.HiddenInput())
tenant_id = forms.CharField(widget=forms.HiddenInput())
user_data = forms.CharField(widget=forms.Textarea,
label=_("User Data"),
required=False)
flavor = forms.ChoiceField(label=_("Flavor"),
help_text=_("Size of image to launch."))
keypair = forms.ChoiceField(label=_("Keypair"),
required=False,
help_text=_("Which keypair to use for "
"authentication."))
count = forms.IntegerField(label=_("Instance Count"),
required=True,
min_value=1,
initial=1,
help_text=_("Number of instances to launch."))
security_groups = forms.MultipleChoiceField(
label=_("Security Groups"),
required=True,
initial=["default"],
widget=forms.CheckboxSelectMultiple(),
help_text=_("Launch instance in these "
"security groups."))
volume = forms.ChoiceField(label=_("Volume or Volume Snapshot"),
required=False,
help_text=_("Volume to boot from."))
device_name = forms.CharField(label=_("Device Name"),
required=False,
initial="vda",
help_text=_("Volume mount point (e.g. 'vda' "
"mounts at '/dev/vda')."))
delete_on_terminate = forms.BooleanField(
label=_("Delete on Terminate"),
initial=False,
required=False,
help_text=_("Delete volume on instance terminate"))

def __init__(self, *args, **kwargs):
flavor_list = kwargs.pop('flavor_list')
keypair_list = kwargs.pop('keypair_list')
if keypair_list:
keypair_list.insert(0, ("", _("Select a keypair")))
else:
keypair_list = (("", _("No keypairs available.")),)
security_group_list = kwargs.pop('security_group_list')
volume_list = kwargs.pop('volume_list')
super(LaunchForm, self).__init__(*args, **kwargs)
self.fields['flavor'].choices = flavor_list
self.fields['keypair'].choices = keypair_list
self.fields['security_groups'].choices = security_group_list
self.fields['volume'].choices = volume_list

def clean(self):
cleaned_data = super(LaunchForm, self).clean()
count = cleaned_data.get('count', 1)
volume = cleaned_data.get('volume', None)

if volume and count > 1:
msg = _('Cannot launch more than one instance if '
'volume is specified.')
raise ValidationError(msg)

return cleaned_data

def handle(self, request, data):
try:
if(len(data['volume']) > 0):
if(data['delete_on_terminate']):
delete_on_terminate = 1
else:
delete_on_terminate = 0
dev_mapping = {data['device_name']:
("%s::%s" % (data['volume'], delete_on_terminate))}
else:
dev_mapping = None

api.server_create(request,
data['name'],
data['image_id'],
data['flavor'],
data.get('keypair'),
normalize_newlines(data.get('user_data')),
data.get('security_groups'),
dev_mapping,
instance_count=data.get('count'))
messages.success(request,
_('Instance "%s" launched.') % data["name"])
except:
redirect = reverse("horizon:nova:images_and_snapshots:index")
exceptions.handle(request,
_('Unable to launch instance: %(exc)s'),
redirect=redirect)
return shortcuts.redirect('horizon:nova:instances_and_volumes:index')
27 changes: 15 additions & 12 deletions horizon/dashboards/nova/images_and_snapshots/images/tables.py
Expand Up @@ -16,7 +16,9 @@

import logging

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 api
Expand All @@ -26,6 +28,19 @@
LOG = logging.getLogger(__name__)


class LaunchImage(tables.LinkAction):
name = "launch_image"
verbose_name = _("Launch")
url = "horizon:nova:instances_and_volumes:instances:launch"
classes = ("btn-launch", "ajax-modal")

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])


class DeleteImage(tables.DeleteAction):
data_type_singular = _("Image")
data_type_plural = _("Images")
Expand All @@ -40,18 +55,6 @@ def delete(self, request, obj_id):
api.image_delete(request, obj_id)


class LaunchImage(tables.LinkAction):
name = "launch"
verbose_name = _("Launch")
url = "horizon:nova:images_and_snapshots:images:launch"
classes = ("ajax-modal", "btn-launch")

def allowed(self, request, image=None):
if image:
return image.status in ('active',)
return False


class EditImage(tables.LinkAction):
name = "edit"
verbose_name = _("Edit")
Expand Down

0 comments on commit b4fa6ba

Please sign in to comment.