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 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										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 %} |  | ||||||
|                           {{ form.non_field_errors }} |  | ||||||
|                           {{ form.email.errors|striptags}} |  | ||||||
|                           <div> |  | ||||||
|                             {% for message in messages %} |  | ||||||
|                                 <strong>{{ message }}</strong> |  | ||||||
|                             {% endfor %}                   |  | ||||||
| 					</div> | 					</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…
	
	Add table
		Add a link
		
	
		Reference in a new issue