commit
				
					
						78773eb5c3
					
				
			
		
					 12 changed files with 410 additions and 327 deletions
				
			
		| 
						 | 
				
			
			@ -5,3 +5,8 @@
 | 
			
		|||
    * [datacenterlight] Fix initially shown price
 | 
			
		||||
1.0.2: 2017-05-28
 | 
			
		||||
    * [datacenterlight] Fixed login redirecting to blank page after logout
 | 
			
		||||
 | 
			
		||||
next
 | 
			
		||||
	* [opennebula_api] Improve testing, add ssh key functions
 | 
			
		||||
	* [opennebula_api] Remove template views
 | 
			
		||||
	* [datacenterlight] Allow user to have multiple ssh keys 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ from django import forms
 | 
			
		|||
from membership.models import CustomUser
 | 
			
		||||
from django.contrib.auth import authenticate
 | 
			
		||||
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from utils.stripe_utils import StripeUtils
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,21 +58,19 @@ class HostingUserSignupForm(forms.ModelForm):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class UserHostingKeyForm(forms.ModelForm):
 | 
			
		||||
    private_key = forms.CharField(widget=forms.PasswordInput(), required=False)
 | 
			
		||||
    public_key = forms.CharField(widget=forms.PasswordInput(), required=False)
 | 
			
		||||
    user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(), required=False)
 | 
			
		||||
    name = forms.CharField(required=False)
 | 
			
		||||
    private_key = forms.CharField(widget=forms.HiddenInput(), required=False)
 | 
			
		||||
    public_key = forms.CharField(widget=forms.Textarea(), required=False,
 | 
			
		||||
            help_text=_('Paste here your public key'))
 | 
			
		||||
    user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(),
 | 
			
		||||
            required=False, widget=forms.HiddenInput())
 | 
			
		||||
    name = forms.CharField(required=True)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.request = kwargs.pop("request")
 | 
			
		||||
        super(UserHostingKeyForm, self).__init__(*args, **kwargs)
 | 
			
		||||
        # self.initial['user'].initial = self.request.user.id
 | 
			
		||||
        # print(self.fields)
 | 
			
		||||
 | 
			
		||||
    def clean_name(self):
 | 
			
		||||
        return "dcl-priv-key-%s" % (
 | 
			
		||||
            ''.join(random.choice(string.ascii_lowercase) for i in range(7))
 | 
			
		||||
        )
 | 
			
		||||
        return self.data.get('name')
 | 
			
		||||
 | 
			
		||||
    def clean_user(self):
 | 
			
		||||
        return self.request.user
 | 
			
		||||
| 
						 | 
				
			
			@ -90,4 +89,4 @@ class UserHostingKeyForm(forms.ModelForm):
 | 
			
		|||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = UserHostingKey
 | 
			
		||||
        fields = ['user', 'public_key', 'name']
 | 
			
		||||
        fields = ['user', 'name', 'public_key']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2017-05-26 13:35+0000\n"
 | 
			
		||||
"POT-Creation-Date: 2017-06-01 21:03+0000\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -18,61 +18,64 @@ msgstr ""
 | 
			
		|||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:67
 | 
			
		||||
#: hosting/forms.py:63
 | 
			
		||||
msgid "Paste here your public key"
 | 
			
		||||
msgstr "Fügen Sie Ihren public key ein"
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:68
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:139
 | 
			
		||||
msgid "My Virtual Machines"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:72
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:73
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:145
 | 
			
		||||
#: hosting/templates/hosting/orders.html:12
 | 
			
		||||
msgid "My Orders"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:77
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:78
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:152
 | 
			
		||||
msgid "Keys"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:82
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:83
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:158
 | 
			
		||||
msgid "Notifications "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:89
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:90
 | 
			
		||||
msgid "Logout"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:94
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:136
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:95
 | 
			
		||||
msgid "How it works"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:97
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:139
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:98
 | 
			
		||||
msgid "Your infrastructure"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:100
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:142
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:101
 | 
			
		||||
msgid "Our inftrastructure"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:103
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:145
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:104
 | 
			
		||||
msgid "Pricing"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:106
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:149
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:107
 | 
			
		||||
msgid "Contact"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:109
 | 
			
		||||
#: hosting/templates/hosting/login.html:29
 | 
			
		||||
#: hosting/templates/hosting/login.html:38
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:24
 | 
			
		||||
#: hosting/templates/hosting/signup.html:23
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:110
 | 
			
		||||
#: hosting/templates/hosting/login.html:32
 | 
			
		||||
#: hosting/templates/hosting/login.html:41
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:31
 | 
			
		||||
#: hosting/templates/hosting/signup.html:30
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:132
 | 
			
		||||
#: hosting/templates/hosting/base_short.html:134
 | 
			
		||||
msgid "Home"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +147,7 @@ msgid "Customers"
 | 
			
		|||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/bills.html:16
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:45
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:42
 | 
			
		||||
msgid "Name"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -173,13 +176,13 @@ msgid "Set your new password"
 | 
			
		|||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/confirm_reset_password.html:28
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:20
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:22
 | 
			
		||||
msgid "Reset"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/confirm_reset_password.html:32
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:24
 | 
			
		||||
#: hosting/templates/hosting/signup.html:23
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:28
 | 
			
		||||
#: hosting/templates/hosting/signup.html:27
 | 
			
		||||
msgid "Already have an account ?"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -219,21 +222,27 @@ msgstr ""
 | 
			
		|||
msgid "The %(site_name)s team"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/login.html:22
 | 
			
		||||
#: hosting/templates/hosting/login.html:10
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:10
 | 
			
		||||
#: hosting/templates/hosting/signup.html:9
 | 
			
		||||
msgid "Your VM hosted in Switzerland"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/login.html:26
 | 
			
		||||
msgid "You haven been logged out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/login.html:44
 | 
			
		||||
#: hosting/templates/hosting/login.html:49
 | 
			
		||||
msgid "Don't have an account yet ? "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/login.html:44
 | 
			
		||||
#: hosting/templates/hosting/signup.html:10
 | 
			
		||||
