Force user to generate ssh key in order to create a VM #3147. As user I want to terminate a VM using web interface #3148. Change password in opennebula when user change his password on hosting app #3149
This commit is contained in:
parent
1a6e1a44d8
commit
3873540849
7 changed files with 214 additions and 43 deletions
|
@ -101,7 +101,9 @@ class UserHostingKeyForm(forms.ModelForm):
|
||||||
# print(self.fields)
|
# print(self.fields)
|
||||||
|
|
||||||
def clean_name(self):
|
def clean_name(self):
|
||||||
return ''.join(random.choice(string.ascii_lowercase) for i in range(7))
|
return "dcl-priv-key-%s" % (
|
||||||
|
''.join(random.choice(string.ascii_lowercase) for i in range(7))
|
||||||
|
)
|
||||||
|
|
||||||
def clean_user(self):
|
def clean_user(self):
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
@ -109,8 +111,6 @@ class UserHostingKeyForm(forms.ModelForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
|
|
||||||
print(cleaned_data)
|
|
||||||
|
|
||||||
if not cleaned_data.get('public_key'):
|
if not cleaned_data.get('public_key'):
|
||||||
private_key, public_key = UserHostingKey.generate_keys()
|
private_key, public_key = UserHostingKey.generate_keys()
|
||||||
cleaned_data.update({
|
cleaned_data.update({
|
||||||
|
|
|
@ -185,18 +185,31 @@ class VirtualMachinePlan(AssignPermissionsMixin, models.Model):
|
||||||
instance.assign_permissions(user)
|
instance.assign_permissions(user)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def cancel_plan(self):
|
def cancel_plan(self, vm_id):
|
||||||
self.status = self.CANCELED_STATUS
|
self.status = self.CANCELED_STATUS
|
||||||
self.save(update_fields=['status'])
|
self.save(update_fields=['status'])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def terminate_opennebula_vm(self, user, vm_id):
|
||||||
|
|
||||||
|
opennebula_client = OpenNebulaManager(
|
||||||
|
user.email,
|
||||||
|
user.password,
|
||||||
|
)
|
||||||
|
|
||||||
|
return opennebula_client.terminate_vm(vm_id)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_opennebula_vm(self, user, specs):
|
def create_opennebula_vm(self, user, specs):
|
||||||
|
# import pdb
|
||||||
|
# pdb.set_trace()
|
||||||
|
|
||||||
|
|
||||||
# Init opennebula manager using given user
|
# Init opennebula manager using given user
|
||||||
opennebula_client = OpenNebulaManager(
|
opennebula_client = OpenNebulaManager(
|
||||||
user.email,
|
user.email,
|
||||||
user.password[0:20],
|
user.password,
|
||||||
create_user=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a vm in opennebula using given specs
|
# Create a vm in opennebula using given specs
|
||||||
|
|
|
@ -35,7 +35,7 @@ class OpenNebulaManager:
|
||||||
'11': 'CLONING_FAILURE',
|
'11': 'CLONING_FAILURE',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, email=None, password=None, create_user=True):
|
def __init__(self, email=None, password=None):
|
||||||
|
|
||||||
# Get oneadmin client
|
# Get oneadmin client
|
||||||
self.oneadmin_client = self._get_opennebula_client(
|
self.oneadmin_client = self._get_opennebula_client(
|
||||||
|
@ -43,9 +43,6 @@ class OpenNebulaManager:
|
||||||
settings.OPENNEBULA_PASSWORD
|
settings.OPENNEBULA_PASSWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
if not create_user:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get or create oppenebula user using given credentials
|
# Get or create oppenebula user using given credentials
|
||||||
self.opennebula_user = self._get_or_create_user(
|
self.opennebula_user = self._get_or_create_user(
|
||||||
email,
|
email,
|
||||||
|
@ -121,9 +118,17 @@ class OpenNebulaManager:
|
||||||
|
|
||||||
return vm_data
|
return vm_data
|
||||||
|
|
||||||
|
def change_user_password(self, new_password):
|
||||||
|
self.oneadmin_client.call(
|
||||||
|
oca.User.METHODS['passwd'],
|
||||||
|
self.opennebula_user.id,
|
||||||
|
new_password
|
||||||
|
)
|
||||||
|
|
||||||
def create_vm(self, specs):
|
def create_vm(self, specs):
|
||||||
vm_id = None
|
vm_id = None
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# We do have the vm_template param set. Get and parse it
|
# We do have the vm_template param set. Get and parse it
|
||||||
# and check it to be in the desired range.
|
# and check it to be in the desired range.
|
||||||
# We have 8 possible VM templates for the moment which are 1x, 2x, 4x ...
|
# We have 8 possible VM templates for the moment which are 1x, 2x, 4x ...
|
||||||
|
@ -136,6 +141,9 @@ class OpenNebulaManager:
|
||||||
<TYPE>{disk_type}</TYPE>
|
<TYPE>{disk_type}</TYPE>
|
||||||
<SIZE>{size}</SIZE>
|
<SIZE>{size}</SIZE>
|
||||||
</DISK>
|
</DISK>
|
||||||
|
<CONTEXT>
|
||||||
|
<SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY>
|
||||||
|
</CONTEXT>
|
||||||
</VM>
|
</VM>
|
||||||
"""
|
"""
|
||||||
vm_id = oca.VirtualMachine.allocate(
|
vm_id = oca.VirtualMachine.allocate(
|
||||||
|
@ -145,7 +153,8 @@ class OpenNebulaManager:
|
||||||
vcpu=specs.get('cores'),
|
vcpu=specs.get('cores'),
|
||||||
cpu=0.1 * specs.get('cores'),
|
cpu=0.1 * specs.get('cores'),
|
||||||
disk_type='fs',
|
disk_type='fs',
|
||||||
size=10000 * specs.get('disk_size')
|
size=10000 * specs.get('disk_size'),
|
||||||
|
ssh_key=specs.get('ssh_key')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -155,10 +164,6 @@ class OpenNebulaManager:
|
||||||
self.opennebula_user.id,
|
self.opennebula_user.id,
|
||||||
self.opennebula_user.group_ids[0]
|
self.opennebula_user.group_ids[0]
|
||||||
)
|
)
|
||||||
# oca.VirtualMachine.chown(
|
|
||||||
# vm_id,
|
|
||||||
|
|
||||||
# )
|
|
||||||
|
|
||||||
except socket.timeout as socket_err:
|
except socket.timeout as socket_err:
|
||||||
logger.error("Socket timeout error: {0}".format(socket_err))
|
logger.error("Socket timeout error: {0}".format(socket_err))
|
||||||
|
@ -171,6 +176,29 @@ class OpenNebulaManager:
|
||||||
|
|
||||||
return vm_id
|
return vm_id
|
||||||
|
|
||||||
|
def terminate_vm(self, vm_id):
|
||||||
|
|
||||||
|
TERMINATE_ACTION = 'terminate'
|
||||||
|
vm_terminated = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.oneadmin_client.call(
|
||||||
|
oca.VirtualMachine.METHODS['action'],
|
||||||
|
TERMINATE_ACTION,
|
||||||
|
int(vm_id),
|
||||||
|
)
|
||||||
|
vm_terminated = True
|
||||||
|
except socket.timeout as socket_err:
|
||||||
|
logger.error("Socket timeout error: {0}".format(socket_err))
|
||||||
|
except OpenNebulaException as opennebula_err:
|
||||||
|
logger.error("OpenNebulaException error: {0}".format(opennebula_err))
|
||||||
|
except OSError as os_err:
|
||||||
|
logger.error("OSError : {0}".format(os_err))
|
||||||
|
except ValueError as value_err:
|
||||||
|
logger.error("ValueError : {0}".format(value_err))
|
||||||
|
|
||||||
|
return vm_terminated
|
||||||
|
|
||||||
def get_vm_templates(self):
|
def get_vm_templates(self):
|
||||||
template_pool = oca.VmTemplatePool(self.oneadmin_client)
|
template_pool = oca.VmTemplatePool(self.oneadmin_client)
|
||||||
template_pool.info()
|
template_pool.info()
|
||||||
|
|
|
@ -170,16 +170,28 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<button type="text" data-href="{% url 'hosting:virtual_machines' virtual_machine.id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-danger">{% trans "Cancel Virtual Machine"%}</button>
|
<button type="text" data-href="{% url 'hosting:virtual_machines' virtual_machine.id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-danger">{% trans "Terminate Virtual Machine"%}</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<br/>
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% for message in messages %}
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Cancel Modal -->
|
<!-- Cancel Modal -->
|
||||||
<div class="modal fade" id="confirm-cancel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="confirm-cancel" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
{% trans "Cancel your Virtual Machine"%}
|
{% trans "Terminate your Virtual Machine"%}
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
{% trans "Are you sure do you want to cancel your Virtual Machine "%} {{vm.virtual_machine}} {% trans "plan?"%}
|
{% trans "Are you sure do you want to cancel your Virtual Machine "%} {{vm.virtual_machine}} {% trans "plan?"%}
|
||||||
|
|
|
@ -9,11 +9,18 @@
|
||||||
<form method="POST" action="" >
|
<form method="POST" action="" >
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "Access Key"%} </h3>
|
<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 %}
|
||||||
<hr/>
|
<hr/>
|
||||||
{% if not user_key %}
|
{% if not user_key %}
|
||||||
<div class="alert alert-warning">
|
<h3>
|
||||||
{% trans "Upload your own key. "%}
|
{% trans "Upload your own key. "%}
|
||||||
</div>
|
</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="comment">Paste here your public key</label>
|
<label for="comment">Paste here your public key</label>
|
||||||
<textarea class="form-control" rows="6" name="public_key"></textarea>
|
<textarea class="form-control" rows="6" name="public_key"></textarea>
|
||||||
|
@ -22,10 +29,10 @@
|
||||||
<button class="btn btn-success">{% trans "Upload Key"%} </a>
|
<button class="btn btn-success">{% trans "Upload Key"%} </a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-warning">
|
<h3>
|
||||||
{% trans "Or generate a new key pair."%}
|
{% trans "Or generate a new key pair."%}
|
||||||
|
|
||||||
</div>
|
</h3>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-success">{% trans "Generate Key Pair"%} </a>
|
<button class="btn btn-success">{% trans "Generate Key Pair"%} </a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +65,7 @@
|
||||||
{% if private_key %}
|
{% if private_key %}
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
|
|
||||||
<strong>{% trans "Warning!"%}</strong>{% trans "You can view your SSH private key once. Don't lost your key"%}
|
<strong>{% trans "Warning!"%}</strong>{% trans "You can download your SSH private key once. Don't lost your key"%}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<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>
|
||||||
|
|
|
@ -11,6 +11,16 @@
|
||||||
<a class="btn btn-success" href="{% url 'hosting:create-virtual-machine' %}" >{% trans "Create VM"%} </a>
|
<a class="btn btn-success" href="{% url 'hosting:create-virtual-machine' %}" >{% trans "Create VM"%} </a>
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<br/>
|
||||||
|
<div class="col-md-12">
|
||||||
|
<br/>
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% for message in messages %}
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "ID"%}</th>
|
<th>{% trans "ID"%}</th>
|
||||||
|
|
141
hosting/views.py
141
hosting/views.py
|
@ -11,7 +11,8 @@ from django.contrib.auth import authenticate, login
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.utils.http import urlsafe_base64_decode
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
|
||||||
from guardian.mixins import PermissionRequiredMixin
|
from guardian.mixins import PermissionRequiredMixin
|
||||||
from stored_messages.settings import stored_messages_settings
|
from stored_messages.settings import stored_messages_settings
|
||||||
|
@ -186,6 +187,43 @@ class PasswordResetConfirmView(PasswordResetConfirmViewMixin):
|
||||||
template_name = 'hosting/confirm_reset_password.html'
|
template_name = 'hosting/confirm_reset_password.html'
|
||||||
success_url = reverse_lazy('hosting:login')
|
success_url = reverse_lazy('hosting:login')
|
||||||
|
|
||||||
|
def post(self, request, uidb64=None, token=None, *arg, **kwargs):
|
||||||
|
try:
|
||||||
|
uid = urlsafe_base64_decode(uidb64)
|
||||||
|
user = CustomUser.objects.get(pk=uid)
|
||||||
|
|
||||||
|
opennebula_client = OpenNebulaManager(
|
||||||
|
email=user.email,
|
||||||
|
password=user.password,
|
||||||
|
)
|
||||||
|
|
||||||
|
except (TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
|
||||||
|
user = None
|
||||||
|
opennebula_client = None
|
||||||
|
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
|
||||||
|
if user is not None and default_token_generator.check_token(user, token):
|
||||||
|
if form.is_valid():
|
||||||
|
new_password = form.cleaned_data['new_password2']
|
||||||
|
user.set_password(new_password)
|
||||||
|
user.save()
|
||||||
|
messages.success(request, 'Password has been reset.')
|
||||||
|
|
||||||
|
# Change opennebula password
|
||||||
|
opennebula_client.change_user_password(new_password)
|
||||||
|
|
||||||
|
return self.form_valid(form)
|
||||||
|
else:
|
||||||
|
messages.error(request, 'Password reset has not been successful.')
|
||||||
|
form.add_error(None, 'Password reset has not been successful.')
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
else:
|
||||||
|
messages.error(request, 'The reset password link is no longer valid.')
|
||||||
|
form.add_error(None, 'The reset password link is no longer valid.')
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
class NotificationsView(LoginRequiredMixin, TemplateView):
|
class NotificationsView(LoginRequiredMixin, TemplateView):
|
||||||
template_name = 'hosting/notifications.html'
|
template_name = 'hosting/notifications.html'
|
||||||
|
@ -261,14 +299,6 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
|
||||||
'form': UserHostingKeyForm(request=self.request)
|
'form': UserHostingKeyForm(request=self.request)
|
||||||
})
|
})
|
||||||
|
|
||||||
del(context['form'])
|
|
||||||
context.update({
|
|
||||||
'form': form
|
|
||||||
})
|
|
||||||
form = UserHostingKeyForm(request=self.request)
|
|
||||||
|
|
||||||
print("context", context)
|
|
||||||
|
|
||||||
# return HttpResponseRedirect(reverse('hosting:key_pair'))
|
# return HttpResponseRedirect(reverse('hosting:key_pair'))
|
||||||
return render(self.request, self.template_name, context)
|
return render(self.request, self.template_name, context)
|
||||||
|
|
||||||
|
@ -332,6 +362,21 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
try:
|
||||||
|
UserHostingKey.objects.get(
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
except UserHostingKey.DoesNotExist:
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
'In order to create a VM, you create/upload your SSH KEY first.'
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(reverse('hosting:key_pair'))
|
||||||
|
|
||||||
|
return self.render_to_response(self.get_context_data())
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
|
|
||||||
|
@ -415,13 +460,27 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
# If the Stripe payment was successed, set order status approved
|
# If the Stripe payment was successed, set order status approved
|
||||||
order.set_approved()
|
order.set_approved()
|
||||||
|
|
||||||
|
# Get user ssh key
|
||||||
|
try:
|
||||||
|
user_key = UserHostingKey.objects.get(
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add ssh_key to specs
|
||||||
|
specs.update({
|
||||||
|
'ssh_key': user_key.public_key
|
||||||
|
})
|
||||||
|
|
||||||
|
except UserHostingKey.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
# Create a vm using logged user
|
# Create a vm using logged user
|
||||||
oppennebula_vm_id = VirtualMachinePlan.create_opennebula_vm(
|
opennebula_vm_id = VirtualMachinePlan.create_opennebula_vm(
|
||||||
self.request.user,
|
self.request.user,
|
||||||
specs
|
specs
|
||||||
)
|
)
|
||||||
|
|
||||||
plan.oppenebula_id = oppennebula_vm_id
|
plan.opennebula_id = opennebula_vm_id
|
||||||
plan.save()
|
plan.save()
|
||||||
|
|
||||||
# Send notification to ungleich as soon as VM has been booked
|
# Send notification to ungleich as soon as VM has been booked
|
||||||
|
@ -503,6 +562,18 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
try:
|
||||||
|
UserHostingKey.objects.get(
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
except UserHostingKey.DoesNotExist:
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
'In order to create a VM, you need to create/upload your SSH KEY first.'
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(reverse('hosting:key_pair'))
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'vm_types': VirtualMachineType.get_serialized_vm_types(),
|
'vm_types': VirtualMachineType.get_serialized_vm_types(),
|
||||||
'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
|
'configuration_options': VirtualMachinePlan.VM_CONFIGURATION
|
||||||
|
@ -565,18 +636,26 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
|
||||||
# except Exception as error:
|
# except Exception as error:
|
||||||
# raise Http404()
|
# raise Http404()
|
||||||
|
|
||||||
# def get_success_url(self):
|
def get_object(self):
|
||||||
# vm = self.get_object()
|
opennebula_vm_id = self.kwargs.get('pk')
|
||||||
# final_url = "%s%s" % (reverse('hosting:virtual_machines', kwargs={'pk': vm.id}),
|
opennebula_vm = None
|
||||||
# '#status-v')
|
try:
|
||||||
# return final_url
|
opennebula_vm = VirtualMachinePlan.objects.get(opennebula_id=opennebula_vm_id)
|
||||||
|
except Exception as error:
|
||||||
|
print(error)
|
||||||
|
raise Http404()
|
||||||
|
return opennebula_vm
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
final_url = reverse('hosting:virtual_machines')
|
||||||
|
return final_url
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
vm_id = self.kwargs.get('pk')
|
opennebula_vm_id = self.kwargs.get('pk')
|
||||||
try:
|
try:
|
||||||
opennebula_vm = VirtualMachinePlan.get_vm(
|
opennebula_vm = VirtualMachinePlan.get_vm(
|
||||||
self.request.user,
|
self.request.user,
|
||||||
vm_id
|
opennebula_vm_id
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print(error)
|
print(error)
|
||||||
|
@ -588,9 +667,24 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
|
||||||
# context = {}
|
# context = {}
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
def post(self, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
vm = self.get_object()
|
vm = self.get_object()
|
||||||
vm.cancel_plan()
|
|
||||||
|
opennebula_vm_id = self.kwargs.get('pk')
|
||||||
|
|
||||||
|
terminated = VirtualMachinePlan.terminate_opennebula_vm(
|
||||||
|
self.request.user,
|
||||||
|
opennebula_vm_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if not terminated:
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
'Error terminating VM %s' % (opennebula_vm_id)
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
|
#vm.cancel_plan()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'vm': vm,
|
'vm': vm,
|
||||||
|
@ -606,8 +700,14 @@ class VirtualMachineView(PermissionRequiredMixin, LoginRequiredMixin, View):
|
||||||
email = BaseEmail(**email_data)
|
email = BaseEmail(**email_data)
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
'VM %s terminated successfully' % (opennebula_vm_id)
|
||||||
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(self.get_success_url())
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
|
|
||||||
class HostingBillListView(LoginRequiredMixin, ListView):
|
class HostingBillListView(LoginRequiredMixin, ListView):
|
||||||
template_name = "hosting/bills.html"
|
template_name = "hosting/bills.html"
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
@ -616,6 +716,7 @@ class HostingBillListView(LoginRequiredMixin, ListView):
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
ordering = '-id'
|
ordering = '-id'
|
||||||
|
|
||||||
|
|
||||||
class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailView):
|
class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, DetailView):
|
||||||
template_name = "hosting/bill_detail.html"
|
template_name = "hosting/bill_detail.html"
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
|
|
Loading…
Reference in a new issue