Commit a352d93c by Czémán Arnold

dashboard, storage: remove Endpoint model and all associated views

parent 052beafc
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
"pk": 1, "pk": 1,
"model": "storage.datastore", "model": "storage.datastore",
"fields": { "fields": {
"endpoints": [],
"type": "file", "type": "file",
"ceph_user": null, "ceph_user": null,
"secret": null, "secret": null,
......
...@@ -54,7 +54,7 @@ from firewall.models import Vlan, Host ...@@ -54,7 +54,7 @@ from firewall.models import Vlan, Host
from vm.models import ( from vm.models import (
InstanceTemplate, Lease, InterfaceTemplate, Node, Trait, Instance 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.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from .models import Profile, GroupProfile, Message from .models import Profile, GroupProfile, Message
...@@ -1669,9 +1669,7 @@ class CephDataStoreForm(DataStoreForm): ...@@ -1669,9 +1669,7 @@ class CephDataStoreForm(DataStoreForm):
class Meta: class Meta:
model = DataStore model = DataStore
fields = ("type", "name", "path", "hostname", fields = ("type", "name", "path", "hostname",
"ceph_user", "secret", "endpoints") "ceph_user", "secret",)
widgets = {"endpoints": FilteredSelectMultiple(_("Endpoints"),
is_stacked=True)}
class StorageListSearchForm(forms.Form): class StorageListSearchForm(forms.Form):
...@@ -1700,46 +1698,6 @@ class StorageListSearchForm(forms.Form): ...@@ -1700,46 +1698,6 @@ class StorageListSearchForm(forms.Form):
self.data = data 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): class DiskForm(ModelForm):
created = forms.DateTimeField() created = forms.DateTimeField()
modified = forms.DateTimeField() modified = forms.DateTimeField()
......
...@@ -30,7 +30,7 @@ $(function () { ...@@ -30,7 +30,7 @@ $(function () {
}); });
$('.group-create, .node-create, .tx-tpl-ownership, .group-delete, .node-delete, ' + $('.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) { '.storage-delete, .storage-restore').click(function(e) {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
...@@ -96,49 +96,6 @@ $(function () { ...@@ -96,49 +96,6 @@ $(function () {
return false; 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) { $('[href=#index-graph-view]').click(function (e) {
var box = $(this).data('index-box'); var box = $(this).data('index-box');
$("#" + box + "-list-view").hide(); $("#" + box + "-list-view").hide();
......
...@@ -348,10 +348,6 @@ a.hover-black { ...@@ -348,10 +348,6 @@ a.hover-black {
width: 100px; width: 100px;
} }
.endpoint-list-table-thin {
width: 70px;
}
.nojs-dropdown-menu .nojs-dropdown-menu
{ {
position:absolute; position:absolute;
......
...@@ -410,37 +410,3 @@ class StorageListTable(Table): ...@@ -410,37 +410,3 @@ class StorageListTable(Table):
fields = ('name', 'type', 'path', 'hostname', 'used_percent') fields = ('name', 'type', 'path', 'hostname', 'used_percent')
prefix = "storage-" 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 @@ ...@@ -12,9 +12,6 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="pull-right"> <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"> <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" %} <i class="fa fa-plus"></i> {% trans "new data store" %}
</a> </a>
......
...@@ -19,21 +19,6 @@ ...@@ -19,21 +19,6 @@
{{ form.ceph_user|as_crispy_field }} {{ form.ceph_user|as_crispy_field }}
{{ form.secret|as_crispy_field }} {{ form.secret|as_crispy_field }}
</fieldset> </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 %} {% endif %}
<style> <style>
...@@ -44,7 +29,4 @@ ...@@ -44,7 +29,4 @@
fieldset legend { fieldset legend {
font-weight: bold; font-weight: bold;
} }
#group-detail-permissions {
margin-top: 20px;
}
</style> </style>
...@@ -55,7 +55,6 @@ from .views import ( ...@@ -55,7 +55,6 @@ from .views import (
UserList, UserList,
StorageDetail, StorageList, StorageChoose, StorageCreate, DiskDetail, StorageDetail, StorageList, StorageChoose, StorageCreate, DiskDetail,
StorageDelete, StorageRestore, StorageDelete, StorageRestore,
EndpointCreate, EndpointList, EndpointEdit, EndpointDelete,
MessageList, MessageDetail, MessageCreate, MessageDelete, MessageList, MessageDetail, MessageCreate, MessageDelete,
) )
from .views.vm import vm_ops, vm_mass_ops from .views.vm import vm_ops, vm_mass_ops
...@@ -250,15 +249,6 @@ urlpatterns = patterns( ...@@ -250,15 +249,6 @@ urlpatterns = patterns(
url(r"^storage/restore/(?P<pk>\d+)/$", StorageRestore.as_view(), url(r"^storage/restore/(?P<pk>\d+)/$", StorageRestore.as_view(),
name="dashboard.views.storage-restore"), 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(), url(r'^disk/(?P<pk>\d+)/$', DiskDetail.as_view(),
name="dashboard.views.disk-detail"), name="dashboard.views.disk-detail"),
......
...@@ -37,11 +37,10 @@ from braces.views import SuperuserRequiredMixin ...@@ -37,11 +37,10 @@ from braces.views import SuperuserRequiredMixin
from sizefield.utils import filesizeformat from sizefield.utils import filesizeformat
from common.models import WorkerNotFound from common.models import WorkerNotFound
from storage.models import DataStore, Disk, Endpoint from storage.models import DataStore, Disk
from ..tables import DiskListTable, StorageListTable, EndpointListTable from ..tables import DiskListTable, StorageListTable
from ..forms import ( from ..forms import (
DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm, DataStoreForm, CephDataStoreForm, DiskForm, StorageListSearchForm
EndpointForm, EndpointListSearchForm
) )
from .util import FilterMixin from .util import FilterMixin
import json import json
...@@ -157,7 +156,6 @@ class StorageList(SuperuserRequiredMixin, FilterMixin, SingleTableView): ...@@ -157,7 +156,6 @@ class StorageList(SuperuserRequiredMixin, FilterMixin, SingleTableView):
'path': "path__icontains", 'path': "path__icontains",
'poolname': "path__icontains", 'poolname': "path__icontains",
'hostname': "hostname__iexact", 'hostname': "hostname__iexact",
'address': "endpoints__address__in"
} }
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
...@@ -304,7 +302,7 @@ class StorageDetail(SuperuserRequiredMixin, UpdateView): ...@@ -304,7 +302,7 @@ class StorageDetail(SuperuserRequiredMixin, UpdateView):
class StorageDelete(SuperuserRequiredMixin, DeleteView): class StorageDelete(SuperuserRequiredMixin, DeleteView):
model = DataStore model = DataStore
success_message = _("Endpoint successfully deleted.") success_message = _("Storage successfully destroyed.")
def get_template_names(self): def get_template_names(self):
if self.request.is_ajax(): if self.request.is_ajax():
...@@ -387,165 +385,3 @@ class DiskDetail(SuperuserRequiredMixin, UpdateView): ...@@ -387,165 +385,3 @@ class DiskDetail(SuperuserRequiredMixin, UpdateView):
def form_valid(self, form): def form_valid(self, form):
pass 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): ...@@ -53,22 +53,6 @@ def validate_ascii(value):
raise ValidationError("%s is not 'ascii' string" % 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): class DataStore(Model):
"""Collection of virtual disks. """Collection of virtual disks.
...@@ -84,9 +68,7 @@ class DataStore(Model): ...@@ -84,9 +68,7 @@ class DataStore(Model):
validators=[validate_ascii]) validators=[validate_ascii])
# hostname of storage driver # hostname of storage driver
hostname = CharField(max_length=40, verbose_name=_('hostname')) 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, ceph_user = CharField(max_length=255, null=True, blank=True,
verbose_name=_('Ceph username')) verbose_name=_('Ceph username'))
secret = CharField(max_length=255, null=True, blank=True, secret = CharField(max_length=255, null=True, blank=True,
...@@ -124,10 +106,6 @@ class DataStore(Model): ...@@ -124,10 +106,6 @@ class DataStore(Model):
return [disk.filename for disk in deletables] 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): def destroy(self):
if self.destroyed: if self.destroyed:
return False return False
...@@ -481,7 +459,6 @@ class Disk(TimeStampedModel): ...@@ -481,7 +459,6 @@ class Disk(TimeStampedModel):
def get_vmdisk_desc_for_ceph_block_device(self): def get_vmdisk_desc_for_ceph_block_device(self):
desc = self.get_vmdisk_desc_for_filesystem() desc = self.get_vmdisk_desc_for_filesystem()
desc["endpoints"] = self.datastore.get_endpoints()
desc["ceph_user"] = self.datastore.ceph_user desc["ceph_user"] = self.datastore.ceph_user
desc["secret"] = self.datastore.secret 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