#: hosting/templates/hosting/signup.html:19
 | 
			
		||||
#: hosting/templates/hosting/login.html:52
 | 
			
		||||
#: hosting/templates/hosting/signup.html:13
 | 
			
		||||
#: hosting/templates/hosting/signup.html:21
 | 
			
		||||
msgid "Sign up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/login.html:46
 | 
			
		||||
#: hosting/templates/hosting/login.html:54
 | 
			
		||||
msgid "Forgot your password ? "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -310,7 +319,7 @@ msgstr ""
 | 
			
		|||
 | 
			
		||||
#: hosting/templates/hosting/orders.html:19
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_detail.html:30
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:47
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:44
 | 
			
		||||
#: hosting/templates/hosting/virtual_machines.html:31
 | 
			
		||||
msgid "Status"
 | 
			
		||||
msgstr ""
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +353,7 @@ msgstr ""
 | 
			
		|||
msgid "Delete"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:11
 | 
			
		||||
#: hosting/templates/hosting/reset_password.html:14
 | 
			
		||||
msgid "Reset your password"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -400,50 +409,46 @@ msgstr ""
 | 
			
		|||
msgid "Access Key"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:22
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:25
 | 
			
		||||
msgid "Upload your own key. "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:29
 | 
			
		||||
msgid "Upload Key"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:33
 | 
			
		||||
msgid "Or generate a new key pair."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:37
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:31
 | 
			
		||||
msgid "Generate Key Pair"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:46
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:43
 | 
			
		||||
msgid "Created at"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:68
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:81
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:66
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:79
 | 
			
		||||
msgid "Warning!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:68
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:66
 | 
			
		||||
msgid "You can download your SSH  private key once. Don't lost your key"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:76
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:74
 | 
			
		||||
msgid "Copy to Clipboard"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:77
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:75
 | 
			
		||||
msgid "Download"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:81
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:79
 | 
			
		||||
msgid ""
 | 
			
		||||
"Your SSH private key was already generated and downloaded, if you lost it, "
 | 
			
		||||
"contact us. "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:84
 | 
			
		||||
#: hosting/templates/hosting/virtual_machine_key.html:82
 | 
			
		||||
msgid "Generate my key"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@
 | 
			
		|||
		<div class="row">
 | 
			
		||||
			<div class="col-md-9 col-md-offset-2">
 | 
			
		||||
				 <div  class="col-sm-12">
 | 
			
		||||
                    <form method="POST" action="" >
 | 
			
		||||
                    <form method="POST" action="" novalidate>
 | 
			
		||||
                        {% csrf_token %}
 | 
			
		||||
				        <h3><i class="fa fa-key" aria-hidden="true"></i>{% trans "Access Key"%} </h3>
 | 
			
		||||
                        {% if messages %}
 | 
			
		||||
| 
						 | 
				
			
			@ -15,28 +15,25 @@
 | 
			
		|||
                            <span>{{ message }}</span>
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </div>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
				        <hr/>	
 | 
			
		||||
                        {% if not user_key %}
 | 
			
		||||
                            <h3>
 | 
			
		||||
						{% endif %}
 | 
			
		||||
                        {% for field in form %}
 | 
			
		||||
							
 | 
			
		||||
                            {% bootstrap_field field %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
                        {% buttons %}
 | 
			
		||||
                            <button type="submit" class="btn btn-success">
 | 
			
		||||
                                {% trans "Upload your own key. "%} 
 | 
			
		||||
                            </h3>
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                              <label for="comment">Paste here your public key</label>
 | 
			
		||||
                              <textarea class="form-control" rows="6" name="public_key"></textarea>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <button class="btn btn-success">{% trans "Upload Key"%} </a>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        
 | 
			
		||||
                            <h3>
 | 
			
		||||
                                {% trans "Or generate a new key pair."%} 
 | 
			
		||||
 | 
			
		||||
                            </h3>
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                            </button>
 | 
			
		||||
<br />
 | 
			
		||||
<br />
 | 
			
		||||
							{% trans "Or generate a new key pair."%} <br />
 | 
			
		||||
<br />
 | 
			
		||||
                                <button class="btn btn-success">{% trans "Generate Key Pair"%} </a>
 | 
			
		||||
                            </button>
 | 
			
		||||
 | 
			
		||||
                        {% endbuttons %} 
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                            </div>
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            <h5> Use your created key to access to the machine. If you lost it, contact us. </h5>
 | 
			
		||||
                            <table class="table borderless table-hover"> 
 | 
			
		||||
                                <br/>
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +46,7 @@
 | 
			
		|||
                                </tr>
 | 
			
		||||
                                </thead>
 | 
			
		||||
                                <tbody> 
 | 
			
		||||
									{% for user_key in keys %}
 | 
			
		||||
                                    <tr> 
 | 
			
		||||
                                        <td scope="row">{{user_key.name}}</td> 
 | 
			
		||||
                                        <td>{{user_key.created_at}}</td> 
 | 
			
		||||
| 
						 | 
				
			
			@ -57,9 +55,9 @@
 | 
			
		|||
 | 
			
		||||
                                        </td> 
 | 
			
		||||
                                    </tr>
 | 
			
		||||
									{% endfor %}
 | 
			
		||||
                                </tbody> 
 | 
			
		||||
                            </table>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </form>
 | 
			
		||||
 | 
			
		||||
				        {% if private_key %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
from django.test import TestCase
 | 
			
		||||
 | 
			
		||||
# Create your tests here.
 | 
			
		||||
 | 
			
		||||
test_user_can_add_key()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -301,16 +301,12 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
 | 
			
		|||
            self
 | 
			
		||||
        ).get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            user_key = UserHostingKey.objects.get(
 | 
			
		||||
                user=self.request.user
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        except UserHostingKey.DoesNotExist:
 | 
			
		||||
            user_key = None
 | 
			
		||||
        user_keys = UserHostingKey.objects.filter(
 | 
			
		||||
            user=self.request.user
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        context.update({
 | 
			
		||||
            'user_key': user_key
 | 
			
		||||
            'keys': user_keys
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
| 
						 | 
				
			
			@ -351,24 +347,14 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, FormView):
 | 
			
		|||
        opennebula_user = user_pool.get_by_name(owner.email)
 | 
			
		||||
 | 
			
		||||
        # Get user ssh key
 | 
			
		||||
        user_key = UserHostingKey.objects.get(user=owner)
 | 
			
		||||
        public_key = form.cleaned_data.get('public_key')
 | 
			
		||||
        # Add ssh key to user
 | 
			
		||||
        manager.oneadmin_client.call('user.update', opennebula_user.id,
 | 
			
		||||
                                     '<CONTEXT><SSH_PUBLIC_KEY>{ssh_key}</SSH_PUBLIC_KEY></CONTEXT>'.format(ssh_key=user_key.public_key))
 | 
			
		||||
                                     '<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key))
 | 
			
		||||
 | 
			
		||||
        return render(self.request, self.template_name, context)
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            UserHostingKey.objects.get(
 | 
			
		||||
                user=self.request.user
 | 
			
		||||
            )
 | 
			
		||||
            return HttpResponseRedirect(reverse('hosting:key_pair'))
 | 
			
		||||
 | 
			
		||||
        except UserHostingKey.DoesNotExist:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        form = self.get_form()
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            return self.form_valid(form)
 | 
			
		||||
| 
						 | 
				
			
			@ -421,11 +407,7 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
			
		|||
        return context
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        try:
 | 
			
		||||
            UserHostingKey.objects.get(
 | 
			
		||||
                user=self.request.user
 | 
			
		||||
            )
 | 
			
		||||
        except UserHostingKey.DoesNotExist:
 | 
			
		||||
        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.'
 | 
			
		||||
| 
						 | 
				
			
			@ -487,14 +469,16 @@ class PaymentVMView(LoginRequiredMixin, FormView):
 | 
			
		|||
            manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                        password=owner.password)
 | 
			
		||||
            # Get user ssh key
 | 
			
		||||
            try:
 | 
			
		||||
                user_key = UserHostingKey.objects.get(
 | 
			
		||||
                    user=self.request.user
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            except UserHostingKey.DoesNotExist:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
            if not UserHostingKey.objects.filter( user=self.request.user).exists():
 | 
			
		||||
                context.update({
 | 
			
		||||
                    'sshError': 'error',
 | 
			
		||||
                    'form': form
 | 
			
		||||
                })
 | 
			
		||||
                return render(request, self.template_name, context)
 | 
			
		||||
            # For now just get first one
 | 
			
		||||
            user_key = UserHostingKey.objects.filter(
 | 
			
		||||
                    user=self.request.user).first()
 | 
			
		||||
            
 | 
			
		||||
            # Create a vm using logged user
 | 
			
		||||
            vm_id = manager.create_vm(
 | 
			
		||||
                template_id=vm_template_id,
 | 
			
		||||
| 
						 | 
				
			
			@ -639,11 +623,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
			
		|||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            UserHostingKey.objects.get(
 | 
			
		||||
                user=self.request.user
 | 
			
		||||
            )
 | 
			
		||||
        except UserHostingKey.DoesNotExist:
 | 
			
		||||
        if not UserHostingKey.objects.filter( user=self.request.user).exists():
 | 
			
		||||
            messages.success(
 | 
			
		||||
                request,
 | 
			
		||||
                'In order to create a VM, you need to create/upload your SSH KEY first.'
 | 
			
		||||
| 
						 | 
				
			
			@ -667,7 +647,7 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View):
 | 
			
		|||
            )
 | 
			
		||||
            context = {
 | 
			
		||||
                'error': 'connection'
 | 
			
		||||
            }
 | 
			
		||||
            }        
 | 
			
		||||
 | 
			
		||||
        return render(request, self.template_name, context)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								opennebula_api/exceptions.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								opennebula_api/exceptions.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
 | 
			
		||||
class KeyExistsError(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class UserExistsError(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class UserCredentialError(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
| 
						 | 
				
			
			@ -2,12 +2,15 @@ import oca
 | 
			
		|||
import socket
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from oca.pool import WrongNameError
 | 
			
		||||
from oca.exceptions import OpenNebulaException
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.utils.functional import cached_property
 | 
			
		||||
 | 
			
		||||
from oca.pool import WrongNameError
 | 
			
		||||
from oca.exceptions import OpenNebulaException
 | 
			
		||||
from utils.models import CustomUser
 | 
			
		||||
from .exceptions import KeyExistsError, UserExistsError, UserCredentialError
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,10 +38,33 @@ class OpenNebulaManager():
 | 
			
		|||
            )
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
    def _get_client(self, user):
 | 
			
		||||
        """Get a opennebula client object for a CustomUser object 
 | 
			
		||||
        
 | 
			
		||||
        Args:
 | 
			
		||||
            user (CustomUser): dynamicweb CustomUser object
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            oca.Client: Opennebula client object
 | 
			
		||||
 | 
			
		||||
        Raise:
 | 
			
		||||
            ConnectionError: If the connection to the opennebula server can't be
 | 
			
		||||
                established 
 | 
			
		||||
        """
 | 
			
		||||
        return oca.Client("{0}:{1}".format(
 | 
			
		||||
            user.email,
 | 
			
		||||
            user.password),
 | 
			
		||||
            "{protocol}://{domain}:{port}{endpoint}".format(
 | 
			
		||||
                protocol=settings.OPENNEBULA_PROTOCOL,
 | 
			
		||||
                domain=settings.OPENNEBULA_DOMAIN,
 | 
			
		||||
                port=settings.OPENNEBULA_PORT,
 | 
			
		||||
                endpoint=settings.OPENNEBULA_ENDPOINT
 | 
			
		||||
        ))
 | 
			
		||||
 | 
			
		||||
    def _get_opennebula_client(self, username, password):
 | 
			
		||||
        return oca.Client("{0}:{1}".format(
 | 
			
		||||
            username,
 | 
			
		||||
 | 
			
		||||
            password),
 | 
			
		||||
            "{protocol}://{domain}:{port}{endpoint}".format(
 | 
			
		||||
                protocol=settings.OPENNEBULA_PROTOCOL,
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +73,69 @@ class OpenNebulaManager():
 | 
			
		|||
                endpoint=settings.OPENNEBULA_ENDPOINT
 | 
			
		||||
        ))
 | 
			
		||||
 | 
			
		||||
    def _get_user(self, user):
 | 
			
		||||
        """Get the corresponding opennebula user for a CustomUser object 
 | 
			
		||||
        
 | 
			
		||||
        Args:
 | 
			
		||||
            user (CustomUser): dynamicweb CustomUser object
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            oca.User: Opennebula user object
 | 
			
		||||
 | 
			
		||||
        Raise:
 | 
			
		||||
            WrongNameError: If no openebula user with this credentials exists
 | 
			
		||||
            ConnectionError: If the connection to the opennebula server can't be
 | 
			
		||||
                established 
 | 
			
		||||
        """
 | 
			
		||||
        user_pool = self._get_user_pool()
 | 
			
		||||
        return user_pool.get_by_name(user.email)
 | 
			
		||||
 | 
			
		||||
    def create_user(self, user: CustomUser):
 | 
			
		||||
        """Create a new opennebula user or a corresponding CustomUser object
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        Args:
 | 
			
		||||
            user (CustomUser): dynamicweb CustomUser object
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            int: Return the opennebula user id
 | 
			
		||||
            
 | 
			
		||||
        Raises:
 | 
			
		||||
            ConnectionError: If the connection to the opennebula server can't be
 | 
			
		||||
                established 
 | 
			
		||||
            UserExistsError: If a user with this credeintals already exits on the
 | 
			
		||||
                server
 | 
			
		||||
            UserCredentialError: If a user with this email exists but the
 | 
			
		||||
                password is worng
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            self._get_user(user)
 | 
			
		||||
            try: 
 | 
			
		||||
                self._get_client(self, user)
 | 
			
		||||
                logger.debug('User already exists')
 | 
			
		||||
                raise UserExistsError()
 | 
			
		||||
            except OpenNebulaException as err:
 | 
			
		||||
                logger.error('OpenNebulaException error: {0}'.format(err))
 | 
			
		||||
                logger.debug('User exists but password is wrong')
 | 
			
		||||
                raise UserCredentialError()
 | 
			
		||||
 | 
			
		||||
        except WrongNameError:
 | 
			
		||||
            user_id = self.oneadmin_client.call(oca.User.METHODS['allocate'],
 | 
			
		||||
                user.email, user.password, 'core')
 | 
			
		||||
            logger.debug('Created a user for CustomObject: {user} with user id = {u_id}',
 | 
			
		||||
                user=user,
 | 
			
		||||
                u_id=user_id
 | 
			
		||||
            )
 | 
			
		||||
            return user_id 
 | 
			
		||||
        except ConnectionRefusedError:
 | 
			
		||||
            logger.error('Could not connect to host: {host} via protocol {protocol}'.format(
 | 
			
		||||
                host=settings.OPENNEBULA_DOMAIN,
 | 
			
		||||
                protocol=settings.OPENNEBULA_PROTOCOL)
 | 
			
		||||
            )
 | 
			
		||||
            raise ConnectionRefusedError
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    def _get_or_create_user(self, email, password):
 | 
			
		||||
        try:
 | 
			
		||||
            user_pool = self._get_user_pool()
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +166,7 @@ class OpenNebulaManager():
 | 
			
		|||
                host=settings.OPENNEBULA_DOMAIN,
 | 
			
		||||
                protocol=settings.OPENNEBULA_PROTOCOL)
 | 
			
		||||
            )
 | 
			
		||||
            raise ConnectionRefusedError
 | 
			
		||||
            raise 
 | 
			
		||||
        return user_pool
 | 
			
		||||
 | 
			
		||||
    def _get_vm_pool(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +260,6 @@ class OpenNebulaManager():
 | 
			
		|||
                                  <DEV_PREFIX>vd</DEV_PREFIX>
 | 
			
		||||
                                  <IMAGE_ID>{image_id}</IMAGE_ID>
 | 
			
		||||
                           </DISK>
 | 
			
		||||
                          </TEMPLATE>
 | 
			
		||||
                        """.format(size=1024 * int(specs['disk_size']),
 | 
			
		||||
                                   image_id=image_id)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,10 +281,18 @@ class OpenNebulaManager():
 | 
			
		|||
                                  <IMAGE>{image}</IMAGE>
 | 
			
		||||
                                  <IMAGE_UNAME>{image_uname}</IMAGE_UNAME>
 | 
			
		||||
                           </DISK>
 | 
			
		||||
                          </TEMPLATE>
 | 
			
		||||
                        """.format(size=1024 * int(specs['disk_size']),
 | 
			
		||||
                                   image=image,
 | 
			
		||||
                                   image_uname=image_uname)
 | 
			
		||||
                        
 | 
			
		||||
                                
 | 
			
		||||
        if ssh_key:
 | 
			
		||||
            vm_specs += """<CONTEXT>
 | 
			
		||||
                    <SSH_PUBLIC_KEY>{ssh}</SSH_PUBLIC_KEY>
 | 
			
		||||
                    <NETWORK>YES</NETWORK>
 | 
			
		||||
                   </CONTEXT>
 | 
			
		||||
                              </TEMPLATE>
 | 
			
		||||
                """.format(ssh=public_key)
 | 
			
		||||
        vm_id = self.client.call(oca.VmTemplate.METHODS['instantiate'],
 | 
			
		||||
                                 template.id,
 | 
			
		||||
                                 '',
 | 
			
		||||
| 
						 | 
				
			
			@ -204,25 +300,6 @@ class OpenNebulaManager():
 | 
			
		|||
                                 vm_specs,
 | 
			
		||||
                                 False)
 | 
			
		||||
 | 
			
		||||
        self.oneadmin_client.call(
 | 
			
		||||
            'vm.update',
 | 
			
		||||
            vm_id,
 | 
			
		||||
            """<CONTEXT>
 | 
			
		||||
                <SSH_PUBLIC_KEY>{ssh}</SSH_PUBLIC_KEY>
 | 
			
		||||
               </CONTEXT>
 | 
			
		||||
            """.format(ssh=ssh_key)
 | 
			
		||||
        )
 | 
			
		||||
        try:
 | 
			
		||||
            self.oneadmin_client.call(
 | 
			
		||||
                oca.VirtualMachine.METHODS['chown'],
 | 
			
		||||
                vm_id,
 | 
			
		||||
                self.opennebula_user.id,
 | 
			
		||||
                self.opennebula_user.group_ids[0]
 | 
			
		||||
            )
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            logger.info(
 | 
			
		||||
                'Could not change owner for vm with id: {}.'.format(vm_id))
 | 
			
		||||
 | 
			
		||||
        self.oneadmin_client.call(
 | 
			
		||||
            oca.VirtualMachine.METHODS['action'],
 | 
			
		||||
            'release',
 | 
			
		||||
| 
						 | 
				
			
			@ -350,3 +427,85 @@ class OpenNebulaManager():
 | 
			
		|||
            self.opennebula_user.id,
 | 
			
		||||
            new_password
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def add_public_key(self, user, public_key='', merge=False):
 | 
			
		||||
        """ 
 | 
			
		||||
 | 
			
		||||
        Args: 
 | 
			
		||||
            user (CustomUser): Dynamicweb user 
 | 
			
		||||
            public_key (string): Public key to add to the user
 | 
			
		||||
            merge (bool): Optional if True the new public key replaces the old
 | 
			
		||||
 | 
			
		||||
        Raises:
 | 
			
		||||
            KeyExistsError: If replace is False and the user already has a
 | 
			
		||||
                public key 
 | 
			
		||||
            WrongNameError: If no openebula user with this credentials exists
 | 
			
		||||
            ConnectionError: If the connection to the opennebula server can't be
 | 
			
		||||
                established 
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            True if public_key was added
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        # TODO: Check if we can remove this first try because we basically just
 | 
			
		||||
        # raise the possible Errors 
 | 
			
		||||
        try:
 | 
			
		||||
            open_user = self._get_user(user)
 | 
			
		||||
            try:
 | 
			
		||||
                old_key = open_user.template.ssh_public_key 
 | 
			
		||||
                if not merge:
 | 
			
		||||
                    raise KeyExistsError()
 | 
			
		||||
                public_key += '\n{key}'.format(key=old_key)
 | 
			
		||||
 | 
			
		||||
            except AttributeError:
 | 
			
		||||
                pass
 | 
			
		||||
            self.oneadmin_client.call('user.update', open_user.id,
 | 
			
		||||
                         '<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key))
 | 
			
		||||
            return True
 | 
			
		||||
        except WrongNameError:
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
        except ConnectionError:
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
    def remove_public_key(self, user, public_key=''):
 | 
			
		||||
        """ 
 | 
			
		||||
 | 
			
		||||
        Args: 
 | 
			
		||||
            user (CustomUser): Dynamicweb user 
 | 
			
		||||
            public_key (string): Public key to be removed to the user
 | 
			
		||||
 | 
			
		||||
        Raises:
 | 
			
		||||
            KeyDoesNotExistsError: If replace is False and the user already has a
 | 
			
		||||
                public key 
 | 
			
		||||
            WrongNameError: If no openebula user with this credentials exists
 | 
			
		||||
            ConnectionError: If the connection to the opennebula server can't be
 | 
			
		||||
                established 
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            True if public_key was removed
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            open_user = self._get_user(user)
 | 
			
		||||
            try:
 | 
			
		||||
                old_key = open_user.template.ssh_public_key 
 | 
			
		||||
                if public_key not in old_key:
 | 
			
		||||
                    raise KeyDoesNotExistsError()
 | 
			
		||||
                if '\n{}'.format(public_key) in old_key:
 | 
			
		||||
                    public_key = old_key.replace('\n{}'.format(public_key), '')
 | 
			
		||||
                else: 
 | 
			
		||||
                    public_key = old_key.replace(public_key, '')
 | 
			
		||||
 | 
			
		||||
            except AttributeError:
 | 
			
		||||
                raise KeyDoesNotExistsError()
 | 
			
		||||
                
 | 
			
		||||
            self.oneadmin_client.call('user.update', open_user.id,
 | 
			
		||||
                         '<CONTEXT><SSH_PUBLIC_KEY>{key}</SSH_PUBLIC_KEY></CONTEXT>'.format(key=public_key))
 | 
			
		||||
            return True
 | 
			
		||||
        except WrongNameError:
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
        except ConnectionError:
 | 
			
		||||
            raise
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,36 +11,10 @@ from .models import OpenNebulaManager
 | 
			
		|||
class VirtualMachineTemplateSerializer(serializers.Serializer):
 | 
			
		||||
    """Serializer to map the virtual machine template instance into JSON format."""
 | 
			
		||||
    id          = serializers.IntegerField(read_only=True)
 | 
			
		||||
    set_name    = serializers.CharField(read_only=True, label='Name')
 | 
			
		||||
    name        = serializers.SerializerMethodField()
 | 
			
		||||
    cores       = serializers.SerializerMethodField() 
 | 
			
		||||
    disk        = serializers.IntegerField(write_only=True)
 | 
			
		||||
    disk_size   = serializers.SerializerMethodField()
 | 
			
		||||
    set_memory      = serializers.IntegerField(write_only=True, label='Memory')
 | 
			
		||||
    memory      = serializers.SerializerMethodField()
 | 
			
		||||
    price       = serializers.SerializerMethodField()
 | 
			
		||||
 | 
			
		||||
    def create(self, validated_data):
 | 
			
		||||
        data = validated_data
 | 
			
		||||
        template = data.pop('template')
 | 
			
		||||
 | 
			
		||||
        cores = template.pop('vcpu')
 | 
			
		||||
        name    = data.pop('name')
 | 
			
		||||
        disk_size = data.pop('disk') 
 | 
			
		||||
        memory  = template.pop('memory')
 | 
			
		||||
        manager = OpenNebulaManager()
 | 
			
		||||
        
 | 
			
		||||
        try:
 | 
			
		||||
            opennebula_id = manager.create_template(name=name, cores=cores,
 | 
			
		||||
                                                    memory=memory,
 | 
			
		||||
                                                    disk_size=disk_size,
 | 
			
		||||
                                                    core_price=core_price,
 | 
			
		||||
                                                    disk_size_price=disk_size_price,
 | 
			
		||||
                                                    memory_price=memory_price)
 | 
			
		||||
        except OpenNebulaException as err:
 | 
			
		||||
            raise serializers.ValidationError("OpenNebulaException occured. {0}".format(err))
 | 
			
		||||
        
 | 
			
		||||
        return manager.get_template(template_id=opennebula_id)
 | 
			
		||||
 | 
			
		||||
    def get_cores(self, obj):
 | 
			
		||||
        if hasattr(obj.template, 'vcpu'):
 | 
			
		||||
| 
						 | 
				
			
			@ -58,24 +32,14 @@ class VirtualMachineTemplateSerializer(serializers.Serializer):
 | 
			
		|||
        except:
 | 
			
		||||
            return 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_price(self, obj):
 | 
			
		||||
        template = obj.template
 | 
			
		||||
        price = float(template.cpu) * 5.0
 | 
			
		||||
        price += (int(template.memory)/1024 * 2.0)
 | 
			
		||||
        try:
 | 
			
		||||
            for disk in template.disks:
 | 
			
		||||
                price += int(disk.size)/1024 * 0.6
 | 
			
		||||
        except:
 | 
			
		||||
            pass
 | 
			
		||||
        return price
 | 
			
		||||
 | 
			
		||||
    def get_memory(self, obj):
 | 
			
		||||
        return int(obj.template.memory)/1024
 | 
			
		||||
 | 
			
		||||
    def get_name(self, obj):
 | 
			
		||||
        return obj.name.strip('public-')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachineSerializer(serializers.Serializer):
 | 
			
		||||
    """Serializer to map the virtual machine instance into JSON format."""
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,35 +1,54 @@
 | 
			
		|||
import socket
 | 
			
		||||
import random
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
from django.test import TestCase
 | 
			
		||||
from .models import VirtualMachine, VirtualMachineTemplate, OpenNebulaManager
 | 
			
		||||
 | 
			
		||||
from .models import OpenNebulaManager
 | 
			
		||||
from .serializers import VirtualMachineSerializer
 | 
			
		||||
from utils.models import CustomUser
 | 
			
		||||
 | 
			
		||||
class OpenNebulaManagerTestCases(TestCase):
 | 
			
		||||
    """This class defines the test suite for the opennebula manager model."""
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        """Define the test client and other test variables."""
 | 
			
		||||
        self.cores = 1 
 | 
			
		||||
        self.memory = 1
 | 
			
		||||
        self.disk_size = 10.0
 | 
			
		||||
        
 | 
			
		||||
        self.email = 'test@test.com'
 | 
			
		||||
        self.password = 'testtest'
 | 
			
		||||
 | 
			
		||||
        self.manager = OpenNebulaManager(email=None, password=None, create_user=False) 
 | 
			
		||||
        self.email = '{}@ungleich.ch'.format(''.join(random.choices(string.ascii_uppercase, k=10)))
 | 
			
		||||
        self.password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=20)) 
 | 
			
		||||
 | 
			
		||||
        self.user = CustomUser.objects.create(name='test', email=self.email,
 | 
			
		||||
                password=self.password) 
 | 
			
		||||
 | 
			
		||||
        self.vm_specs = {}
 | 
			
		||||
        self.vm_specs['cpu'] = 1
 | 
			
		||||
        self.vm_specs['memory'] = 2
 | 
			
		||||
        self.vm_specs['disk_size'] = 10
 | 
			
		||||
 | 
			
		||||
        self.manager = OpenNebulaManager() 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_model_can_connect_to_server(self):
 | 
			
		||||
        """Test the opennebula manager model can connect to a server."""
 | 
			
		||||
    def test_connect_to_server(self):
 | 
			
		||||
        """Test the opennebula manager can connect to a server."""
 | 
			
		||||
        try:
 | 
			
		||||
            user_pool = self.manager._get_user_pool()
 | 
			
		||||
        except:
 | 
			
		||||
            user_pool = None
 | 
			
		||||
        self.assertFalse(user_pool is None)
 | 
			
		||||
            ver = self.manager.oneadmin_client.version()
 | 
			
		||||
        except: 
 | 
			
		||||
            ver = None
 | 
			
		||||
        self.assertTrue(ver is not None)
 | 
			
		||||
 | 
			
		||||
    def test_model_can_create_user(self):
 | 
			
		||||
        """Test the opennebula manager model can create a new user."""
 | 
			
		||||
    def test_get_user(self):
 | 
			
		||||
        """Test the opennebula manager can get a existing user."""
 | 
			
		||||
        self.manager.create_user(self.user)
 | 
			
		||||
        user = self.manager._get_user(self.user)
 | 
			
		||||
        name = user.name
 | 
			
		||||
        self.assertNotEqual(name, None)
 | 
			
		||||
 | 
			
		||||
    def test_create_and_delete_user(self):
 | 
			
		||||
        """Test the opennebula manager can create and delete a new user."""
 | 
			
		||||
        old_count = len(self.manager._get_user_pool())
 | 
			
		||||
        self.manager = OpenNebulaManager(email=self.email,
 | 
			
		||||
                                         password=self.password,
 | 
			
		||||
                                         create_user=True)
 | 
			
		||||
                                         password=self.password)
 | 
			
		||||
        user_pool = self.manager._get_user_pool()
 | 
			
		||||
        new_count = len(user_pool)
 | 
			
		||||
        # Remove the user afterwards
 | 
			
		||||
| 
						 | 
				
			
			@ -38,105 +57,85 @@ class OpenNebulaManagerTestCases(TestCase):
 | 
			
		|||
        
 | 
			
		||||
        self.assertNotEqual(old_count, new_count)
 | 
			
		||||
 | 
			
		||||
    def test_user_can_login(self):
 | 
			
		||||
        """ Test the manager can login to a new created user"""
 | 
			
		||||
        self.manager.create_user(self.user)
 | 
			
		||||
        user = self.manager._get_user(self.user)
 | 
			
		||||
        client = self.manager._get_client(self.user)
 | 
			
		||||
        version = client.version()
 | 
			
		||||
 | 
			
		||||
class VirtualMachineTemplateTestCase(TestCase):
 | 
			
		||||
    """This class defines the test suite for the virtualmachine template model."""
 | 
			
		||||
        # Cleanup 
 | 
			
		||||
        user.delete()
 | 
			
		||||
        self.assertNotEqual(version, None)
 | 
			
		||||
 | 
			
		||||
    def test_add_public_key_to_user(self):
 | 
			
		||||
        """ Test the manager can add a new public key to an user """
 | 
			
		||||
        self.manager.create_user(self.user)
 | 
			
		||||
        user = self.manager._get_user(self.user)
 | 
			
		||||
        public_key = 'test'
 | 
			
		||||
        self.manager.add_public_key(self.user, public_key)
 | 
			
		||||
        # Fetch new user information from opennebula
 | 
			
		||||
        user.info()
 | 
			
		||||
        user_public_key = user.template.ssh_public_key
 | 
			
		||||
        # Cleanup 
 | 
			
		||||
        user.delete()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(user_public_key, public_key)
 | 
			
		||||
        
 | 
			
		||||
    def test_append_public_key_to_user(self):
 | 
			
		||||
        """ Test the manager can append a new public key to an user """
 | 
			
		||||
        self.manager.create_user(self.user)
 | 
			
		||||
        user = self.manager._get_user(self.user)
 | 
			
		||||
        public_key = 'test'
 | 
			
		||||
        self.manager.add_public_key(self.user, public_key)
 | 
			
		||||
        # Fetch new user information from opennebula
 | 
			
		||||
        user.info()
 | 
			
		||||
        old_public_key = user.template.ssh_public_key
 | 
			
		||||
        self.manager.add_public_key(self.user, public_key, merge=True)
 | 
			
		||||
        user.info()
 | 
			
		||||
        new_public_key = user.template.ssh_public_key
 | 
			
		||||
        # Cleanup 
 | 
			
		||||
        user.delete()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(new_public_key, '{}\n{}'.format(old_public_key,
 | 
			
		||||
            public_key))
 | 
			
		||||
 | 
			
		||||
    def test_remove_public_key_to_user(self):
 | 
			
		||||
        """ Test the manager can remove a public key from an user """
 | 
			
		||||
        self.manager.create_user(self.user)
 | 
			
		||||
        user = self.manager._get_user(self.user)
 | 
			
		||||
        public_key = 'test'
 | 
			
		||||
        self.manager.add_public_key(self.user, public_key)
 | 
			
		||||
        self.manager.add_public_key(self.user, public_key, merge=True)
 | 
			
		||||
        user.info()
 | 
			
		||||
        old_public_key = user.template.ssh_public_key
 | 
			
		||||
        self.manager.remove_public_key(self.user, public_key)
 | 
			
		||||
        user.info()
 | 
			
		||||
        new_public_key = user.template.ssh_public_key
 | 
			
		||||
        # Cleanup 
 | 
			
		||||
        user.delete()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(new_public_key,
 | 
			
		||||
                old_public_key.replace('{}\n'.format(public_key), '', 1))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_requires_ssh_key_for_new_vm(self):
 | 
			
		||||
        """Test the opennebula manager requires the user to have a ssh key when
 | 
			
		||||
        creating a new vm"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachineSerializerTestCase(TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        """Define the test client and other test variables."""
 | 
			
		||||
        self.template_name = "Standard"
 | 
			
		||||
        self.base_price = 0.0
 | 
			
		||||
        self.core_price = 5.0
 | 
			
		||||
        self.memory_price = 2.0
 | 
			
		||||
        self.disk_size_price = 0.6
 | 
			
		||||
 | 
			
		||||
        self.cores = 1 
 | 
			
		||||
        self.memory = 1
 | 
			
		||||
        self.disk_size = 10.0
 | 
			
		||||
 | 
			
		||||
        self.manager = OpenNebulaManager(email=None, password=None, create_user=False)
 | 
			
		||||
        self.opennebula_id = self.manager.create_template(name=self.template_name,
 | 
			
		||||
                                                          cores=self.cores,
 | 
			
		||||
                                                          memory=self.memory,
 | 
			
		||||
                                                          disk_size=self.disk_size)
 | 
			
		||||
 | 
			
		||||
        self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id,
 | 
			
		||||
                                               base_price=self.base_price,
 | 
			
		||||
                                               memory_price=self.memory_price,
 | 
			
		||||
                                               core_price=self.core_price,
 | 
			
		||||
                                               disk_size_price=self.disk_size_price)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_model_can_create_a_virtualmachine_template(self):
 | 
			
		||||
        """Test the virtualmachine template model can create a template."""
 | 
			
		||||
        old_count = VirtualMachineTemplate.objects.count()
 | 
			
		||||
        self.template.save()
 | 
			
		||||
        new_count = VirtualMachineTemplate.objects.count()
 | 
			
		||||
        # Remove the template afterwards
 | 
			
		||||
        template = self.manager._get_template(self.template.opennebula_id)
 | 
			
		||||
        template.delete()
 | 
			
		||||
        self.assertNotEqual(old_count, new_count)
 | 
			
		||||
 | 
			
		||||
    def test_model_can_calculate_price(self):
 | 
			
		||||
        price = self.cores * self.core_price
 | 
			
		||||
        price += self.memory * self.memory_price
 | 
			
		||||
        price += self.disk_size * self.disk_size_price 
 | 
			
		||||
        self.assertEqual(price, self.template.calculate_price())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VirtualMachineTestCase(TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        """Define the test client and other test variables."""
 | 
			
		||||
        self.template_name = "Standard"
 | 
			
		||||
        self.base_price = 0.0
 | 
			
		||||
        self.core_price = 5.0
 | 
			
		||||
        self.memory_price = 2.0
 | 
			
		||||
        self.disk_size_price = 0.6
 | 
			
		||||
 | 
			
		||||
        self.cores = 1 
 | 
			
		||||
        self.memory = 1
 | 
			
		||||
        self.disk_size = 10.0
 | 
			
		||||
        self.manager = OpenNebulaManager(email=None, password=None, create_user=False)
 | 
			
		||||
        self.opennebula_id = self.manager.create_template(name=self.template_name,
 | 
			
		||||
                                                          cores=self.cores,
 | 
			
		||||
                                                          memory=self.memory,
 | 
			
		||||
                                                          disk_size=self.disk_size)
 | 
			
		||||
 | 
			
		||||
        self.template = VirtualMachineTemplate(opennebula_id=self.opennebula_id,
 | 
			
		||||
                                               base_price=self.base_price,
 | 
			
		||||
                                               memory_price=self.memory_price,
 | 
			
		||||
                                               core_price=self.core_price,
 | 
			
		||||
                                               disk_size_price=self.disk_size_price)
 | 
			
		||||
        self.template_id = self.template.opennebula_id()
 | 
			
		||||
        self.opennebula_id = self.manager.create_virtualmachine(template_id=self.template_id)
 | 
			
		||||
        self.manager = OpenNebulaManager(email=None, password=None)
 | 
			
		||||
                                           
 | 
			
		||||
        self.virtualmachine = VirtualMachine(opennebula_id=self.opennebula_id,
 | 
			
		||||
                                             template=self.template)
 | 
			
		||||
 | 
			
		||||
    def test_serializer_strips_of_public(self):
 | 
			
		||||
        """ Test the serialized object contains no 'public-'.""" 
 | 
			
		||||
        """ Test the serialized virtual machine object contains no 'public-'.""" 
 | 
			
		||||
 | 
			
		||||
        template = self.manager.get_templates().first()
 | 
			
		||||
        serialized = VirtualMachineTemplateSerializer(template)
 | 
			
		||||
        self.assertEqual(serialized.data.name, template.name.strip('public-'))
 | 
			
		||||
        for vm in self.manager.get_vms():
 | 
			
		||||
            serialized = VirtualMachineSerializer(vm)
 | 
			
		||||
            self.assertEqual(serialized.data.get('name'), vm.name.strip('public-'))
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    def test_model_can_create_a_virtualmachine(self):
 | 
			
		||||
        """Test the virtualmachine model can create a virtualmachine."""
 | 
			
		||||
        old_count = VirtualMachine.objects.count()
 | 
			
		||||
        self.virtualmachine.save()
 | 
			
		||||
        new_count = VirtualMachine.objects.count()
 | 
			
		||||
        self.assertNotEqual(old_count, new_count)
 | 
			
		||||
 | 
			
		||||
    def test_model_can_create_a_virtualmachine_for_user(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def test_model_can_delete_a_virtualmachine(self):
 | 
			
		||||
        """Test the virtualmachine model can delete a virtualmachine."""
 | 
			
		||||
        self.virtualmachine.save()
 | 
			
		||||
        old_count = VirtualMachine.objects.count()
 | 
			
		||||
        VirtualMachine.objects.first().delete()
 | 
			
		||||
        new_count = VirtualMachine.objects.count()
 | 
			
		||||
        self.assertNotEqual(old_count, new_count)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,10 @@
 | 
			
		|||
from django.conf.urls import url, include
 | 
			
		||||
from rest_framework.urlpatterns import format_suffix_patterns
 | 
			
		||||
from .views import TemplateCreateView, TemplateDetailsView,\
 | 
			
		||||
                   VmCreateView, VmDetailsView
 | 
			
		||||
from .views import VmCreateView, VmDetailsView
 | 
			
		||||
 | 
			
		||||
urlpatterns = {
 | 
			
		||||
    url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
 | 
			
		||||
 | 
			
		||||
    url(r'^templates/$', TemplateCreateView.as_view(), name="template_create"),
 | 
			
		||||
    url(r'^templates/(?P<pk>[0-9]+)/$', TemplateDetailsView.as_view(),
 | 
			
		||||
        name="templates_details"),
 | 
			
		||||
    
 | 
			
		||||
    url(r'^vms/$', VmCreateView.as_view(), name="vm_create"),
 | 
			
		||||
    url(r'^vms/(?P<pk>[0-9]+)/$', VmDetailsView.as_view(),
 | 
			
		||||
        name="vm_details"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,38 +20,6 @@ class ServiceUnavailable(APIException):
 | 
			
		|||
    default_code = 'service_unavailable'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TemplateCreateView(generics.ListCreateAPIView):
 | 
			
		||||
    """This class handles the GET and POST requests."""
 | 
			
		||||
 | 
			
		||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        manager = OpenNebulaManager()
 | 
			
		||||
        return manager.get_templates()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def perform_create(self, serializer):
 | 
			
		||||
        """Save the post data when creating a new template."""
 | 
			
		||||
        serializer.save()
 | 
			
		||||
 | 
			
		||||
class TemplateDetailsView(generics.RetrieveUpdateDestroyAPIView):
 | 
			
		||||
    """This class handles the http GET, PUT and DELETE requests."""
 | 
			
		||||
 | 
			
		||||
    serializer_class = VirtualMachineTemplateSerializer
 | 
			
		||||
    permission_classes = (permissions.IsAuthenticated)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        manager = OpenNebulaManager()
 | 
			
		||||
        # We may have ConnectionRefusedError if we don't have a 
 | 
			
		||||
        # connection to OpenNebula. For now, we raise ServiceUnavailable
 | 
			
		||||
        try:
 | 
			
		||||
            templates = manager.get_templates()
 | 
			
		||||
        except ConnectionRefusedError:
 | 
			
		||||
            raise ServiceUnavailable            
 | 
			
		||||
        
 | 
			
		||||
        return templates
 | 
			
		||||
 | 
			
		||||
class VmCreateView(generics.ListCreateAPIView):
 | 
			
		||||
    """This class handles the GET and POST requests."""
 | 
			
		||||
    serializer_class = VirtualMachineSerializer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue