Merge pull request #308 from levivm/develop
Merging ssh fix from modulos
This commit is contained in:
commit
c38b36a8a5
7 changed files with 171 additions and 80 deletions
|
@ -85,7 +85,7 @@
|
||||||
<ul id="g-account-menu" class="dropdown-menu" role="menu">
|
<ul id="g-account-menu" class="dropdown-menu" role="menu">
|
||||||
<li><a href="{% url 'hosting:logout' %}"><i class="glyphicon glyphicon-lock"></i>{% trans "Logout"%} </a></li>
|
<li><a href="{% url 'hosting:logout' %}"><i class="glyphicon glyphicon-lock"></i>{% trans "Logout"%} </a></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'hosting:key_pair' %}">
|
<a href="{% url 'hosting:ssh_keys' %}">
|
||||||
<i class="fa fa-key"></i> {% trans "Keys"%}
|
<i class="fa fa-key"></i> {% trans "Keys"%}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -149,7 +149,7 @@
|
||||||
<li>⋅</li>
|
<li>⋅</li>
|
||||||
<li>
|
<li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'hosting:key_pair' %}">
|
<a href="{% url 'hosting:ssh_keys' %}">
|
||||||
{% trans "Keys"%}
|
{% trans "Keys"%}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<h4 class="modal-title" id="ModalLabel">{% trans "Do You want do delete your order?"%}</h4>
|
<h4 class="modal-title" id="ModalLabel">{% trans "Do You want to delete your order?"%}</h4>
|
||||||
|
|
||||||
<form method="post"
|
<form method="post"
|
||||||
action="{% url 'hosting:delete_order' order.id %}">
|
action="{% url 'hosting:delete_order' order.id %}">
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
|
|
||||||
{% bootstrap_field field %}
|
{% bootstrap_field field %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% buttons %}
|
{% buttons %}
|
||||||
|
@ -32,34 +31,8 @@
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{% endbuttons %}
|
{% endbuttons %}
|
||||||
<div class="form-group">
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<h5> {% trans "Use your created key to access to the machine. If you lost it, contact us." %} </h5>
|
|
||||||
<table class="table borderless table-hover">
|
|
||||||
<br/>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{% trans "Name"%}</th>
|
|
||||||
<th>{% trans "Created at"%} </th>
|
|
||||||
<th>{% trans "Status"%} </th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for user_key in keys %}
|
|
||||||
<tr>
|
|
||||||
<td scope="row">{{user_key.name}}</td>
|
|
||||||
<td>{{user_key.created_at}}</td>
|
|
||||||
<td>
|
|
||||||
<span class="h3 label label-success"><strong>Active</strong></span>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
</form>
|
||||||
|
<h5> Use your created key to access to the machine. If you lost it, contact us. </h5>
|
||||||
|
|
||||||
{% if private_key %}
|
{% if private_key %}
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
|
@ -70,17 +43,7 @@
|
||||||
<textarea class="form-control" rows="6" id="ssh_key" type="hidden" style="display:none">{{private_key}}</textarea>
|
<textarea class="form-control" rows="6" id="ssh_key" type="hidden" style="display:none">{{private_key}}</textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="form-group pull-right">
|
{% endif %}
|
||||||
<button type="button" id="copy_to_clipboard" data-clipboard-target="#ssh_key" class="btn btn-warning"
|
|
||||||
data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">{% trans "Copy to Clipboard"%}</button>
|
|
||||||
<button type="button" id="download_ssh_key" class="btn btn-warning">{% trans "Download"%}</button>
|
|
||||||
</div> -->
|
|
||||||
{% else %}
|
|
||||||
<!-- <div class="alert alert-warning">
|
|
||||||
<strong>{% trans "Warning!"%}</strong>{% trans "Your SSH private key was already generated and downloaded, if you lost it, contact us. "%}
|
|
||||||
</div>
|
|
||||||
--> {% endif %}
|
|
||||||
<!-- <a class="btn btn-success" href="{% url 'hosting:virtual_machines' %}">{% trans "Generate my key"%} </a> -->
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
96
hosting/templates/hosting/user_keys.html
Normal file
96
hosting/templates/hosting/user_keys.html
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{% extends "hosting/base_short.html" %}
|
||||||
|
{% load staticfiles bootstrap3 i18n %}
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<div class="container virtual-machine-container dashboard-container ">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9 col-md-offset-2">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "Access Key"%} </h3>
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% for message in messages %}
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<p class="pull-right">
|
||||||
|
<a class="btn btn-success" href="{% url 'hosting:create_ssh_key' %}" >{% trans "Add Key"%} </a>
|
||||||
|
</p>
|
||||||
|
<h5> Use your created key to access to the machine. If you lost it, contact us. </h5>
|
||||||
|
<table class="table borderless table-hover">
|
||||||
|
<br/>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Name"%}</th>
|
||||||
|
<th>{% trans "Created at"%} </th>
|
||||||
|
<th>{% trans "Status"%} </th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user_key in keys %}
|
||||||
|
<tr>
|
||||||
|
<td scope="row">{{user_key.name}}</td>
|
||||||
|
<td>{{user_key.created_at}}</td>
|
||||||
|
<td>
|
||||||
|
<span class="h3 label label-success"><strong>Active</strong></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-default" data-toggle="modal"
|
||||||
|
data-target="#Modal{{ user_key.id }}"><a
|
||||||
|
href="#">{% trans "Delete Key"%}</a>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="modal fade" id="Modal{{user_key.id }}" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal"
|
||||||
|
aria-label="Confirm"><span
|
||||||
|
aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<h4 class="modal-title" id="ModalLabel">{% trans "Do You want to delete this key?"%}</h4>
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'hosting:delete_ssh_key' user_key.id %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default"
|
||||||
|
data-dismiss="modal">
|
||||||
|
{% trans "Close"%}
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{% trans "Delete"%}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if next_url %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.location.href = '{{next_url}}';
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{%endblock%}
|
||||||
|
|
|
@ -2,4 +2,6 @@ from django.test import TestCase
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
|
|
||||||
test_user_can_add_key()
|
test_user_can_add_ssh_key()
|
||||||
|
|
||||||
|
test_user_can_delete_ssh_ke()
|
||||||
|
|
|
@ -3,9 +3,10 @@ from django.conf.urls import url
|
||||||
from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
|
from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
|
||||||
NodeJSHostingView, LoginView, SignupView, IndexView, \
|
NodeJSHostingView, LoginView, SignupView, IndexView, \
|
||||||
OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
|
OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
|
||||||
VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
|
VirtualMachineView, OrdersHostingDeleteView, NotificationsView, \
|
||||||
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\
|
MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView,\
|
||||||
CreateVirtualMachinesView, HostingBillListView, HostingBillDetailView
|
CreateVirtualMachinesView, HostingBillListView, HostingBillDetailView, \
|
||||||
|
SSHKeyDeleteView, SSHKeyCreateView, SSHKeyListView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'index/?$', IndexView.as_view(), name='index'),
|
url(r'index/?$', IndexView.as_view(), name='index'),
|
||||||
|
@ -23,10 +24,12 @@ urlpatterns = [
|
||||||
url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
|
url(r'my-virtual-machines/?$', VirtualMachinesPlanListView.as_view(), name='virtual_machines'),
|
||||||
url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(),
|
url(r'my-virtual-machines/(?P<pk>\d+)/?$', VirtualMachineView.as_view(),
|
||||||
name='virtual_machines'),
|
name='virtual_machines'),
|
||||||
# url(r'my-virtual-machines/(?P<pk>\d+)/delete/?$', VirtualMachineCancelView.as_view(),
|
url(r'ssh_keys/?$', SSHKeyListView.as_view(),
|
||||||
# name='virtual_machines_cancel'),
|
name='ssh_keys'),
|
||||||
url(r'vm-key-pair/?$', GenerateVMSSHKeysView.as_view(),
|
url(r'delete_ssh_key/(?P<pk>\d+)/?$', SSHKeyDeleteView.as_view(),
|
||||||
name='key_pair'),
|
name='delete_ssh_key'),
|
||||||
|
url(r'create_ssh_key/?$', SSHKeyCreateView.as_view(),
|
||||||
|
name='create_ssh_key'),
|
||||||
url(r'^notifications/$', NotificationsView.as_view(), name='notifications'),
|
url(r'^notifications/$', NotificationsView.as_view(), name='notifications'),
|
||||||
url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(),
|
url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(),
|
||||||
name='read_notification'),
|
name='read_notification'),
|
||||||
|
|
|
@ -188,7 +188,7 @@ class SignupView(CreateView):
|
||||||
template_name = 'hosting/signup.html'
|
template_name = 'hosting/signup.html'
|
||||||
form_class = HostingUserSignupForm
|
form_class = HostingUserSignupForm
|
||||||
model = CustomUser
|
model = CustomUser
|
||||||
success_url = reverse_lazy('hosting:key_pair')
|
success_url = reverse_lazy('hosting:ssh_keys')
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
next_url = self.request.session.get(
|
next_url = self.request.session.get(
|
||||||
|
@ -288,31 +288,58 @@ class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView):
|
||||||
return HttpResponseRedirect(reverse('hosting:notifications'))
|
return HttpResponseRedirect(reverse('hosting:notifications'))
|
||||||
|
|
||||||
|
|
||||||
class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
|
class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
|
||||||
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
success_url = reverse_lazy('hosting:ssh_keys')
|
||||||
|
model = UserHostingKey
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
owner = self.request.user
|
||||||
|
manager = OpenNebulaManager()
|
||||||
|
pk = self.kwargs.get('pk')
|
||||||
|
# Get user ssh key
|
||||||
|
public_key = UserHostingKey.objects.get(pk=pk)
|
||||||
|
# Add ssh key to user
|
||||||
|
try:
|
||||||
|
manager.remove_public_key(user=owner, public_key=public_key)
|
||||||
|
except ConnectionError:
|
||||||
|
pass
|
||||||
|
except WrongNameError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
|
||||||
|
|
||||||
|
class SSHKeyListView(LoginRequiredMixin, ListView):
|
||||||
|
template_name = "hosting/user_keys.html"
|
||||||
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
context_object_name = "keys"
|
||||||
|
model = UserHostingKey
|
||||||
|
paginate_by = 10
|
||||||
|
ordering = '-id'
|
||||||
|
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
user = self.request.user
|
||||||
|
self.queryset = UserHostingKey.objects.filter(user=user)
|
||||||
|
return super(SSHKeyListView, self).get_queryset()
|
||||||
|
|
||||||
|
def render_to_response(self, context, **response_kwargs):
|
||||||
|
if not self.queryset:
|
||||||
|
return HttpResponseRedirect(reverse('hosting:create_ssh_key'))
|
||||||
|
return super(SSHKeyListView, self).render_to_response(context, **response_kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class SSHKeyCreateView(LoginRequiredMixin, FormView):
|
||||||
form_class = UserHostingKeyForm
|
form_class = UserHostingKeyForm
|
||||||
model = UserHostingKey
|
model = UserHostingKey
|
||||||
template_name = 'hosting/virtual_machine_key.html'
|
template_name = 'hosting/user_key.html'
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
context_object_name = "virtual_machine"
|
context_object_name = "virtual_machine"
|
||||||
|
success_url = reverse_lazy('hosting:ssh_keys')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(
|
|
||||||
GenerateVMSSHKeysView,
|
|
||||||
self
|
|
||||||
).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
user_keys = UserHostingKey.objects.filter(
|
|
||||||
user=self.request.user
|
|
||||||
)
|
|
||||||
|
|
||||||
context.update({
|
|
||||||
'keys': user_keys
|
|
||||||
})
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
kwargs = super(GenerateVMSSHKeysView, self).get_form_kwargs()
|
kwargs = super(SSHKeyCreateView, self).get_form_kwargs()
|
||||||
kwargs.update({'request': self.request})
|
kwargs.update({'request': self.request})
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
@ -339,22 +366,22 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
|
||||||
})
|
})
|
||||||
|
|
||||||
owner = self.request.user
|
owner = self.request.user
|
||||||
# Create OpenNebulaManager
|
manager = OpenNebulaManager()
|
||||||
manager = OpenNebulaManager(email=owner.email,
|
|
||||||
password=owner.password)
|
|
||||||
# Get OpenNebula user id
|
|
||||||
user_pool = manager._get_user_pool()
|
|
||||||
opennebula_user = user_pool.get_by_name(owner.email)
|
|
||||||
|
|
||||||
# Get user ssh key
|
# Get user ssh key
|
||||||
public_key = form.cleaned_data.get('public_key')
|
public_key = form.cleaned_data.get('public_key')
|
||||||
# Add ssh key to user
|
# Add ssh key to user
|
||||||
manager.oneadmin_client.call('user.update', opennebula_user.id,
|
try:
|
||||||
'<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key))
|
manager.add_public_key(user=owner, public_key=public_key, merge=True)
|
||||||
|
except ConnectionError:
|
||||||
|
pass
|
||||||
|
except WrongNameError:
|
||||||
|
pass
|
||||||
|
|
||||||
return render(self.request, self.template_name, context)
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
print(self.request.POST.dict())
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
return self.form_valid(form)
|
return self.form_valid(form)
|
||||||
|
@ -412,7 +439,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
request,
|
request,
|
||||||
'In order to create a VM, you create/upload your SSH KEY first.'
|
'In order to create a VM, you create/upload your SSH KEY first.'
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(reverse('hosting:key_pair'))
|
return HttpResponseRedirect(reverse('hosting:ssh_keys'))
|
||||||
|
|
||||||
if 'next' in request.session:
|
if 'next' in request.session:
|
||||||
del request.session['next']
|
del request.session['next']
|
||||||
|
@ -628,7 +655,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
|
||||||
request,
|
request,
|
||||||
'In order to create a VM, you need to create/upload your SSH KEY first.'
|
'In order to create a VM, you need to create/upload your SSH KEY first.'
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(reverse('hosting:key_pair'))
|
return HttpResponseRedirect(reverse('hosting:ssh_keys'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
manager = OpenNebulaManager()
|
manager = OpenNebulaManager()
|
||||||
|
|
Loading…
Reference in a new issue