Merged trunk
This commit is contained in:
commit
724381a0b7
|
@ -196,7 +196,7 @@ class CreateVolumeForm(forms.Form):
|
|||
class AttachVolumeForm(ProjectFormBase):
|
||||
volume = forms.ChoiceField()
|
||||
instance = forms.ChoiceField()
|
||||
device = forms.CharField(initial='/dev/vdb')
|
||||
device = forms.CharField(initial='/dev/vdc')
|
||||
|
||||
def __init__(self, project, *args, **kwargs):
|
||||
super(AttachVolumeForm, self).__init__(project, *args, **kwargs)
|
||||
|
|
|
@ -91,9 +91,9 @@ class ProjectManager(object):
|
|||
groups='all'):
|
||||
conn = self.get_nova_connection()
|
||||
return conn.modify_image_attribute(image_id,
|
||||
attribute='launchPermission',
|
||||
operation='remove',
|
||||
groups='all',)
|
||||
attribute=attribute,
|
||||
operation=operation,
|
||||
groups=groups,)
|
||||
|
||||
|
||||
@wrap_nova_error
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<h3 class="image_list_heading"> {{ heading }} </h3>
|
||||
<h3 class="image_list_heading"> {{ heading }} </h3>
|
||||
{% if images %}
|
||||
<table id="image_launch">
|
||||
<tr>
|
||||
|
@ -54,13 +54,13 @@
|
|||
{% endif %}
|
||||
|
||||
<a id="launch_{{ image.id }}" class="launch" href="{% url nova_images_launch project.projectname image.id %}" title="Click to launch image">Launch</a>
|
||||
{% if can_modify or user.username == ami.ownerId %}
|
||||
{% if user.username == ami.ownerId %}
|
||||
<a id="edit_image_link" href="{% url nova_images_update project.projectname ami.id %}">Edit Image</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% if can_modify or user.username == ami.ownerId %}
|
||||
{% if user.username == ami.ownerId %}
|
||||
<span class="image_privacy">
|
||||
<form id="privacy_{{ ami.id }}" action="{% url nova_images_privacy project.projectname ami.id %}" method="post" accept-charset="utf-8">
|
||||
{% csrf_token %}
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
{% extends "django_nova/images/base.html" %}
|
||||
|
||||
{% block title %} - Launch an Image{% endblock %}
|
||||
|
||||
{% block headerjs %}
|
||||
<script type="text/javascript" src="/media/django_nova/js/jquery.form.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div id="right_content">
|
||||
<div id="page_head">
|
||||
<h2 id="page_heading">Images</h2>
|
||||
<p id="page_description">Images are snapshots of running systems which can easily be deployed to run one or more instances.</p>
|
||||
</div>
|
||||
|
||||
{% include "django_nova/_messages.html" %}
|
||||
|
||||
{% if images %}
|
||||
<table id="image_launch">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Description</th>
|
||||
<th colspan="2">Owner</th>
|
||||
</tr>
|
||||
{% for image in images %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
{% if image.id == ami.id %}
|
||||
<td class="detail_wrapper" colspan="4">
|
||||
<div id="{{ ami.id }}" class="image_detail">
|
||||
<div class="column">
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Owner: </span>
|
||||
<span class="data">{{ ami.ownerId }}</span>
|
||||
</div>
|
||||
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Description: </span>
|
||||
<span class="data">{{ ami.description }}</span>
|
||||
</div>
|
||||
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Location: </span>
|
||||
<span class="data">{{ ami.location }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="image_detail_item">
|
||||
<span class="label">ID: </span>
|
||||
<span class="data">{{ ami.id }}</span>
|
||||
</div>
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Name: </span>
|
||||
<span class="data">{% if ami.displayName %}{{ ami.displayName }}{%else%}{{ ami.id }}{% endif %}</span>
|
||||
</div>
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Type: </span>
|
||||
<span class="data">{{ ami.type }}</span>
|
||||
</div>
|
||||
<div class="image_detail_item">
|
||||
<span class="label">Architecture: </span>
|
||||
<span class="data">{{ ami.architecture }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="last" class="column">
|
||||
{% if ami.is_public %}
|
||||
<div id="public" class="privacy">Public Image</div>
|
||||
{% else %}
|
||||
<div id="private" class="privacy">Private Image</div>
|
||||
{% endif %}
|
||||
|
||||
<a id="launch_{{ image.id }}" class="launch" href="{% url nova_images_launch project.projectname image.id %}" title="Click to launch image">Launch</a>
|
||||
{% if can_modify or user.username == ami.ownerId %}
|
||||
<a id="edit_image_link" href="{% url nova_images_update project.projectname ami.id %}">Edit Image</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% if can_modify or user.username == ami.ownerId %}
|
||||
<span class="image_privacy">
|
||||
<form id="privacy_{{ ami.id }}" action="{% url nova_images_privacy project.projectname ami.id %}" method="post" accept-charset="utf-8">
|
||||
{% csrf_token %}
|
||||
{% if ami.is_public %}
|
||||
<input class="private" type="submit" value="Make Private" />
|
||||
{% else %}
|
||||
<input class="public" type="submit" value="Make Public" />
|
||||
{% endif %}
|
||||
</form>
|
||||
</span>
|
||||
|
||||
<span class="delete">
|
||||
<form id="delete_{{ ami.id }}" action="{% url nova_images_remove project.projectname ami.id %}" method="post" accept-charset="utf-8">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Remove Image" />
|
||||
</form>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="image_id"><a href="{% url nova_images_detail project.projectname image.id %}">{{ image.id }}</a></td>
|
||||
<td class="image_location odd">
|
||||
{% if image.description %}
|
||||
{{ image.description }}
|
||||
{% else %}
|
||||
{{ image.location }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="image_owner_id">{{ image.ownerId }}</td>
|
||||
<td class="image_launch_btn odd"><a id="launch_{{ image.id }}" class="launch" href="{% url nova_images_launch project.projectname image.id %}">Launch</a></td>
|
||||
{#<td class="odd"><a class="ui-state-default ui-corner-all" onclick="$('#dlg_launch').dialog('open');">Launch</a></td>#}
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="ui-widget">
|
||||
<div class="ui-state-highlight ui-corner-all">
|
||||
<p>
|
||||
<span class="ui-icon ui-icon-info"></span>
|
||||
No images currently available.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div id="dlg_launch" title="Launch Instance" style="display:none;">
|
||||
<form id="frm_launch" action="url nova_images_launch project.projectname" method="post">
|
||||
{% csrf_token %}
|
||||
{% include "django_nova/images/_launch_form.html" %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="dlg_confirm" title="Confirm Termination">
|
||||
<p>Are you sure you wish to unregister the <span id="ami_name"></span> image?</p>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block footerjs %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
var options = {
|
||||
success: handleResponse,
|
||||
beforeSubmit: showRequest,
|
||||
dataType: 'json'
|
||||
}
|
||||
|
||||
// TODO: On dialog open, reset form and validation.
|
||||
$(function() {
|
||||
$('#dlg_launch').dialog({
|
||||
buttons: {
|
||||
'Ok': function() {
|
||||
$('#frm_launch').ajaxSubmit(options);
|
||||
},
|
||||
'Cancel': function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
},
|
||||
autoOpen: false,
|
||||
resizable: false,
|
||||
width: 400,
|
||||
height: 400
|
||||
});
|
||||
});
|
||||
|
||||
function showRequest(formData, jqForm, options) {
|
||||
var queryString = $.param(formData);
|
||||
alert('About to submit: \n\n' + queryString);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleResponse(data, statusText, xhr, $form) {
|
||||
alert('status: ' + statusText + '\nsuccess:\n\n' + data.success);
|
||||
}
|
||||
|
||||
$(function(){
|
||||
$('.delete form').submit(function() {
|
||||
ami_name = $(this).parent().parent().attr("id");
|
||||
$('#ami_name').text(ami_name);
|
||||
$('#dlg_confirm').dialog('open');
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#dlg_confirm').dialog({
|
||||
buttons: {
|
||||
'Ok': onConfirmOK,
|
||||
'Cancel': function() { $(this).dialog('close'); }
|
||||
},
|
||||
autoOpen: false,
|
||||
resizable: false,
|
||||
width: 500,
|
||||
height: 200
|
||||
});
|
||||
})
|
||||
|
||||
function onConfirmOK() {
|
||||
$(this).dialog('close');
|
||||
form = document.getElementById('delete_' + ami_name);
|
||||
if(form) form.submit();
|
||||
}
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -19,7 +19,7 @@
|
|||
<fieldset>
|
||||
<h3 class="image_id">Launch Image {{ ami.id }}</h3>
|
||||
<div class="even">
|
||||
<label>Location</label>
|
||||
<h4 class="label">Location</h4>
|
||||
<span class="image_location">{{ ami.location }}</span>
|
||||
</div>
|
||||
{% include "django_nova/images/_launch_form.html" %}
|
||||
|
|
|
@ -33,15 +33,16 @@
|
|||
<fieldset class="module aligned {{ fieldset.classes }}">
|
||||
<h3 id="edit_{{ user.username }}">Edit Roles for User: {{ user.username }}</h3>
|
||||
<div class="form-row">
|
||||
<label>User</label>
|
||||
<h4 class="label">User</h4>
|
||||
<span id="user_name">{{ user.username }}</span>
|
||||
</div>
|
||||
<input type="hidden" name="username" value="{{ user.id }}" id="username" />
|
||||
|
||||
|
||||
<label for="id_role_from">Roles</label>
|
||||
{% for field in form.visible_fields %}
|
||||
<div class="form-row">
|
||||
{{ field.errors }}
|
||||
{{ field.label_tag }}{{ field }}
|
||||
{{ field }}
|
||||
{% if field.field.help_text %}<p class="help">{{ field.field.help_text|safe }}</p>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -123,8 +123,6 @@ class ImageViewTests(BaseProjectViewTests):
|
|||
|
||||
self.project.get_images().AndReturn([self.ami])
|
||||
self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
|
||||
shortcuts.get_user_image_permissions(mox.IgnoreArg(),
|
||||
TEST_PROJECT).AndReturn(True)
|
||||
forms.get_key_pair_choices(self.project).AndReturn(
|
||||
self.create_key_pair_choices([TEST_KEY]))
|
||||
forms.get_instance_type_choices().AndReturn(
|
||||
|
@ -142,15 +140,12 @@ class ImageViewTests(BaseProjectViewTests):
|
|||
|
||||
def test_remove_form(self):
|
||||
self.mox.StubOutWithMock(self.project, 'get_image')
|
||||
self.project.get_image(TEST_IMAGE_ID).AndReturn(self.ami)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(reverse('nova_images_remove',
|
||||
args=[TEST_PROJECT, TEST_IMAGE_ID]))
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'django_nova/images/detail_list.html')
|
||||
self.assertEqual(res.context['ami'].id, TEST_IMAGE_ID)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('nova_images',
|
||||
args=[TEST_PROJECT]))
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_remove(self):
|
||||
|
@ -161,7 +156,7 @@ class ImageViewTests(BaseProjectViewTests):
|
|||
res = self.client.post(reverse('nova_images_remove',
|
||||
args=[TEST_PROJECT, TEST_IMAGE_ID]))
|
||||
self.assertRedirectsNoFollow(res, reverse('nova_images',
|
||||
args=[TEST_PROJECT]))
|
||||
args=[TEST_PROJECT]))
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
|
|
|
@ -107,12 +107,12 @@ def project_view(request, project_name):
|
|||
nova = get_nova_admin_connection()
|
||||
project = nova.get_project(project_name)
|
||||
users = nova.get_project_members(project_name)
|
||||
|
||||
|
||||
try:
|
||||
manager = auth_models.User.objects.get(username=project.projectManagerId)
|
||||
except auth_models.User.DoesNotExist:
|
||||
manager = None
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.ProjectForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
@ -127,8 +127,8 @@ def project_view(request, project_name):
|
|||
messages.error(request,
|
||||
'Unable modify the project %s: %s - %s' %
|
||||
(project_name, e.code, e.error_message))
|
||||
|
||||
|
||||
|
||||
|
||||
return redirect('admin_project', request.POST["projectname"])
|
||||
else:
|
||||
form = forms.ProjectForm(initial={'projectname': project.projectname,
|
||||
|
@ -219,14 +219,16 @@ def remove_global_roles(username):
|
|||
@staff_member_required
|
||||
def project_user(request, project_name, project_user):
|
||||
nova = get_nova_admin_connection()
|
||||
project = nova.get_project(project_name)
|
||||
userroles = nova.get_user_roles(project_user, project_name)
|
||||
|
||||
try:
|
||||
modeluser = auth_models.User.objects.get(username = project_user)
|
||||
except auth_models.User.DoesNotExist:
|
||||
modeluser = None
|
||||
|
||||
if request.method == 'POST':
|
||||
form = forms.ProjectUserForm(request.POST)
|
||||
form = forms.ProjectUserForm(project, request.user, request.POST)
|
||||
if form.is_valid():
|
||||
username = project_user
|
||||
|
||||
|
@ -240,12 +242,11 @@ def project_user(request, project_name, project_user):
|
|||
return redirect('admin_project', project_name)
|
||||
else:
|
||||
roles = [str(role.role) for role in userroles]
|
||||
form = forms.ProjectUserForm({
|
||||
'role': roles,
|
||||
'user': modeluser,
|
||||
})
|
||||
form = forms.ProjectUserForm(project,
|
||||
request.user,
|
||||
{'role': roles,
|
||||
'user': modeluser})
|
||||
|
||||
project = nova.get_project(project_name)
|
||||
|
||||
return render_to_response('admin/django_nova/project/project_user.html', {
|
||||
'form' : form,
|
||||
|
|
|
@ -113,8 +113,6 @@ def detail(request, project_id, image_id):
|
|||
images = project.get_images()
|
||||
|
||||
ami = project.get_image(image_id)
|
||||
can_modify = shortcuts.get_user_image_permissions(request.user.username,
|
||||
project_id)
|
||||
|
||||
if not ami:
|
||||
raise http.Http404()
|
||||
|
@ -122,10 +120,8 @@ def detail(request, project_id, image_id):
|
|||
'form': forms.LaunchInstanceForm(project),
|
||||
'region': project.region,
|
||||
'project': project,
|
||||
'images': images,
|
||||
'image_lists': _image_lists(images, project_id),
|
||||
'ami': ami,
|
||||
'can_modify': can_modify,
|
||||
}, context_instance = template.RequestContext(request))
|
||||
|
||||
|
||||
|
@ -145,17 +141,7 @@ def remove(request, project_id, image_id):
|
|||
'Image %s has been successfully deregistered.' %
|
||||
image_id)
|
||||
|
||||
return redirect('nova_images', project_id)
|
||||
else:
|
||||
ami = project.get_image(image_id)
|
||||
|
||||
#FIXME - is the code below used? if we reach here should we
|
||||
#just redirect? (anthony)
|
||||
return render_to_response('django_nova/images/detail_list.html', {
|
||||
'region': project.region,
|
||||
'project': project,
|
||||
'ami': ami,
|
||||
}, context_instance = template.RequestContext(request))
|
||||
return redirect('nova_images', project_id)
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -73,6 +73,7 @@ def edit_user(request, project_id, username):
|
|||
nova = get_nova_admin_connection()
|
||||
project = get_project_or_404(request, project_id)
|
||||
user = nova.get_user(username)
|
||||
userroles = nova.get_user_roles(username, project_id)
|
||||
|
||||
if project.projectManagerId != request.user.username:
|
||||
return redirect('login')
|
||||
|
@ -84,7 +85,11 @@ def edit_user(request, project_id, username):
|
|||
|
||||
return redirect('nova_project_manage', project_id)
|
||||
else:
|
||||
form = nova_forms.ProjectUserForm(project, user)
|
||||
roles = [str(role.role) for role in userroles]
|
||||
form = nova_forms.ProjectUserForm(project,
|
||||
user,
|
||||
{'role': roles,
|
||||
'user': user})
|
||||
|
||||
return render_to_response('django_nova/projects/edit_user.html', {
|
||||
'form' : form,
|
||||
|
|
|
@ -116,7 +116,10 @@ def attach(request, project_id):
|
|||
'Unable to attach volume: %s' % e.message)
|
||||
else:
|
||||
messages.success(request,
|
||||
'Volume %s has been successfully attached.' %
|
||||
'Volume %s is scheduled to be attached. If '
|
||||
'it doesn\'t become attached in two '
|
||||
'minutes, please try again (you may need to '
|
||||
'specify a different device).' %
|
||||
form.cleaned_data['volume'])
|
||||
else:
|
||||
volumes = project.get_volumes()
|
||||
|
|
|
@ -62,7 +62,8 @@
|
|||
</div>
|
||||
{% if not request.user.is_authenticated %}
|
||||
<div class="home_block">
|
||||
<h3>Don't have an account? <a id="lnk_register" href="{% url registration_register %}">Register</a></h3>
|
||||
<h3>Don't have an account?</h3><br/>
|
||||
<a id="lnk_register" href="{% url registration_register %}">Register</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="home_block">
|
||||
|
@ -75,4 +76,3 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ span.data {
|
|||
|
||||
#home_login fieldset {
|
||||
width: 400px;
|
||||
padding: 20px;
|
||||
padding: 20px 20px 46px 20px;
|
||||
}
|
||||
|
||||
#home_login label {
|
||||
|
@ -780,4 +780,4 @@ div.image_detail, div.instance_detail {
|
|||
|
||||
form.edit_instance input[type="submit"], form.edit_image input[type="submit"] {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue