resolve conflicts
This commit is contained in:
commit
398b7062e0
18 changed files with 244 additions and 81 deletions
|
@ -7,7 +7,7 @@ class BetaAccessForm(forms.ModelForm):
|
||||||
email = forms.CharField(widget=forms.EmailInput())
|
email = forms.CharField(widget=forms.EmailInput())
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = ['email']
|
fields = ['name', 'email']
|
||||||
model = BetaAccess
|
model = BetaAccess
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -820,4 +820,4 @@ a#forgotpassword {
|
||||||
}
|
}
|
||||||
.form-300{
|
.form-300{
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
12
datacenterlight/static/datacenterlight/js/form.js
Normal file
12
datacenterlight/static/datacenterlight/js/form.js
Normal file
File diff suppressed because one or more lines are too long
27
datacenterlight/templates/datacenterlight/beta_access.html
Normal file
27
datacenterlight/templates/datacenterlight/beta_access.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<form novalidate id ="beta_access" class="form-beta" method="POST" action="{% url 'datacenterlight:beta_access'%}">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<div>
|
||||||
|
{% for message in messages %}
|
||||||
|
<strong>{{ message }}</strong>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="inputs">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="text" name="name" class="form-control" id="name" placeholder="Enter name">
|
||||||
|
<span style="color: white">{{ form.name.errors|striptags}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="email" name="email" class="form-control" id="email" placeholder="Enter email">
|
||||||
|
<span style="color: white">{{ form.email.errors|striptags}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-default btn-transparent btn-lg">{% trans "Request Beta Access" %}</button>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
$('#beta_access').ajaxForm({
|
||||||
|
target: '#beta_access_form', success: function(response) { }
|
||||||
|
});
|
||||||
|
</script>
|
47
datacenterlight/templates/datacenterlight/beta_success.html
Normal file
47
datacenterlight/templates/datacenterlight/beta_success.html
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="modal fade bs-example-modal-sm" style="color:black;" id="successModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="vertical-alignment-helper">
|
||||||
|
<div class="modal-dialog vertical-align-center">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">{% trans "Request Sent" %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>{% trans "Thank you, we will contact you as soon as possible" %}</p>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
<script>
|
||||||
|
// Show modal
|
||||||
|
$('#successModal').modal('show');
|
||||||
|
// close the modal after 3 seconds
|
||||||
|
setTimeout(function() {
|
||||||
|
$('#successModal').modal('hide');
|
||||||
|
}, 5000);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.vertical-alignment-helper {
|
||||||
|
display:table;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
pointer-events:none; /* This makes sure that we can still click outside of the modal to close it */
|
||||||
|
}
|
||||||
|
.vertical-align-center {
|
||||||
|
/* To center vertically */
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
pointer-events:none;
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
/* Bootstrap sets the size of the modal in the modal-dialog class, we need to inherit it */
|
||||||
|
width:inherit;
|
||||||
|
height:inherit;
|
||||||
|
/* To center horizontally */
|
||||||
|
margin: 0 auto;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -227,7 +227,7 @@
|
||||||
<h3>{% trans "VM hosting" %} </h3>
|
<h3>{% trans "VM hosting" %} </h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="price">
|
<div class="price">
|
||||||
<span>15CHF</span>
|
<span>15CHF/month</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="descriptions">
|
<div class="descriptions">
|
||||||
<div class="description">
|
<div class="description">
|
||||||
|
@ -243,7 +243,7 @@
|
||||||
<p>{% trans "15 GiB storage(SSD)" %}</p>
|
<p>{% trans "15 GiB storage(SSD)" %}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="{% url 'datacenterlight:pricing' %}" class="btn btn-primary">{% trans "Buy Now!" %}</a>
|
<a href="{% url 'datacenterlight:pricing' %}" class="btn btn-primary">{% trans "Order Now!" %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -261,43 +261,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-md-6">
|
<div class="col-sm-6 col-md-6">
|
||||||
<div class="form">
|
<!-- Beta access form, will be loaded via ajax -->
|
||||||
<form class="form-beta" method="POST" action="">
|
<div class="form" id="beta_access_form">
|
||||||
{% csrf_token %}
|
</div>
|
||||||
{{ form.non_field_errors }}
|
|
||||||
{{ form.email.errors|striptags}}
|
|
||||||
<div>
|
|
||||||
{% for message in messages %}
|
|
||||||
<strong>{{ message }}</strong>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="inputs">
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="name" class="form-control" id="name" placeholder="Enter name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="email" name="email" class="form-control" id="email" placeholder="Enter email">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-default btn-transparent btn-lg">{% trans "Request Beta Access" %}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal fade bs-example-modal-sm" style="color:black;" id="sucessModal" 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="Close"><span aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">{% trans "Request Sent" %}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>{% trans "Thank you, we will contact you as soon as possible" %}</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer text-center">
|
|
||||||
<button type="submit" class="btn btn-primary" data-dismiss="modal">Ok</button>
|
|
||||||
</div>
|
|
||||||
</div><!-- /.modal-content -->
|
|
||||||
</div><!-- /.modal-dialog -->
|
|
||||||
</div><!-- /.modal -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -389,12 +355,12 @@
|
||||||
windowPadding: 10,
|
windowPadding: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
var hash = window.location.hash.substr(1);
|
$.ajax({
|
||||||
console.log(hash);
|
url: "{% url 'datacenterlight:beta_access' %}",
|
||||||
if (hash == 'requestform'){
|
context: document.body
|
||||||
$('#reques-success-message').modal('show');
|
}).done(function(response) {
|
||||||
}
|
$('#beta_access_form').html(response);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -403,6 +369,8 @@
|
||||||
<!-- Bootstrap Core JavaScript -->
|
<!-- Bootstrap Core JavaScript -->
|
||||||
<script src="{% static 'datacenterlight/js/bootstrap.min.js' %}"></script>
|
<script src="{% static 'datacenterlight/js/bootstrap.min.js' %}"></script>
|
||||||
<script src="{% static 'datacenterlight/js/main.js' %}"></script>
|
<script src="{% static 'datacenterlight/js/main.js' %}"></script>
|
||||||
|
<!-- Load form js -->
|
||||||
|
<script src="{% static 'datacenterlight/js/form.js' %}"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .views import IndexView, BetaProgramView, LandingProgramView, PricingView
|
from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -8,4 +8,5 @@ urlpatterns = [
|
||||||
url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'),
|
url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'),
|
||||||
url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
|
url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
|
||||||
url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
|
url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
|
||||||
|
url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,6 +5,7 @@ from .models import BetaAccess, BetaAccessVMType, BetaAccessVM
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.urlresolvers import reverse_lazy, reverse
|
from django.core.urlresolvers import reverse_lazy, reverse
|
||||||
from utils.mailer import BaseEmail
|
from utils.mailer import BaseEmail
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
from opennebula_api.models import OpenNebulaManager
|
from opennebula_api.models import OpenNebulaManager
|
||||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer
|
from opennebula_api.serializers import VirtualMachineTemplateSerializer
|
||||||
|
@ -15,6 +16,43 @@ class LandingProgramView(TemplateView):
|
||||||
class PricingView(TemplateView):
|
class PricingView(TemplateView):
|
||||||
template_name = "datacenterlight/pricing.html"
|
template_name = "datacenterlight/pricing.html"
|
||||||
|
|
||||||
|
class BetaAccessView(FormView):
|
||||||
|
template_name = "datacenterlight/beta_access.html"
|
||||||
|
form_class = BetaAccessForm
|
||||||
|
success_message = "Thank you, we will contact you as soon as possible"
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
|
||||||
|
}
|
||||||
|
|
||||||
|
email_data = {
|
||||||
|
'subject': 'DatacenterLight Beta Access Request',
|
||||||
|
'to': form.cleaned_data.get('email'),
|
||||||
|
'context': context,
|
||||||
|
'template_name': 'request_access_confirmation',
|
||||||
|
'template_path': 'datacenterlight/emails/'
|
||||||
|
}
|
||||||
|
email = BaseEmail(**email_data)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
context.update({
|
||||||
|
'email': form.cleaned_data.get('email')
|
||||||
|
})
|
||||||
|
|
||||||
|
email_data = {
|
||||||
|
'subject': 'DatacenterLight Beta Access Request',
|
||||||
|
'to': 'info@ungleich.ch',
|
||||||
|
'context': context,
|
||||||
|
'template_name': 'request_access_notification',
|
||||||
|
'template_path': 'datacenterlight/emails/'
|
||||||
|
}
|
||||||
|
email = BaseEmail(**email_data)
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
messages.add_message(self.request, messages.SUCCESS, self.success_message)
|
||||||
|
return render(self.request, 'datacenterlight/beta_success.html', {})
|
||||||
|
|
||||||
class BetaProgramView(CreateView):
|
class BetaProgramView(CreateView):
|
||||||
template_name = "datacenterlight/beta.html"
|
template_name = "datacenterlight/beta.html"
|
||||||
|
|
|
@ -4,15 +4,21 @@ from django.core.urlresolvers import reverse
|
||||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer
|
from opennebula_api.serializers import VirtualMachineTemplateSerializer
|
||||||
from opennebula_api.models import OpenNebulaManager
|
from opennebula_api.models import OpenNebulaManager
|
||||||
|
|
||||||
|
from .models import HostingPlan
|
||||||
|
|
||||||
|
|
||||||
class ProcessVMSelectionMixin(object):
|
class ProcessVMSelectionMixin(object):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
||||||
template_id = int(request.POST.get('vm_template_id'))
|
template_id = int(request.POST.get('vm_template_id'))
|
||||||
|
configuration_id = int(request.POST.get('configuration'))
|
||||||
template = OpenNebulaManager().get_template(template_id)
|
template = OpenNebulaManager().get_template(template_id)
|
||||||
data = VirtualMachineTemplateSerializer(template).data
|
data = VirtualMachineTemplateSerializer(template).data
|
||||||
|
configuration = HostingPlan.objects.get(id=configuration_id)
|
||||||
|
|
||||||
request.session['template'] = data
|
request.session['template'] = data
|
||||||
|
request.session['specs'] = configuration.serialize()
|
||||||
|
|
||||||
if not request.user.is_authenticated():
|
if not request.user.is_authenticated():
|
||||||
request.session['next'] = reverse('hosting:payment')
|
request.session['next'] = reverse('hosting:payment')
|
||||||
|
|
|
@ -35,7 +35,8 @@
|
||||||
<option value="{{config.id}}">
|
<option value="{{config.id}}">
|
||||||
CORE: {{config.cpu|floatformat}},
|
CORE: {{config.cpu|floatformat}},
|
||||||
RAM: {{config.memory|floatformat}} GiB,
|
RAM: {{config.memory|floatformat}} GiB,
|
||||||
SSD: {{config.disk_size|floatformat}} GiB
|
SSD: {{config.disk_size|floatformat}} GiB,
|
||||||
|
PRICE: {{config.price|floatformat}} CHF/Month
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
<div class="row text-center">
|
<div class="row text-center">
|
||||||
|
|
||||||
<div class="block col-md-offset-3">
|
<div class="block col-md-offset-3">
|
||||||
{% for vm in vm_types %}
|
{% for vm in configuration_options %}
|
||||||
<div class="col-xs-12 col-sm-6 col-md-4">
|
<div class="col-xs-12 col-sm-6 col-md-4">
|
||||||
<form class="form-inline" method="POST" action="{{request.path}}">
|
<form class="form-inline" method="POST" action="{{request.path}}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="hosting_company" value="{{vm.hosting_company}}">
|
<input type="hidden" name="hosting_company" value="{{vm.hosting_company}}">
|
||||||
<input type="hidden" name="location_code" value="{{vm.location_code}}">
|
<input type="hidden" name="location_code" value="{{vm.location_code}}">
|
||||||
<input type="hidden" name="vm_template_id" value="{{vm.id}}">
|
<input type="hidden" name="configuration" value="{{vm.id}}">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,14 +53,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<!-- <li>
|
<li>
|
||||||
<label for="configuration">Configuration: </label>
|
<label for="configuration">Configuration: </label>
|
||||||
<select class="form-control" name="configuration" id="{{vm.hosting_company}}-configuration" data-vm-type="{{vm.hosting_company}}">
|
<select class="form-control" name="vm_template_id" id="{{vm.hosting_company}}-configuration" data-vm-type="{{vm.hosting_company}}">
|
||||||
{% for key,value in configuration_options.items %}
|
{% for template in templates %}
|
||||||
<option value="{{key}}">{{ value }}</option>
|
<option value="{{template.id}}">{{ template.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</li> -->
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="hidden" name="final_price" value="{{vm.final_price|floatformat}}">
|
<input type="hidden" name="final_price" value="{{vm.final_price|floatformat}}">
|
||||||
<h3 id="{{vm.hosting_company}}-final-price">{{vm.price|floatformat}} CHF</h3>
|
<h3 id="{{vm.hosting_company}}-final-price">{{vm.price|floatformat}} CHF</h3>
|
||||||
|
|
|
@ -41,11 +41,17 @@
|
||||||
<div class="col-md-12 inline-headers">
|
<div class="col-md-12 inline-headers">
|
||||||
<h3>{{virtual_machine.hosting_company_name}}</h3>
|
<h3>{{virtual_machine.hosting_company_name}}</h3>
|
||||||
|
|
||||||
{% if virtual_machine.ip %}
|
{% if virtual_machine.ipv6 %}
|
||||||
<div class="pull-right right-place">
|
<div class="pull-right right-place">
|
||||||
<button type="link" data-clipboard-text="{{virtual_machine.ip}}" id="copy_vm_id" class="to_copy btn btn-link"
|
<button type="link"
|
||||||
|
data-clipboard-text="{{virtual_machine.ipv4}}" id="copy_vm_id" class="to_copy btn btn-link"
|
||||||
data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">
|
data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">
|
||||||
Ip: {{virtual_machine.ip}} <i class="fa fa-files-o" aria-hidden="true"></i>
|
Ipv4: {{virtual_machine.ipv4}} <i class="fa fa-files-o" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
<button type="link"
|
||||||
|
data-clipboard-text="{{virtual_machine.ipv6}}" id="copy_vm_id" class="to_copy btn btn-link"
|
||||||
|
data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">
|
||||||
|
Ipv6: {{virtual_machine.ipv6}} <i class="fa fa-files-o" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -98,7 +104,7 @@
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="col-md-12 inline-headers">
|
<div class="col-md-12 inline-headers">
|
||||||
<h3>{% trans "Current pricing"%}</h3>
|
<h3>{% trans "Current pricing"%}</h3>
|
||||||
<span class="h3 pull-right"><strong>{{virtual_machine.price|floatformat}} CHF</strong>/mo</span>
|
<span class="h3 pull-right"><strong>{{virtual_machine.price|floatformat}} CHF</strong>/month</span>
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -113,6 +113,12 @@
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
|
{% if next_url %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.location.href = '{{next_url}}';
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{%endblock%}
|
{%endblock%}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,15 @@
|
||||||
</div>
|
</div>
|
||||||
{% if not error %}
|
{% if not error %}
|
||||||
<p class="pull-right">
|
<p class="pull-right">
|
||||||
<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/>
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "ID"%}</th>
|
<th>{% trans "ID"%}</th>
|
||||||
<th>{% trans "Amount"%}</th>
|
<th>{% trans "Ipv4"%}</th>
|
||||||
|
<th>{% trans "Ipv6"%}</th>
|
||||||
<th>{% trans "Status"%}</th>
|
<th>{% trans "Status"%}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -35,7 +36,12 @@
|
||||||
{% for vm in vms %}
|
{% for vm in vms %}
|
||||||
<tr>
|
<tr>
|
||||||
<td scope="row">{{vm.vm_id}}</td>
|
<td scope="row">{{vm.vm_id}}</td>
|
||||||
<td>{{vm.price}} CHF</td>
|
{% if vm.ipv6 %}
|
||||||
|
<td>{{vm.ipv4}}</td>
|
||||||
|
|
||||||
|
<td>{{vm.ipv6}}</td>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
{% if vm.state == 'ACTIVE' %}
|
{% if vm.state == 'ACTIVE' %}
|
||||||
|
|
|
@ -19,7 +19,7 @@ urlpatterns = [
|
||||||
url(r'bills/?$', HostingBillListView.as_view(), name='bills'),
|
url(r'bills/?$', HostingBillListView.as_view(), name='bills'),
|
||||||
url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), name='bills'),
|
url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), name='bills'),
|
||||||
url(r'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'),
|
url(r'cancel_order/(?P<pk>\d+)/?$', OrdersHostingDeleteView.as_view(), name='delete_order'),
|
||||||
url(r'create-virtual-machine/?$', CreateVirtualMachinesView.as_view(), name='create-virtual-machine'),
|
url(r'create_virtual_machine/?$', CreateVirtualMachinesView.as_view(), name='create_virtual_machine'),
|
||||||
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'),
|
||||||
|
|
|
@ -47,6 +47,7 @@ class DjangoHostingView(ProcessVMSelectionMixin, View):
|
||||||
HOSTING = 'django'
|
HOSTING = 'django'
|
||||||
templates = OpenNebulaManager().get_templates()
|
templates = OpenNebulaManager().get_templates()
|
||||||
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
||||||
|
configuration_options = HostingPlan.get_serialized_configs()
|
||||||
|
|
||||||
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
||||||
context = {
|
context = {
|
||||||
|
@ -57,8 +58,8 @@ class DjangoHostingView(ProcessVMSelectionMixin, View):
|
||||||
'google_analytics': "UA-62285904-6",
|
'google_analytics': "UA-62285904-6",
|
||||||
'vm_types': data,
|
'vm_types': data,
|
||||||
'email': "info@django-hosting.ch",
|
'email': "info@django-hosting.ch",
|
||||||
# 'vm_types': VirtualMachineType.get_serialized_vm_types(),
|
'configuration_options': configuration_options,
|
||||||
# 'configuration_options': dict(VirtualMachinePlan.VM_CONFIGURATION)
|
'templates': templates,
|
||||||
}
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@ -77,7 +78,7 @@ class RailsHostingView(ProcessVMSelectionMixin, View):
|
||||||
HOSTING = 'rails'
|
HOSTING = 'rails'
|
||||||
|
|
||||||
templates = OpenNebulaManager().get_templates()
|
templates = OpenNebulaManager().get_templates()
|
||||||
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
configuration_options = HostingPlan.get_serialized_configs()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'hosting': HOSTING,
|
'hosting': HOSTING,
|
||||||
|
@ -85,7 +86,8 @@ class RailsHostingView(ProcessVMSelectionMixin, View):
|
||||||
'domain': "rails-hosting.ch",
|
'domain': "rails-hosting.ch",
|
||||||
'google_analytics': "UA-62285904-5",
|
'google_analytics': "UA-62285904-5",
|
||||||
'email': "info@rails-hosting.ch",
|
'email': "info@rails-hosting.ch",
|
||||||
'vm_types': data,
|
'configuration_options': configuration_options,
|
||||||
|
'templates': templates,
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -102,7 +104,7 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View):
|
||||||
HOSTING = 'nodejs'
|
HOSTING = 'nodejs'
|
||||||
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
# configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
|
||||||
templates = OpenNebulaManager().get_templates()
|
templates = OpenNebulaManager().get_templates()
|
||||||
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
configuration_options = HostingPlan.get_serialized_configs()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'hosting': HOSTING,
|
'hosting': HOSTING,
|
||||||
|
@ -111,7 +113,9 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View):
|
||||||
'domain': "node-hosting.ch",
|
'domain': "node-hosting.ch",
|
||||||
'google_analytics': "UA-62285904-7",
|
'google_analytics': "UA-62285904-7",
|
||||||
'email': "info@node-hosting.ch",
|
'email': "info@node-hosting.ch",
|
||||||
'vm_types': data,
|
'templates': templates,
|
||||||
|
'configuration_options': configuration_options,
|
||||||
|
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -128,12 +132,15 @@ class HostingPricingView(ProcessVMSelectionMixin, View):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
# configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
|
# configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
|
||||||
templates = OpenNebulaManager().get_templates()
|
templates = OpenNebulaManager().get_templates()
|
||||||
data = VirtualMachineTemplateSerializer(templates, many=True).data
|
configuration_options = HostingPlan.get_serialized_configs()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
# 'configuration_options': configuration_options,
|
# 'configuration_options': configuration_options,
|
||||||
'email': "info@django-hosting.ch",
|
'email': "info@django-hosting.ch",
|
||||||
'vm_types': data,
|
'templates': templates,
|
||||||
|
'configuration_options': configuration_options,
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@ -280,7 +287,6 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
|
||||||
form_class = UserHostingKeyForm
|
form_class = UserHostingKeyForm
|
||||||
model = UserHostingKey
|
model = UserHostingKey
|
||||||
template_name = 'hosting/virtual_machine_key.html'
|
template_name = 'hosting/virtual_machine_key.html'
|
||||||
success_url = reverse_lazy('hosting:orders')
|
|
||||||
login_url = reverse_lazy('hosting:login')
|
login_url = reverse_lazy('hosting:login')
|
||||||
context_object_name = "virtual_machine"
|
context_object_name = "virtual_machine"
|
||||||
|
|
||||||
|
@ -317,7 +323,8 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
|
||||||
context.update({
|
context.update({
|
||||||
'private_key': form.cleaned_data.get('private_key'),
|
'private_key': form.cleaned_data.get('private_key'),
|
||||||
'key_name': form.cleaned_data.get('name'),
|
'key_name': form.cleaned_data.get('name'),
|
||||||
'form': UserHostingKeyForm(request=self.request)
|
'form': UserHostingKeyForm(request=self.request),
|
||||||
|
'next_url': reverse('hosting:create_virtual_machine')
|
||||||
})
|
})
|
||||||
|
|
||||||
# return HttpResponseRedirect(reverse('hosting:key_pair'))
|
# return HttpResponseRedirect(reverse('hosting:key_pair'))
|
||||||
|
@ -384,6 +391,8 @@ class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
if 'next' in request.session:
|
||||||
|
del request.session['next']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
UserHostingKey.objects.get(
|
UserHostingKey.objects.get(
|
||||||
|
|
|
@ -82,6 +82,7 @@ class OpenNebulaManager():
|
||||||
try:
|
try:
|
||||||
vm_pool = oca.VirtualMachinePool(self.client)
|
vm_pool = oca.VirtualMachinePool(self.client)
|
||||||
vm_pool.info()
|
vm_pool.info()
|
||||||
|
return vm_pool
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
logger.info('Could not connect via client, using oneadmin instead')
|
logger.info('Could not connect via client, using oneadmin instead')
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import oca
|
import oca
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
|
||||||
id = serializers.IntegerField(read_only=True)
|
id = serializers.IntegerField(read_only=True)
|
||||||
set_name = serializers.CharField(read_only=True, label='Name')
|
set_name = serializers.CharField(read_only=True, label='Name')
|
||||||
name = serializers.SerializerMethodField()
|
name = serializers.SerializerMethodField()
|
||||||
cores = serializers.IntegerField(source='template.vcpu')
|
cores = serializers.SerializerMethodField()
|
||||||
disk = serializers.IntegerField(write_only=True)
|
disk = serializers.IntegerField(write_only=True)
|
||||||
disk_size = serializers.SerializerMethodField()
|
disk_size = serializers.SerializerMethodField()
|
||||||
set_memory = serializers.IntegerField(write_only=True, label='Memory')
|
set_memory = serializers.IntegerField(write_only=True, label='Memory')
|
||||||
|
@ -41,6 +42,12 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
|
||||||
|
|
||||||
return manager.get_template(template_id=opennebula_id)
|
return manager.get_template(template_id=opennebula_id)
|
||||||
|
|
||||||
|
def get_cores(self, obj):
|
||||||
|
if hasattr(obj.template, 'vcpu'):
|
||||||
|
return obj.template.vcpu
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
def get_disk_size(self, obj):
|
def get_disk_size(self, obj):
|
||||||
template = obj.template
|
template = obj.template
|
||||||
disk_size = 0
|
disk_size = 0
|
||||||
|
@ -67,8 +74,7 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
|
||||||
return int(obj.template.memory)/1024
|
return int(obj.template.memory)/1024
|
||||||
|
|
||||||
def get_name(self, obj):
|
def get_name(self, obj):
|
||||||
# TODO: Filter public- away
|
return obj.name.strip('public-')
|
||||||
return obj.name
|
|
||||||
|
|
||||||
class VirtualMachineSerializer(serializers.Serializer):
|
class VirtualMachineSerializer(serializers.Serializer):
|
||||||
"""Serializer to map the virtual machine instance into JSON format."""
|
"""Serializer to map the virtual machine instance into JSON format."""
|
||||||
|
@ -81,9 +87,8 @@ class VirtualMachineSerializer(serializers.Serializer):
|
||||||
|
|
||||||
|
|
||||||
disk_size = serializers.SerializerMethodField()
|
disk_size = serializers.SerializerMethodField()
|
||||||
ip = serializers.CharField(read_only=True,
|
ipv4 = serializers.SerializerMethodField()
|
||||||
source='user_template.ungleich_public_ip',
|
ipv6 = serializers.SerializerMethodField()
|
||||||
default='-')
|
|
||||||
vm_id = serializers.IntegerField(read_only=True, source='id')
|
vm_id = serializers.IntegerField(read_only=True, source='id')
|
||||||
state = serializers.CharField(read_only=True, source='str_state')
|
state = serializers.CharField(read_only=True, source='str_state')
|
||||||
price = serializers.SerializerMethodField()
|
price = serializers.SerializerMethodField()
|
||||||
|
@ -146,4 +151,34 @@ class VirtualMachineSerializer(serializers.Serializer):
|
||||||
def get_configuration(self, obj):
|
def get_configuration(self, obj):
|
||||||
template_id = obj.template.template_id
|
template_id = obj.template.template_id
|
||||||
template = OpenNebulaManager().get_template(template_id)
|
template = OpenNebulaManager().get_template(template_id)
|
||||||
return template.name
|
return template.name.strip('public-')
|
||||||
|
|
||||||
|
def get_ipv4(self, obj):
|
||||||
|
nic = obj.template.nics[0]
|
||||||
|
if 'vm-ipv6-nat64-ipv4' in nic.network and is_in_v4_range(nic.mac):
|
||||||
|
return str(v4_from_mac(nic.mac))
|
||||||
|
else:
|
||||||
|
return '-'
|
||||||
|
|
||||||
|
def get_ipv6(self, obj):
|
||||||
|
nic = obj.template.nics[0]
|
||||||
|
return nic.ip6_global
|
||||||
|
|
||||||
|
|
||||||
|
def hexstr2int(string):
|
||||||
|
return int(string.replace(':', ''), 16)
|
||||||
|
|
||||||
|
FIRST_MAC = hexstr2int('02:00:b3:39:79:4d')
|
||||||
|
FIRST_V4 = ipaddress.ip_address('185.203.112.2')
|
||||||
|
COUNT = 1000
|
||||||
|
|
||||||
|
def v4_from_mac(mac):
|
||||||
|
"""Calculates the IPv4 address from a MAC address.
|
||||||
|
|
||||||
|
mac: string (the colon-separated representation)
|
||||||
|
returns: ipaddress.ip_address object with the v4 address
|
||||||
|
"""
|
||||||
|
return FIRST_V4 + (hexstr2int(mac) - FIRST_MAC)
|
||||||
|
|
||||||
|
def is_in_v4_range(mac):
|
||||||
|
return FIRST_MAC <= hexstr2int(mac) < FIRST_MAC + 1000
|
||||||
|
|
Loading…
Reference in a new issue