dynamicweb/hosting/views.py

1079 lines
40 KiB
Python
Raw Normal View History

import logging
import subprocess
import uuid
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.tokens import default_token_generator
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse_lazy, reverse
from django.http import Http404
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.shortcuts import render
from django.utils.http import urlsafe_base64_decode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.views.generic import View, CreateView, FormView, ListView, \
DetailView, \
DeleteView, TemplateView, UpdateView
from guardian.mixins import PermissionRequiredMixin
from oca.pool import WrongIdError
from stored_messages.api import mark_read
from stored_messages.models import Message
from stored_messages.settings import stored_messages_settings
from membership.models import CustomUser, StripeCustomer
from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineSerializer, \
VirtualMachineTemplateSerializer
from utils.forms import BillingAddressForm, PasswordResetRequestForm, \
UserBillingAddressForm
from utils.hosting_utils import get_all_public_keys
from utils.mailer import BaseEmail
from utils.stripe_utils import StripeUtils
from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, \
LoginViewMixin
from .forms import HostingUserSignupForm, HostingUserLoginForm, \
UserHostingKeyForm, generate_ssh_key_name
from .mixins import ProcessVMSelectionMixin
from .models import HostingOrder, HostingBill, HostingPlan, UserHostingKey
logger = logging.getLogger(__name__)
2017-05-13 04:59:57 +00:00
CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \
backend connection error. please try again in a few \
minutes."
class DashboardView(View):
template_name = "hosting/dashboard.html"
def get_context_data(self, **kwargs):
context = {}
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
return render(request, self.template_name, context)
class DjangoHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/django.html"
def get_context_data(self, **kwargs):
HOSTING = 'django'
2017-05-13 05:31:29 +00:00
templates = OpenNebulaManager().get_templates()
data = VirtualMachineTemplateSerializer(templates, many=True).data
configuration_options = HostingPlan.get_serialized_configs()
2017-05-13 05:31:29 +00:00
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
context = {
'hosting': HOSTING,
'hosting_long': "Django",
2017-05-13 05:31:29 +00:00
# 'configuration_detail': configuration_detail,
'domain': "django-hosting.ch",
'google_analytics': "UA-62285904-6",
2017-05-13 05:31:29 +00:00
'vm_types': data,
'email': "info@django-hosting.ch",
'configuration_options': configuration_options,
'templates': templates,
}
return context
def get(self, request, *args, **kwargs):
request.session['hosting_url'] = reverse('hosting:djangohosting')
context = self.get_context_data()
return render(request, self.template_name, context)
class RailsHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/rails.html"
def get_context_data(self, **kwargs):
HOSTING = 'rails'
2017-05-13 05:31:29 +00:00
templates = OpenNebulaManager().get_templates()
configuration_options = HostingPlan.get_serialized_configs()
2017-05-13 05:31:29 +00:00
context = {
'hosting': HOSTING,
'hosting_long': "Ruby On Rails",
'domain': "rails-hosting.ch",
'google_analytics': "UA-62285904-5",
'email': "info@rails-hosting.ch",
'configuration_options': configuration_options,
'templates': templates,
}
return context
def get(self, request, *args, **kwargs):
request.session['hosting_url'] = reverse('hosting:railshosting')
context = self.get_context_data()
return render(request, self.template_name, context)
class NodeJSHostingView(ProcessVMSelectionMixin, View):
template_name = "hosting/nodejs.html"
def get_context_data(self, **kwargs):
HOSTING = 'nodejs'
2017-05-13 05:31:29 +00:00
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
templates = OpenNebulaManager().get_templates()
configuration_options = HostingPlan.get_serialized_configs()
2017-05-13 05:31:29 +00:00
context = {
2017-05-13 05:31:29 +00:00
'hosting': HOSTING,
'hosting_long': "NodeJS",
2017-05-13 05:31:29 +00:00
# 'configuration_detail': configuration_detail,
'domain': "node-hosting.ch",
'google_analytics': "UA-62285904-7",
'email': "info@node-hosting.ch",
'templates': templates,
'configuration_options': configuration_options,
}
return context
def get(self, request, *args, **kwargs):
request.session['hosting_url'] = reverse('hosting:nodejshosting')
context = self.get_context_data()
return render(request, self.template_name, context)
class HostingPricingView(ProcessVMSelectionMixin, View):
template_name = "hosting/hosting_pricing.html"
def get_context_data(self, **kwargs):
2017-05-13 05:31:29 +00:00
# configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
templates = OpenNebulaManager().get_templates()
configuration_options = HostingPlan.get_serialized_configs()
2017-05-13 05:31:29 +00:00
context = {
2017-05-13 05:31:29 +00:00
# 'configuration_options': configuration_options,
'email': "info@django-hosting.ch",
'templates': templates,
'configuration_options': configuration_options,
}
return context
def get(self, request, *args, **kwargs):
request.session['hosting_url'] = reverse('hosting:djangohosting')
context = self.get_context_data()
return render(request, self.template_name, context)
class IndexView(View):
template_name = "hosting/index.html"
def get_context_data(self, **kwargs):
2017-05-13 05:31:29 +00:00
templates = OpenNebulaManager().get_templates()
data = VirtualMachineTemplateSerializer(templates, many=True).data
context = {
'hosting': "nodejs",
'hosting_long': "NodeJS",
'domain': "node-hosting.ch",
'google_analytics': "UA-62285904-7",
'email': "info@node-hosting.ch",
2017-05-13 05:31:29 +00:00
'vm_types': data
# 'vm_types': VirtualMachineType.get_serialized_vm_types(),
}
return context
def get(self, request, *args, **kwargs):
context = self.get_context_data()
return render(request, self.template_name, context)
class LoginView(LoginViewMixin):
template_name = "hosting/login.html"
form_class = HostingUserLoginForm
success_url = reverse_lazy('hosting:dashboard')
class SignupView(CreateView):
template_name = 'hosting/signup.html'
form_class = HostingUserSignupForm
2016-05-18 22:58:28 +00:00
model = CustomUser
2017-06-03 13:03:55 +00:00
success_url = reverse_lazy('hosting:ssh_keys')
def get_success_url(self):
next_url = self.request.session.get(
'next', self.success_url)
2016-04-30 18:55:55 +00:00
return next_url
def form_valid(self, form):
name = form.cleaned_data.get('name')
email = form.cleaned_data.get('email')
password = form.cleaned_data.get('password')
2017-07-26 11:15:49 +00:00
this_base_url = "{0}://{1}".format(self.request.scheme,
self.request.get_host())
CustomUser.register(name, password, email,
app='dcl', base_url=this_base_url)
return HttpResponseRedirect(reverse_lazy('hosting:signup-validate'))
class SignupValidateView(TemplateView):
template_name = "hosting/signup_validate.html"
def get_context_data(self, **kwargs):
context = super(SignupValidateView, self).get_context_data(**kwargs)
2017-07-26 11:15:49 +00:00
login_url = '<a href="' + \
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
2017-07-26 11:15:49 +00:00
home_url = '<a href="' + \
reverse('datacenterlight:index') + '">Data Center Light</a>'
2017-06-29 16:23:25 +00:00
message = '{signup_success_message} {lurl}</a> \
<br />{go_back} {hurl}.'.format(
2017-06-29 16:23:25 +00:00
signup_success_message=_(
'Thank you for signing up. We have sent an email to you. '
'Please follow the instructions in it to activate your account. Once activated, you can login using'),
go_back=_('Go back to'),
lurl=login_url,
hurl=home_url
)
context['message'] = mark_safe(message)
context['section_title'] = _('Sign up')
return context
2015-08-09 20:13:38 +00:00
class SignupValidatedView(SignupValidateView):
template_name = "hosting/signup_validate.html"
def get_context_data(self, **kwargs):
context = super(SignupValidateView, self).get_context_data(**kwargs)
validated = CustomUser.validate_url(self.kwargs['validate_slug'])
2017-07-26 11:15:49 +00:00
login_url = '<a href="' + \
reverse('hosting:login') + '">' + str(_('login')) + '</a>'
2017-06-29 16:23:25 +00:00
section_title = _('Account activation')
if validated:
2017-06-29 16:23:25 +00:00
message = '{account_activation_string} <br /> {login_string} {lurl}.'.format(
2017-07-26 11:15:49 +00:00
account_activation_string=_(
"Your account has been activated."),
2017-06-29 16:23:25 +00:00
login_string=_("You can now"),
lurl=login_url)
else:
2017-07-26 11:15:49 +00:00
home_url = '<a href="' + \
2017-08-18 20:51:34 +00:00
reverse('datacenterlight:index') + \
'">Data Center Light</a>'
message = '{sorry_message} <br />{go_back_to} {hurl}'.format(
2017-06-29 16:23:25 +00:00
sorry_message=_("Sorry. Your request is invalid."),
go_back_to=_('Go back to'),
hurl=home_url
)
context['message'] = mark_safe(message)
context['section_title'] = section_title
return context
class PasswordResetView(PasswordResetViewMixin):
2017-06-12 15:21:48 +00:00
site = 'dcl'
template_name = 'hosting/reset_password.html'
form_class = PasswordResetRequestForm
success_url = reverse_lazy('hosting:login')
template_email_path = 'hosting/emails/'
class PasswordResetConfirmView(PasswordResetConfirmViewMixin):
template_name = 'hosting/confirm_reset_password.html'
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:
error_msg = _('The reset password link is no longer valid.')
messages.error(request, _(error_msg))
form.add_error(None, error_msg)
return self.form_invalid(form)
class NotificationsView(LoginRequiredMixin, TemplateView):
template_name = 'hosting/notifications.html'
login_url = reverse_lazy('hosting:login')
def get_context_data(self, **kwargs):
context = super(NotificationsView, self).get_context_data(**kwargs)
backend = stored_messages_settings.STORAGE_BACKEND()
unread_notifications = backend.inbox_list(self.request.user)
read_notifications = backend.archive_list(self.request.user)
context.update({
'unread_notifications': unread_notifications,
'all_notifications': read_notifications + unread_notifications
})
return context
class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView):
model = Message
success_url = reverse_lazy('hosting:notifications')
login_url = reverse_lazy('hosting:login')
fields = '__all__'
def post(self, *args, **kwargs):
message = self.get_object()
backend = stored_messages_settings.STORAGE_BACKEND()
backend.archive_store([self.request.user], message)
mark_read(self.request.user, message)
return HttpResponseRedirect(reverse('hosting:notifications'))
2017-06-03 11:33:05 +00:00
class SSHKeyDeleteView(LoginRequiredMixin, DeleteView):
login_url = reverse_lazy('hosting:login')
2017-06-03 13:03:55 +00:00
success_url = reverse_lazy('hosting:ssh_keys')
2017-06-03 11:33:05 +00:00
model = UserHostingKey
def get_object(self, queryset=None):
""" Hook to ensure UserHostingKey object is owned by request.user.
We reply with a Http404 if the user is not the owner of the key.
"""
obj = super(SSHKeyDeleteView, self).get_object()
if not obj.user == self.request.user:
raise Http404
return obj
2017-06-03 13:03:55 +00:00
def delete(self, request, *args, **kwargs):
owner = self.request.user
manager = OpenNebulaManager(
email=owner.email,
password=owner.password
)
2017-06-03 13:03:55 +00:00
pk = self.kwargs.get('pk')
# Get user ssh key
2017-06-09 20:36:14 +00:00
public_key = UserHostingKey.objects.get(pk=pk).public_key
manager.manage_public_key([{'value': public_key, 'state': False}])
2017-06-03 13:03:55 +00:00
return super(SSHKeyDeleteView, self).delete(request, *args, **kwargs)
2017-06-03 13:03:55 +00:00
class SSHKeyListView(LoginRequiredMixin, ListView):
template_name = "hosting/user_keys.html"
login_url = reverse_lazy('hosting:login')
2017-06-03 13:03:55 +00:00
context_object_name = "keys"
model = UserHostingKey
paginate_by = 10
ordering = '-id'
2017-06-03 13:03:55 +00:00
def get_queryset(self):
user = self.request.user
self.queryset = UserHostingKey.objects.filter(user=user)
return super(SSHKeyListView, self).get_queryset()
2017-06-03 13:03:55 +00:00
def render_to_response(self, context, **response_kwargs):
if not self.queryset:
2017-07-12 05:21:43 +00:00
return HttpResponseRedirect(reverse('hosting:choice_ssh_keys'))
return super(SSHKeyListView, self).render_to_response(context,
**response_kwargs)
2017-06-03 13:03:55 +00:00
class SSHKeyChoiceView(LoginRequiredMixin, View):
template_name = "hosting/choice_ssh_keys.html"
login_url = reverse_lazy('hosting:login')
def get(self, request, *args, **kwargs):
context = {}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
name = generate_ssh_key_name()
private_key, public_key = UserHostingKey.generate_keys()
content = ContentFile(private_key)
2017-07-26 11:15:49 +00:00
ssh_key = UserHostingKey.objects.create(
user=request.user, public_key=public_key, name=name)
filename = name + '_' + str(uuid.uuid4())[:8] + '_private.pem'
ssh_key.private_key.save(filename, content)
owner = self.request.user
manager = OpenNebulaManager(
email=owner.email,
password=owner.password
)
public_key_str = public_key.decode()
manager.manage_public_key([{'value': public_key_str, 'state': True}])
return redirect(reverse_lazy('hosting:ssh_keys'), foo='bar')
2017-06-03 13:03:55 +00:00
class SSHKeyCreateView(LoginRequiredMixin, FormView):
form_class = UserHostingKeyForm
model = UserHostingKey
template_name = 'hosting/user_key.html'
login_url = reverse_lazy('hosting:login')
context_object_name = "virtual_machine"
success_url = reverse_lazy('hosting:ssh_keys')
def get_form_kwargs(self):
2017-06-03 13:03:55 +00:00
kwargs = super(SSHKeyCreateView, self).get_form_kwargs()
kwargs.update({'request': self.request})
return kwargs
def form_valid(self, form):
form.save()
if 'dcl-generated-key-' in form.instance.name:
content = ContentFile(form.cleaned_data.get('private_key'))
2017-07-26 11:15:49 +00:00
filename = form.cleaned_data.get(
'name') + '_' + str(uuid.uuid4())[:8] + '_private.pem'
form.instance.private_key.save(filename, content)
context = self.get_context_data()
2017-05-24 15:58:16 +00:00
next_url = self.request.session.get(
'next',
reverse('hosting:create_virtual_machine')
)
if 'next' in self.request.session:
context.update({
'next_url': next_url
})
del (self.request.session['next'])
if form.cleaned_data.get('private_key'):
context.update({
'private_key': form.cleaned_data.get('private_key'),
'key_name': form.cleaned_data.get('name'),
2017-05-22 03:35:43 +00:00
'form': UserHostingKeyForm(request=self.request),
})
owner = self.request.user
manager = OpenNebulaManager(
email=owner.email,
password=owner.password
)
public_key = form.cleaned_data['public_key']
if type(public_key) is bytes:
public_key = public_key.decode()
manager.manage_public_key([{'value': public_key, 'state': True}])
2017-06-03 13:03:55 +00:00
return HttpResponseRedirect(self.success_url)
def post(self, request, *args, **kwargs):
2017-06-03 13:03:55 +00:00
print(self.request.POST.dict())
form = self.get_form()
required = 'add_ssh' in self.request.POST
form.fields['name'].required = required
form.fields['public_key'].required = required
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
2017-08-24 16:41:15 +00:00
class SettingsView(LoginRequiredMixin, FormView):
template_name = "hosting/settings.html"
login_url = reverse_lazy('hosting:login')
form_class = BillingAddressForm
2017-08-29 12:12:35 +00:00
def get_form(self, form_class):
"""
Check if the user already saved contact details. If so, then show
the form populated with those details, to let user change them.
"""
return form_class(
instance=self.request.user.billing_addresses.first(),
**self.get_form_kwargs())
2017-08-24 16:41:15 +00:00
def get_context_data(self, **kwargs):
context = super(SettingsView, self).get_context_data(**kwargs)
# Get user
user = self.request.user
# Get user last order
last_hosting_order = HostingOrder.objects.filter(
customer__user=user).last()
# If user has already an hosting order, get the credit card data from
# it
if last_hosting_order:
credit_card_data = last_hosting_order.get_cc_data()
context.update({
'credit_card_data': credit_card_data if credit_card_data else None,
})
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
})
return context
2017-08-29 12:12:35 +00:00
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
billing_address_data = form.cleaned_data
billing_address_data.update({
'user': self.request.user.id
})
billing_address_user_form = UserBillingAddressForm(
instance=self.request.user.billing_addresses.first(),
data=billing_address_data)
billing_address_user_form.save()
return self.render_to_response(self.get_context_data())
else:
billing_address_data = form.cleaned_data
return self.form_invalid(form)
2017-08-24 16:41:15 +00:00
class PaymentVMView(LoginRequiredMixin, FormView):
template_name = 'hosting/payment.html'
login_url = reverse_lazy('hosting:login')
form_class = BillingAddressForm
def get_form_kwargs(self):
current_billing_address = self.request.user.billing_addresses.first()
form_kwargs = super(PaymentVMView, self).get_form_kwargs()
if not current_billing_address:
return form_kwargs
form_kwargs.update({
'initial': {
'cardholder_name': current_billing_address.cardholder_name,
'street_address': current_billing_address.street_address,
'city': current_billing_address.city,
'postal_code': current_billing_address.postal_code,
'country': current_billing_address.country,
}
})
return form_kwargs
def get_context_data(self, **kwargs):
context = super(PaymentVMView, self).get_context_data(**kwargs)
# Get user
user = self.request.user
# Get user last order
last_hosting_order = HostingOrder.objects.filter(
customer__user=user).last()
# If user has already an hosting order, get the credit card data from
# it
if last_hosting_order:
credit_card_data = last_hosting_order.get_cc_data()
context.update({
'credit_card_data': credit_card_data if credit_card_data else None,
})
context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
})
return context
def get(self, request, *args, **kwargs):
if not UserHostingKey.objects.filter(user=self.request.user).exists():
messages.success(
request,
'In order to create a VM, you create/upload your SSH KEY first.'
)
2017-06-03 13:03:55 +00:00
return HttpResponseRedirect(reverse('hosting:ssh_keys'))
2017-05-24 15:58:16 +00:00
if 'next' in request.session:
del request.session['next']
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
# Get billing address data
billing_address_data = form.cleaned_data
context = self.get_context_data()
2017-05-13 11:47:53 +00:00
template = request.session.get('template')
specs = request.session.get('specs')
2017-05-13 11:47:53 +00:00
vm_template_id = template.get('id', 1)
2017-05-13 11:47:53 +00:00
final_price = specs.get('price')
token = form.cleaned_data.get('token')
2015-08-09 20:13:38 +00:00
owner = self.request.user
# Get or create stripe customer
customer = StripeCustomer.get_or_create(email=owner.email,
token=token)
if not customer:
2017-08-07 14:23:58 +00:00
msg = _("Invalid credit card")
messages.add_message(
self.request, messages.ERROR, msg,
extra_tags='make_charge_error')
return HttpResponseRedirect(
reverse('hosting:payment') + '#payment_error')
# Create Billing Address
billing_address = form.save()
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=final_price,
2016-04-30 18:55:55 +00:00
customer=customer.stripe_id)
2015-09-22 11:37:22 +00:00
2016-04-30 18:55:55 +00:00
# Check if the payment was approved
if not charge_response.get('response_object'):
msg = charge_response.get('error')
messages.add_message(
self.request, messages.ERROR, msg,
extra_tags='make_charge_error')
return HttpResponseRedirect(
reverse('hosting:payment') + '#payment_error')
charge = charge_response.get('response_object')
2017-05-12 17:13:18 +00:00
# Create OpenNebulaManager
manager = OpenNebulaManager(email=owner.email,
password=owner.password)
# Get user ssh key
if not UserHostingKey.objects.filter(
user=self.request.user).exists():
context.update({
'sshError': 'error',
'form': form
})
return render(request, self.template_name, context)
# Create a vm using logged user
2017-05-12 17:13:18 +00:00
vm_id = manager.create_vm(
2017-05-13 04:59:57 +00:00
template_id=vm_template_id,
2017-05-13 11:47:53 +00:00
specs=specs,
ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY,
2017-05-12 17:13:18 +00:00
)
# Create a Hosting Order
2017-05-12 17:13:18 +00:00
order = HostingOrder.create(
price=final_price,
vm_id=vm_id,
customer=customer,
billing_address=billing_address
)
# Create a Hosting Bill
2017-07-06 18:42:29 +00:00
HostingBill.create(
2017-07-26 11:15:49 +00:00
customer=customer, billing_address=billing_address)
2017-05-12 17:13:18 +00:00
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
billing_address_data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(
billing_address_data)
2017-05-12 17:13:18 +00:00
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Associate an order with a stripe payment
order.set_stripe_charge(charge)
# If the Stripe payment was successed, set order status approved
order.set_approved()
vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
2017-09-02 16:38:25 +00:00
# Send notification to the user as soon as VM has been booked
2016-06-05 20:49:51 +00:00
context = {
'vm': vm,
'order': order,
'base_url': "{0}://{1}".format(request.scheme,
2017-09-02 16:38:25 +00:00
request.get_host()),
'page_header': _(
'Your New VM %(vm_name)s at Data Center Light') % {
'vm_name': vm.get('name')}
2016-06-05 20:49:51 +00:00
}
email_data = {
2017-09-02 16:38:25 +00:00
'subject': context.get('page_header'),
'to': request.user.email,
2016-06-05 20:49:51 +00:00
'context': context,
'template_name': 'new_booked_vm',
'template_path': 'hosting/emails/',
2017-09-02 18:42:58 +00:00
'from_address': settings.DCL_SUPPORT_FROM_ADDRESS,
}
email = BaseEmail(**email_data)
email.send()
# try to see if we have the IP and that if the ssh keys can
# be configured
new_host = manager.get_primary_ipv4(vm_id)
if new_host is not None:
public_keys = get_all_public_keys(owner)
keys = [{'value': key, 'state': True} for key in public_keys]
logger.debug(
"Calling configure on {host} for {num_keys} keys".format(
host=new_host, num_keys=len(keys)))
# Let's delay the task by 75 seconds to be sure that we run
# the cdist configure after the host is up
manager.manage_public_key(keys, hosts=[new_host], countdown=75)
2017-07-30 16:03:16 +00:00
return HttpResponseRedirect(
"{url}?{query_params}".format(
url=reverse('hosting:orders', kwargs={'pk': order.id}),
query_params='page=payment'))
else:
return self.form_invalid(form)
2016-04-30 18:55:55 +00:00
class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin,
DetailView):
template_name = "hosting/order_detail.html"
context_object_name = "order"
login_url = reverse_lazy('hosting:login')
permission_required = ['view_hostingorder']
model = HostingOrder
def get_context_data(self, **kwargs):
# Get context
context = super(DetailView, self).get_context_data(**kwargs)
obj = self.get_object()
owner = self.request.user
manager = OpenNebulaManager(email=owner.email,
password=owner.password)
if self.request.GET.get('page', '') == 'payment':
context['page_header_text'] = _('Confirm Order')
else:
context['page_header_text'] = _('Invoice')
2017-05-14 10:22:10 +00:00
try:
vm = manager.get_vm(obj.vm_id)
context['vm'] = VirtualMachineSerializer(vm).data
except WrongIdError:
messages.error(self.request,
'The VM you are looking for is unavailable at the moment. \
Please contact Data Center Light support.'
)
self.kwargs['error'] = 'WrongIdError'
context['error'] = 'WrongIdError'
2017-05-14 10:22:10 +00:00
except ConnectionRefusedError:
messages.error(self.request,
2017-09-04 16:57:59 +00:00
_(
'In order to create a VM, you need to create/upload your SSH KEY first.')
)
2017-05-12 17:13:18 +00:00
return context
class OrdersHostingListView(LoginRequiredMixin, ListView):
template_name = "hosting/orders.html"
login_url = reverse_lazy('hosting:login')
context_object_name = "orders"
model = HostingOrder
paginate_by = 10
ordering = '-id'
def get_queryset(self):
user = self.request.user
self.queryset = HostingOrder.objects.filter(customer__user=user)
return super(OrdersHostingListView, self).get_queryset()
class OrdersHostingDeleteView(LoginRequiredMixin, DeleteView):
login_url = reverse_lazy('hosting:login')
2016-05-18 22:58:28 +00:00
success_url = reverse_lazy('hosting:orders')
model = HostingOrder
class VirtualMachinesPlanListView(LoginRequiredMixin, ListView):
template_name = "hosting/virtual_machines.html"
login_url = reverse_lazy('hosting:login')
context_object_name = "vms"
paginate_by = 10
ordering = '-id'
def get_queryset(self):
owner = self.request.user
manager = OpenNebulaManager(email=owner.email,
password=owner.password)
2017-05-14 10:22:10 +00:00
try:
queryset = manager.get_vms()
serializer = VirtualMachineSerializer(queryset, many=True)
return serializer.data
except ConnectionRefusedError:
messages.error(self.request,
'We could not load your VMs due to a backend connection \
2017-05-14 10:22:10 +00:00
error. Please try again in a few minutes'
)
2017-05-14 10:22:10 +00:00
self.kwargs['error'] = 'connection'
return []
def get_context_data(self, **kwargs):
error = self.kwargs.get('error')
if error is not None:
print(error)
context = {'error': 'connection'}
2017-05-14 10:22:10 +00:00
else:
context = super(ListView, self).get_context_data(**kwargs)
return context
class CreateVirtualMachinesView(LoginRequiredMixin, View):
template_name = "hosting/create_virtual_machine.html"
login_url = reverse_lazy('hosting:login')
def get(self, request, *args, **kwargs):
if not UserHostingKey.objects.filter(user=self.request.user).exists():
messages.success(
request,
2017-09-04 16:57:59 +00:00
_(
'In order to create a VM, you need to create/upload your SSH KEY first.')
)
2017-06-03 13:03:55 +00:00
return HttpResponseRedirect(reverse('hosting:ssh_keys'))
2017-05-14 10:22:10 +00:00
try:
manager = OpenNebulaManager()
templates = manager.get_templates()
configuration_options = HostingPlan.get_serialized_configs()
context = {
'templates': VirtualMachineTemplateSerializer(templates,
many=True).data,
2017-05-24 15:58:16 +00:00
'configuration_options': configuration_options,
2017-05-14 10:22:10 +00:00
}
except:
2017-05-24 15:58:16 +00:00
messages.error(
request,
2017-05-14 10:22:10 +00:00
'We could not load the VM templates due to a backend connection \
error. Please try again in a few minutes'
2017-05-24 15:58:16 +00:00
)
2017-05-14 10:22:10 +00:00
context = {
2017-05-24 15:58:16 +00:00
'error': 'connection'
}
2017-05-12 17:13:18 +00:00
return render(request, self.template_name, context)
def post(self, request):
2017-05-13 04:59:57 +00:00
manager = OpenNebulaManager()
template_id = request.POST.get('vm_template_id')
template = manager.get_template(template_id)
2017-05-13 11:47:53 +00:00
configuration_id = int(request.POST.get('configuration'))
configuration = HostingPlan.objects.get(id=configuration_id)
request.session['template'] = VirtualMachineTemplateSerializer(
template).data
2017-05-13 11:47:53 +00:00
request.session['specs'] = configuration.serialize()
return redirect(reverse('hosting:payment'))
class VirtualMachineView(LoginRequiredMixin, View):
template_name = "hosting/virtual_machine_detail.html"
login_url = reverse_lazy('hosting:login')
2017-05-09 00:02:29 +00:00
def get_object(self):
owner = self.request.user
2017-05-12 17:13:18 +00:00
vm = None
manager = OpenNebulaManager(
email=owner.email,
password=owner.password
2017-05-12 17:13:18 +00:00
)
vm_id = self.kwargs.get('pk')
try:
vm = manager.get_vm(vm_id)
2017-05-14 10:22:10 +00:00
return vm
except WrongIdError:
messages.error(self.request,
_('We could not find the requested VM. Please \
contact Data Center Light Support.')
)
return None
2017-05-14 10:22:10 +00:00
except ConnectionRefusedError:
messages.error(self.request,
'We could not load your VM due to a backend connection \
2017-05-14 10:22:10 +00:00
error. Please try again in a few minutes'
)
2017-05-14 10:22:10 +00:00
return None
except Exception as error:
print(error)
raise Http404()
def get_success_url(self):
final_url = reverse('hosting:virtual_machines')
return final_url
2017-05-09 00:02:29 +00:00
def get(self, request, *args, **kwargs):
2017-05-12 17:13:18 +00:00
vm = self.get_object()
if vm is None:
return redirect(reverse('hosting:virtual_machines'))
try:
2017-05-14 10:22:10 +00:00
serializer = VirtualMachineSerializer(vm)
context = {
'virtual_machine': serializer.data,
'order': HostingOrder.objects.get(
vm_id=serializer.data['vm_id'])
2017-05-14 10:22:10 +00:00
}
except Exception as ex:
logger.debug("Exception generated {}".format(str(ex)))
2017-05-14 10:22:10 +00:00
pass
2017-05-09 00:02:29 +00:00
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
2017-05-12 17:13:18 +00:00
owner = self.request.user
vm = self.get_object()
opennebula_vm_id = self.kwargs.get('pk')
2017-05-12 17:13:18 +00:00
manager = OpenNebulaManager(
email=owner.email,
password=owner.password
2017-05-12 17:13:18 +00:00
)
vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data
2017-05-12 17:13:18 +00:00
terminated = manager.delete_vm(
vm.id
)
if not terminated:
messages.error(
request,
'Error terminating VM %s' % (opennebula_vm_id)
)
return HttpResponseRedirect(self.get_success_url())
context = {
'vm': vm_data,
'base_url': "{0}://{1}".format(self.request.scheme,
2017-09-02 21:03:05 +00:00
self.request.get_host()),
'page_header': _('Virtual Machine Cancellation')
}
email_data = {
2017-09-02 21:03:05 +00:00
'subject': context['page_header'],
'to': self.request.user.email,
'context': context,
2017-09-02 21:03:05 +00:00
'template_name': 'vm_canceled',
'template_path': 'hosting/emails/',
'from_address': settings.DCL_SUPPORT_FROM_ADDRESS,
}
email = BaseEmail(**email_data)
email.send()
messages.error(
request,
2017-09-04 16:57:59 +00:00
_('VM %(VM_ID)s terminated successfully') % {
'VM_ID': opennebula_vm_id}
)
# Remove all keys belonging to the IP(s)
# ssh-keygen -R ip_address
if vm_data['ipv4'] is not None:
if ', ' in vm_data['ipv4']:
vm_ips = vm_data['ipv4'].split(', ')
for ip_address in vm_ips:
try:
subprocess.check_output(
['ssh-keygen', '-R', ip_address])
except subprocess.CalledProcessError as cpe:
logger.debug(
"""Could not remove key belonging to {ip}.
Error details: {details}""".format(ip=ip_address,
details=str(
cpe)))
else:
try:
subprocess.check_output(
['ssh-keygen', '-R', vm_data['ipv4']])
except subprocess.CalledProcessError as cpe:
logger.debug(
"""Could not remove key belonging to {ip}.
Error details: {details}""".format(ip=vm_data['ipv4'],
details=str(cpe)))
if vm_data['ipv6'] is not None:
if ', ' in vm_data['ipv6']:
vm_ips = vm_data['ipv6'].split(', ')
for ip_address in vm_ips:
try:
subprocess.check_output(
['ssh-keygen', '-R', ip_address])
except subprocess.CalledProcessError as cpe:
logger.debug(
"""Could not remove key belonging to {ip}.
Error details: {details}""".format(ip=ip_address,
details=str(
cpe)))
else:
try:
subprocess.check_output(
['ssh-keygen', '-R', vm_data['ipv6']])
except subprocess.CalledProcessError as cpe:
logger.debug(
"""Could not remove key belonging to {ip}.
Error details: {details}""".format(ip=vm_data['ipv6'],
details=str(cpe)))
return HttpResponseRedirect(self.get_success_url())
2017-05-05 12:59:11 +00:00
class HostingBillListView(PermissionRequiredMixin, LoginRequiredMixin,
ListView):
2017-05-05 12:59:11 +00:00
template_name = "hosting/bills.html"
login_url = reverse_lazy('hosting:login')
2017-05-14 01:19:09 +00:00
permission_required = ['view_hostingview']
2017-05-05 12:59:11 +00:00
context_object_name = "users"
model = StripeCustomer
paginate_by = 10
ordering = '-id'
class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin,
DetailView):
2017-05-05 12:59:11 +00:00
template_name = "hosting/bill_detail.html"
login_url = reverse_lazy('hosting:login')
permission_required = ['view_hostingview']
context_object_name = "bill"
model = HostingBill
def get_object(self, queryset=None):
# Get HostingBill for primary key (Select from customer users)
2017-05-05 12:59:11 +00:00
pk = self.kwargs['pk']
object = HostingBill.objects.filter(customer__id=pk).first()
if object is None:
self.template_name = 'hosting/bill_error.html'
return object
2017-05-05 12:59:11 +00:00
def get_context_data(self, **kwargs):
# Get context
context = super(DetailView, self).get_context_data(**kwargs)
owner = self.request.user
manager = OpenNebulaManager(email=owner.email,
password=owner.password)
# Get vms
queryset = manager.get_vms()
vms = VirtualMachineSerializer(queryset, many=True).data
2017-05-13 11:47:53 +00:00
# Set total price
bill = context['bill']
bill.total_price = 0.0
for vm in vms:
bill.total_price += vm['price']
context['vms'] = vms
return context