Commit a352d93c by Czémán Arnold

dashboard, storage: remove Endpoint model and all associated views

parent 052beafc
......@@ -20,7 +20,6 @@
"pk": 1,
"model": "storage.datastore",
"fields": {
"endpoints": [],
"type": "file",
"ceph_user": null,
"secret": null,
......
......@@ -54,7 +54,7 @@ from firewall.models import Vlan, Host
from vm.models import (
InstanceTemplate, Lease, InterfaceTemplate, Node, Trait, Instance
)
from storage.models import DataStore, Disk, Endpoint
from storage.models import DataStore, Disk
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Permission
from .models import Profile, GroupProfile, Message
......@@ -1669,9 +1669,7 @@ class CephDataStoreForm(DataStoreForm):
class Meta:
model = DataStore
fields = ("type", "name", "path", "hostname",
"ceph_user", "secret", "endpoints")
widgets = {"endpoints": FilteredSelectMultiple(_("Endpoints"),
is_stacked=True)}
"ceph_user", "secret",)
class StorageListSearchForm(forms.Form):
......@@ -1700,46 +1698,6 @@ class StorageListSearchForm(forms.Form):
self.data = data
class EndpointForm(ModelForm):
@property
def helper(self):
helper = FormHelper()
helper.layout = Layout(
Fieldset(
'',
'name',
'address',
'port',
),
FormActions(
Submit('submit', _('Save')),
)
)
return helper
def __init__(self, *args, **kwargs):
super(EndpointForm, self).__init__(*args, **kwargs)
# NOTE: may this is not necessary, this is the default value in
# libvirt's ceph backend
self.fields['port'].initial = 6789
class Meta:
model = Endpoint
fields = ("name", "address", "port")
class EndpointListSearchForm(forms.Form):
s = forms.CharField(widget=forms.TextInput(attrs={
'class': "form-control input-tags",
'placeholder': _("Search...")
}))
def __init__(self, *args, **kwargs):
super(EndpointListSearchForm, self).__init__(*args, **kwargs)
class DiskForm(ModelForm):
created = forms.DateTimeField()
modified = forms.DateTimeField()
......
......@@ -30,7 +30,7 @@ $(function () {
});
$('.group-create, .node-create, .tx-tpl-ownership, .group-delete, .node-delete, ' +
'.disk-remove, .template-delete, .delete-from-group, .lease-delete, .endpoint-delete, ' +
'.disk-remove, .template-delete, .delete-from-group, .lease-delete, ' +
'.storage-delete, .storage-restore').click(function(e) {
$.ajax({
type: 'GET',
......@@ -96,49 +96,6 @@ $(function () {
return false;
});
// NOTE: modal for create endpoint, might use in future
$('.datastore_endpoint-create').click(function(e) {
$.ajax({
type: 'GET',
url: $(this).prop('href'),
success: function(data) {
$('body').append(data);
var modal = $('#confirmation-modal');
modal.modal('show');
modal.on('hidden.bs.modal', function() {
modal.remove();
});
$("#datastore_endpoint_host-create-btn").click(function(){
var form = $("#datastore_endpoint_form");
$.post(form.attr("action"), form.serialize(), function(data){
if(data.status===true){
$('#id_endpoints_from')
.append($('<option>')
.text(data.response.text)
.attr('value', data.response.val));
modal.modal("hide");
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
}
else{
var error_msg = $("#datastore_endpoint-create-alert");
error_msg.empty();
error_msg.append(data.response);
error_msg.show();
}
}, "json");
return false;
});
}
});
return false;
});
$('[href=#index-graph-view]').click(function (e) {
var box = $(this).data('index-box');
$("#" + box + "-list-view").hide();
......
......@@ -348,10 +348,6 @@ a.hover-black {
width: 100px;
}
.endpoint-list-table-thin {
width: 70px;
}
.nojs-dropdown-menu
{
position:absolute;
......
......@@ -410,37 +410,3 @@ class StorageListTable(Table):
fields = ('name', 'type', 'path', 'hostname', 'used_percent')
prefix = "storage-"
class EndpointListTable(Table):
name = TemplateColumn(
verbose_name=_("Name"),
template_name="dashboard/endpoint-list/column-endpoint-name.html",
attrs={'th': {'data-sort': "string"}}
)
address = Column(
verbose_name=_("Address"),
attrs={'th': {'data-sort': "string"}}
)
port = Column(
verbose_name=_("Port"),
attrs={'th': {'data-sort': "string"}}
)
actions = TemplateColumn(
verbose_name=_("Actions"),
template_name="dashboard/endpoint-list/column-endpoint-actions.html",
attrs={'th': {'class': 'endpoint-list-table-thin'}},
orderable=False,
)
class Meta:
model = DataStore
attrs = {'class': ('table table-bordered table-striped table-hover'
'endpoint-list-table')}
fields = ('name', 'address', 'port',)
prefix = "endpoint-"
{% load i18n %}
{% load crispy_forms_tags %}
<form id="datastore_endpoint_form" action="{% url "dashboard.views.storage-endpoint-create" %}" method="POST">
<div class="alert alert-danger" style="display: none;" id="datastore_endpoint-create-alert">
</div>
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% csrf_token %}
<div class="row">
<div class="col-xs-12">{{ form.name|as_crispy_field }}</div>
</div>
<div class="row">
<div class="col-xs-9">
{{ form.address|as_crispy_field }}
</div>
<div class="col-xs-3">
{{ form.port|as_crispy_field }}
</div>
</div>
<input type="submit" value="{% trans "Create new endpoint" %}" class="btn btn-success" id="datastore_endpoint_host-create-btn">
<a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-primary">
{% trans "Back" %}
</a>
</form>
<style>
fieldset {
margin-top: 40px;
}
fieldset legend {
font-weight: bold;
}
</style>
{% extends "dashboard/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Endpoint" %}{% endblock %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Endpoint" %}</h3>
</div>
<div class="panel-body">
<form id="datastore_endpoint_form" action="" method="POST">
{% with form=form %}
{% include "display-form-errors.html" %}
{% endwith %}
{% csrf_token %}
<div class="row">
<div class="col-xs-12">{{ form.name|as_crispy_field }}</div>
</div>
<div class="row">
<div class="col-xs-9">
{{ form.address|as_crispy_field }}
</div>
<div class="col-xs-3">
{{ form.port|as_crispy_field }}
</div>
</div>
<input type="submit" value="{% trans "Save" %}" class="btn btn-primary">
<a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-primary">
{% trans "Back" %}
</a>
</form>
</div><!-- .panel-body -->
</div>
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "dashboard.views.storage-endpoint-delete" pk=object.pk %}"
class="btn btn-xs btn-danger pull-right endpoint-delete">
{% trans "Delete" %}
</a>
<h4 class="no-margin"><i class="fa fa-times"></i> {% trans "Delete endpoint" %}</h4>
</div>
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% block title-page %}{% trans "Endpoints" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "dashboard.views.storage-endpoint-create" %}" class="pull-right btn btn-success btn-xs">
<i class="fa fa-plus"></i> {% trans "new endpoint" %}
</a>
<h3 class="no-margin"><i class="fa fa-database"></i> {% trans "Endpoints" %}</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-offset-8 col-md-4" id="endpoint-list-search">
<form action="" method="GET">
<div class="input-group">
{{ search_form.s }}
<div class="input-group-btn">
<button type="submit" class="btn btn-primary input-tags">
<i class="fa fa-search"></i>
</button>
</div>
</div><!-- .input-group -->
</form>
</div><!-- .col-md-4 #storage-list-search -->
</div>
</div>
<div class="panel-body">
<div class="table-responsive">
{% render_table table %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% load i18n %}
<a href="{% url "dashboard.views.storage-endpoint-edit" pk=record.pk%}" id="endpoint-list-edit-button" class="btn btn-default btn-xs" title="{% trans "Edit" %}">
<i class="fa fa-edit"></i>
</a>
<a href="{% url "dashboard.views.storage-endpoint-delete" pk=record.pk %}" class="btn btn-danger btn-xs endpoint-delete" title="{% trans "Delete" %}">
<i class="fa fa-times"></i>
</a>
<a href="{% url "dashboard.views.storage-endpoint-edit" pk=record.pk %}" title="{{ record.description }}">
{{ record.name }}
</a>
......@@ -12,9 +12,6 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
<a href="{% url "dashboard.views.storage-endpoint-list" %}" class="btn btn-success btn-xs" id="endpoint-list-btn">
{% trans "endpoint list" %}
</a>
<a href="{% url "dashboard.views.storage-choose" %}" class="btn btn-success btn-xs storage-choose">
<i class="fa fa-plus"></i> {% trans "new data store" %}
</a>
......
......@@ -19,21 +19,6 @@
{{ form.ceph_user|as_crispy_field }}
{{ form.secret|as_crispy_field }}
</fieldset>
<fieldset>
<legend>{% trans "Select or add new Ceph monitor endpoints(s)" %}</legend>
<a href="{% url "dashboard.views.storage-endpoint-create" %}" class="btn btn-success">
<i class="fa fa-plus"></i>
{% trans "new endpoint" %}
</a>
<script type="text/javascript" src="/static/admin/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
{{ form.media }}
<div id="group-detail-permissions">
{{ form.endpoints }}
</div>
<link rel="stylesheet" type="text/css" href="/static/admin/css/widgets.css" />
</fieldset>
{% endif %}
<style>
......@@ -44,7 +29,4 @@
fieldset legend {
font-weight: bold;
}
#group-detail-permissions {
margin-top: 20px;
}
</style>
......@@ -55,7 +55,6 @@ from .views import (
UserList,
StorageDetail, StorageList, StorageChoose, StorageCreate, DiskDetail,
StorageDelete, StorageRestore,
EndpointCreate, EndpointList, EndpointEdit, EndpointDelete,
MessageList, MessageDetail, MessageCreate, MessageDelete,
)
from .views.vm import vm_ops, vm_mass_ops
......@@ -250,15 +249,6 @@ urlpatterns = patterns(
url(r"^storage/restore/(?P<pk>\d+)/$", StorageRestore.as_view(),
name="dashboard.views.storage-restore"),
url(r'^storage/endpoint/create/$', EndpointCreate.as_view(),
name="dashboard.views.storage-endpoint-create"),
url(r'^storage/endpoint/list/$', EndpointList.as_view(),
name="dashboard.views.storage-endpoint-list"),
url(r'^storage/endpoint/(?P<pk>\d+)/$', EndpointEdit.as_view(),
name='dashboard.views.storage-endpoint-edit'),
url(r"^storage/endpoint/delete/(?P<pk>\d+)/$", EndpointDelete.as_view(),
name="dashboard.views.storage-endpoint-delete"),
url(r'^disk/(?P<pk>\d+)/$', DiskDetail.as_view(),
name="dashboard.views.disk-detail"),
......
......@@ -37,11 +37,10 @@ from braces.views import SuperuserRequiredMixin
from sizefield.utils import filesizeformat
from common.models import WorkerNotFound
from storage.models import DataStore, Disk, Endpoint
from ..tables import DiskListTable, StorageListTable, EndpointListTable
from storage.models import DataStore, Disk
from ..tables import DiskListTable, StorageListTable
from ..forms import (
DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm,
EndpointForm, EndpointListSearchForm
DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm
)
from .util import FilterMixin
import json
......@@ -157,7 +156,6 @@ class StorageList(SuperuserRequiredMixin, FilterMixin, SingleTableView):
'path': "path__icontains",
'poolname': "path__icontains",
'hostname': "hostname__iexact",
'address': "endpoints__address__in"
}
def get_context_data(self, *args, **kwargs):
......@@ -304,7 +302,7 @@ class StorageDetail(SuperuserRequiredMixin, UpdateView):
class StorageDelete(SuperuserRequiredMixin, DeleteView):
model = DataStore
success_message = _("Endpoint successfully deleted.")
success_message = _("Storage successfully destroyed.")
def get_template_names(self):
if self.request.is_ajax():
......@@ -387,165 +385,3 @@ class DiskDetail(SuperuserRequiredMixin, UpdateView):
def form_valid(self, form):
pass
class EndpointCreate(SuccessMessageMixin, CreateView):
model = Endpoint
form_class = EndpointForm
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/_modal.html']
else:
return ['dashboard/nojs-wrapper.html']
def get_context_data(self, *args, **kwargs):
context = super(EndpointCreate, self).get_context_data(
*args, **kwargs)
context.update({
'box_title': _("Create a new endpoint"),
'ajax_title': True,
'template': "dashboard/endpoint-create.html",
})
return context
def get(self, *args, **kwargs):
if not self.request.user.has_perm('storage.add_endpoint'):
raise PermissionDenied()
return super(EndpointCreate, self).get(*args, **kwargs)
def post(self, request, *args, **kwargs):
if not self.request.user.has_perm('storage.add_endpoint'):
raise PermissionDenied()
form = self.form_class(request.POST)
if not form.is_valid():
if self.request.is_ajax():
errors = self.errors_to_string(form)
return self.json_response(False, errors)
else:
return self.get(request, form, *args, **kwargs)
else:
instance = form.save()
if self.request.is_ajax():
resp = {"val": instance.id, "text": unicode(instance)}
return self.json_response(True, resp)
else:
return redirect(self.get_success_url())
def json_response(self, status, response):
resp = {
"status": status,
"response": response
}
return HttpResponse(json.dumps(resp), content_type="application/json")
def errors_to_string(self, form):
error_str = ""
if form.errors:
for field, error in form.errors.iteritems():
error_str += "%s: %s<br />" % (field, error)
for error in form.non_field_errors():
error_str += "%s<br />" % error
return error_str
def get_success_url(self):
return reverse_lazy("dashboard.views.storage-endpoint-list")
class EndpointList(SuperuserRequiredMixin, FilterMixin, SingleTableView):
template_name = "dashboard/endpoint-list.html"
model = Endpoint
table_class = EndpointListTable
table_pagination = False
allowed_filters = {
'name': "name__icontains",
'address': "address__icontains",
}
def get_context_data(self, *args, **kwargs):
context = super(EndpointList, self).get_context_data(*args, **kwargs)
context['search_form'] = self.search_form
return context
def get(self, *args, **kwargs):
self.search_form = EndpointListSearchForm(self.request.GET)
self.search_form.full_clean()
return super(EndpointList, self).get(*args, **kwargs)
def get_queryset(self):
logger.debug('StorageList.get_queryset() called. User: %s',
unicode(self.request.user))
qs = Endpoint.objects.all()
self.create_fake_get()
try:
filters, excludes = self.get_queryset_filters()
qs = qs.filter(**filters).exclude(**excludes).distinct()
except ValueError:
messages.error(self.request, _("Error during filtering."))
return qs
class EndpointEdit(SuperuserRequiredMixin, UpdateView):
model = Endpoint
fields = ("name", "address", "port")
template_name = "dashboard/endpoint-edit.html"
def get_success_url(self):
ds = self.get_object()
return reverse_lazy("dashboard.views.storage-endpoint-edit",
kwargs={"pk": ds.id})
class EndpointDelete(SuperuserRequiredMixin, DeleteView):
model = Endpoint
success_message = _("Endpoint successfully deleted.")
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/confirm/ajax-delete.html']
else:
return ['dashboard/confirm/base-delete.html']
def check_deletable(self):
object = self.get_object()
if not object.is_deletable:
raise PermissionDenied()
def get(self, request, *args, **kwargs):
try:
self.check_deletable()
except PermissionDenied:
message = ugettext("Another object references"
" to the selected object.")
if request.is_ajax():
return JsonResponse({"error": message})
else:
messages.warning(request, message)
return redirect(self.get_success_url())
return super(EndpointDelete, self).get(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy("dashboard.views.storage-endpoint-list")
def delete_obj(self, request, *args, **kwargs):
self.get_object().delete()
def delete(self, request, *args, **kwargs):
self.check_deletable()
self.delete_obj(request, *args, **kwargs)
if request.is_ajax():
return JsonResponse(
json.dumps({'message': self.success_message}),
)
else:
messages.success(request, self.success_message)
return HttpResponseRedirect(self.get_success_url())
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('storage', '0008_auto_20160609_2338'),
]
operations = [
migrations.RemoveField(
model_name='datastore',
name='endpoints',
),
migrations.DeleteModel(
name='Endpoint',
),
]
......@@ -53,22 +53,6 @@ def validate_ascii(value):
raise ValidationError("%s is not 'ascii' string" % value)
class Endpoint(Model):
""" Address and port of a data store.
"""
name = CharField(max_length=255, unique=True, verbose_name=_('name'))
address = CharField(max_length=1024, verbose_name=_('address'))
port = IntegerField(null=True, blank=True, verbose_name=_('port'))
def __unicode__(self):
return u"%s | %s:%d" % (self.name, self.address, self.port)
@property
def is_deletable(self):
return self.datastore_set.filter(destroyed__isnull=True).count() == 0
class DataStore(Model):
"""Collection of virtual disks.
......@@ -84,9 +68,7 @@ class DataStore(Model):
validators=[validate_ascii])
# hostname of storage driver
hostname = CharField(max_length=40, verbose_name=_('hostname'))
# endpoints of Ceph monitors
endpoints = ManyToManyField(Endpoint, blank=True,
verbose_name=_('endpoints'))
ceph_user = CharField(max_length=255, null=True, blank=True,
verbose_name=_('Ceph username'))
secret = CharField(max_length=255, null=True, blank=True,
......@@ -124,10 +106,6 @@ class DataStore(Model):
return [disk.filename for disk in deletables]
def get_endpoints(self):
return [(ep.address, ep.port) for ep in self.endpoints.all()]
def destroy(self):
if self.destroyed:
return False
......@@ -481,7 +459,6 @@ class Disk(TimeStampedModel):
def get_vmdisk_desc_for_ceph_block_device(self):
desc = self.get_vmdisk_desc_for_filesystem()
desc["endpoints"] = self.datastore.get_endpoints()
desc["ceph_user"] = self.datastore.ceph_user
desc["secret"] = self.datastore.secret
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment