Commit f9f4c6a3 by Bach Dániel

Merge branch 'feature-pass-reset-op-merged'

Conflicts:
	circle/dashboard/views.py
parents eaea5499 83f9b7ce
...@@ -98,17 +98,12 @@ ...@@ -98,17 +98,12 @@
</div> </div>
</dd> </dd>
<dd style="font-size: 10px; text-align: right; padding-top: 8px;"> <dd style="font-size: 10px; text-align: right; padding-top: 8px;">
<a id="vm-details-pw-change" href="#">{% trans "Generate new password!" %}</a> <div id="vm-details-pw-reset">
{% with op=op.password_reset %}{% if op %}
<a href="{{op.get_url}}" class="btn operation btn-default btn-xs" {% if op.disabled %}disabled{% endif %}>{% trans "Generate new password!" %}</a>
{% endif %}{% endwith %}
</div>
</dd> </dd>
<div id="vm-details-pw-confirm"> {% comment %} TODO Couldn't this use a modal? {% endcomment%}
<dt>
{% trans "Are you sure?" %}
</dt>
<dd>
<a href="#" class="vm-details-pw-confirm-choice label label-success" data-choice="1" data-vm="{{ instance.pk }}">{% trans "Yes" %}</a> /
<a href="#" class="vm-details-pw-confirm-choice label label-danger" data-choice="0">{% trans "No" %}</a>
</dd>
</div>
</dl> </dl>
<div class="input-group" id="dashboard-vm-details-connect-command"> <div class="input-group" id="dashboard-vm-details-connect-command">
......
...@@ -143,26 +143,13 @@ class VmDetailTest(LoginMixin, TestCase): ...@@ -143,26 +143,13 @@ class VmDetailTest(LoginMixin, TestCase):
response = c.post('/dashboard/vm/mass-delete/', {'vms': [1]}) response = c.post('/dashboard/vm/mass-delete/', {'vms': [1]})
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
def test_permitted_password_change(self):
c = Client()
self.login(c, "user2")
inst = Instance.objects.get(pk=1)
inst.set_level(self.u2, 'owner')
inst.node = Node.objects.all()[0]
inst.save()
password = inst.pw
response = c.post("/dashboard/vm/1/", {'change_password': True})
self.assertTrue(Instance.get_remote_queue_name.called)
self.assertEqual(response.status_code, 302)
self.assertNotEqual(password, Instance.objects.get(pk=1).pw)
def test_unpermitted_password_change(self): def test_unpermitted_password_change(self):
c = Client() c = Client()
self.login(c, "user2") self.login(c, "user2")
inst = Instance.objects.get(pk=1) inst = Instance.objects.get(pk=1)
inst.set_level(self.u1, 'owner') inst.set_level(self.u1, 'owner')
password = inst.pw password = inst.pw
response = c.post("/dashboard/vm/1/", {'change_password': True}) response = c.post("/dashboard/vm/1/op/password_reset/")
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(password, Instance.objects.get(pk=1).pw) self.assertEqual(password, Instance.objects.get(pk=1).pw)
......
...@@ -306,7 +306,6 @@ class VmDetailView(CheckedDetailView): ...@@ -306,7 +306,6 @@ class VmDetailView(CheckedDetailView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
options = { options = {
'change_password': self.__change_password,
'new_name': self.__set_name, 'new_name': self.__set_name,
'new_description': self.__set_description, 'new_description': self.__set_description,
'new_tag': self.__add_tag, 'new_tag': self.__add_tag,
...@@ -321,19 +320,6 @@ class VmDetailView(CheckedDetailView): ...@@ -321,19 +320,6 @@ class VmDetailView(CheckedDetailView):
raise Http404() raise Http404()
def __change_password(self, request):
self.object = self.get_object()
if not self.object.has_level(request.user, 'owner'):
raise PermissionDenied()
self.object.change_password(user=request.user)
messages.success(request, _("Password changed."))
if request.is_ajax():
return HttpResponse("Success.")
else:
return redirect(reverse_lazy("dashboard.views.detail",
kwargs={'pk': self.object.pk}))
def __set_name(self, request): def __set_name(self, request):
self.object = self.get_object() self.object = self.get_object()
if not self.object.has_level(request.user, 'owner'): if not self.object.has_level(request.user, 'owner'):
...@@ -627,6 +613,7 @@ class AjaxOperationMixin(object): ...@@ -627,6 +613,7 @@ class AjaxOperationMixin(object):
store.used = True store.used = True
return HttpResponse( return HttpResponse(
json.dumps({'success': True, json.dumps({'success': True,
'with_reload': getattr(self, 'with_reload', False),
'messages': [unicode(m) for m in store]}), 'messages': [unicode(m) for m in store]}),
content_type="application=json" content_type="application=json"
) )
...@@ -909,6 +896,9 @@ vm_ops = OrderedDict([ ...@@ -909,6 +896,9 @@ vm_ops = OrderedDict([
('add_interface', VmAddInterfaceView), ('add_interface', VmAddInterfaceView),
('renew', VmRenewView), ('renew', VmRenewView),
('resources_change', VmResourcesChangeView), ('resources_change', VmResourcesChangeView),
('password_reset', VmOperationView.factory(
op='password_reset', icon='unlock', effect='warning',
show_in_toolbar=False, wait_for_result=0.5, with_reload=True)),
]) ])
......
...@@ -13,6 +13,7 @@ from .instance import InstanceTemplate ...@@ -13,6 +13,7 @@ from .instance import InstanceTemplate
from .instance import Instance from .instance import Instance
from .instance import post_state_changed from .instance import post_state_changed
from .instance import pre_state_changed from .instance import pre_state_changed
from .instance import pwgen
from .network import InterfaceTemplate from .network import InterfaceTemplate
from .network import Interface from .network import Interface
from .node import Node from .node import Node
...@@ -22,5 +23,5 @@ __all__ = [ ...@@ -22,5 +23,5 @@ __all__ = [
'NamedBaseResourceConfig', 'VirtualMachineDescModel', 'InstanceTemplate', 'NamedBaseResourceConfig', 'VirtualMachineDescModel', 'InstanceTemplate',
'Instance', 'instance_activity', 'post_state_changed', 'pre_state_changed', 'Instance', 'instance_activity', 'post_state_changed', 'pre_state_changed',
'InterfaceTemplate', 'Interface', 'Trait', 'Node', 'NodeActivity', 'Lease', 'InterfaceTemplate', 'Interface', 'Trait', 'Node', 'NodeActivity', 'Lease',
'node_activity', 'node_activity', 'pwgen'
] ]
...@@ -731,24 +731,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin, ...@@ -731,24 +731,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
timezone.now() + lease.suspend_interval, timezone.now() + lease.suspend_interval,
timezone.now() + lease.delete_interval) timezone.now() + lease.delete_interval)
def change_password(self, user=None):
"""Generate new password for the vm
:param self: The virtual machine.
:param user: The user who's issuing the command.
"""
self.pw = pwgen()
with instance_activity(code_suffix='change_password', instance=self,
readable_name=ugettext_noop("change password"),
user=user):
queue = self.get_remote_queue_name("agent")
agent_tasks.change_password.apply_async(queue=queue,
args=(self.vm_name,
self.pw))
self.save()
def select_node(self): def select_node(self):
"""Returns the node the VM should be deployed or migrated to. """Returns the node the VM should be deployed or migrated to.
""" """
......
...@@ -33,8 +33,9 @@ from .tasks.local_tasks import ( ...@@ -33,8 +33,9 @@ from .tasks.local_tasks import (
) )
from .models import ( from .models import (
Instance, InstanceActivity, InstanceTemplate, Interface, Node, Instance, InstanceActivity, InstanceTemplate, Interface, Node,
NodeActivity, NodeActivity, pwgen
) )
from .tasks import agent_tasks
logger = getLogger(__name__) logger = getLogger(__name__)
...@@ -879,3 +880,27 @@ class ResourcesOperation(InstanceOperation): ...@@ -879,3 +880,27 @@ class ResourcesOperation(InstanceOperation):
register_operation(ResourcesOperation) register_operation(ResourcesOperation)
class PasswordResetOperation(InstanceOperation):
activity_code_suffix = 'Password reset'
id = 'password_reset'
name = _("password reset")
description = _("Password reset")
acl_level = "owner"
required_perms = ()
def check_precond(self):
super(PasswordResetOperation, self).check_precond()
if self.instance.status not in ["RUNNING"]:
raise self.instance.WrongStateError(self.instance)
def _operation(self):
self.instance.pw = pwgen()
queue = self.instance.get_remote_queue_name("agent")
agent_tasks.change_password.apply_async(
queue=queue, args=(self.instance.vm_name, self.instance.pw))
self.instance.save()
register_operation(PasswordResetOperation)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment