浏览代码

[oozie] Only accessible workflows can be scheduled

Romain Rigaux 13 年之前
父节点
当前提交
b88c142

+ 10 - 0
apps/oozie/src/oozie/forms.py

@@ -18,6 +18,7 @@
 import logging
 
 from django import forms
+from django.db.models import Q
 
 from desktop.lib.django_forms import MultiForm, SplitDateTimeWidget
 from oozie.models import Workflow, Node, Java, Mapreduce, Streaming, Coordinator,\
@@ -162,7 +163,16 @@ class CoordinatorForm(forms.ModelForm):
     }
 
   def __init__(self, *args, **kwargs):
+    user = kwargs['user']
+    del kwargs['user']
     super(CoordinatorForm, self).__init__(*args, **kwargs)
+    qs = Workflow.objects.filter(Q(is_shared=True) | Q(owner=user))
+    workflows = []
+    for workflow in qs:
+      if workflow.is_accessible(user):
+        workflows.append(workflow.id)
+    qs = qs.filter(id__in=workflows)
+    self.fields['workflow'].queryset = qs
     self.fields['schema_version'].widget = forms.Select(choices=(('uri:oozie:coordinator:0.1', '0.1'),
                                                                  ('uri:oozie:coordinator:0.2', '0.2'),
                                                                  ('uri:oozie:coordinator:0.3', '0.3'),

+ 3 - 3
apps/oozie/src/oozie/models.py

@@ -1014,9 +1014,9 @@ class Coordinator(Job):
                                               'allowed to run concurrently ( RUNNING status) before the coordinator engine '
                                               'starts throttling them.'))
   execution = models.CharField(max_length=10, null=True, blank=True,
-                               choices=(('FIFO', 'FIFO (oldest first) default'),
-                                        ('LIFO', 'LIFO (newest first)'),
-                                        ('LAST_ONLY', 'LAST_ONLY (discards all older materializations)')),
+                               choices=(('FIFO', _('FIFO (oldest first) default')),
+                                        ('LIFO', _('LIFO (newest first)')),
+                                        ('LAST_ONLY', _('LAST_ONLY (discards all older materializations)'))),
                                  help_text=_t('Execution strategy of its coordinator actions when there is backlog of coordinator '
                                               'actions in the coordinator engine. The different execution strategies are \'oldest first\', '
                                               '\'newest first\' and \'last one only\'. A backlog normally happens because of delayed '

+ 1 - 1
apps/oozie/src/oozie/templates/editor/edit_coordinator.mako

@@ -343,7 +343,7 @@ ${ layout.menubar(section='coordinators') }
 
   <div class="form-actions center">
     <a href="${ url('oozie:list_coordinators') }" class="btn">${ _('Back') }</a>
-    % if can_edit_coordinator:
+    % if coordinator.is_editable(user):
       <input class="btn btn-primary" data-bind="click: submit" type="submit" value="${ _('Save') }"></input>
     % endif
   </div>

+ 47 - 8
apps/oozie/src/oozie/tests.py

@@ -671,24 +671,62 @@ class TestEditor:
     assert_not_equal('', coord2.deployment_dir)
 
 
-  def test_coordinator_permissions(self):
+  def test_coordinator_workflow_access_permissions(self):
     oozie_api.OozieApi = MockOozieCoordinatorApi
     oozie_api._api_cache = None
 
-    coord = create_coordinator(self.wf)
+    self.wf.is_shared = True
+    self.wf.save()
 
-    response = self.c.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+    # Login as someone else not superuser
+    client_another_me = make_logged_in_client(username='another_me', is_superuser=False, groupname='test')
+    grant_access("another_me", "test", "oozie")
+    coord = create_coordinator(self.wf, client_another_me)
+
+    response = client_another_me.get(reverse('oozie:edit_coordinator', args=[coord.id]))
     assert_true('Editor' in response.content, response.content)
+    assert_true('value="Save"' in response.content, response.content)
+
+    # Check can schedule a non personal/shared workflow
+    workflow_select = '%s</option>' % self.wf
+    response = client_another_me.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+    assert_true(workflow_select in response.content, response.content)
+
+    self.wf.is_shared = False
+    self.wf.save()
+
+    response = client_another_me.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+    assert_false(workflow_select in response.content, response.content)
+
+    self.wf.is_shared = True
+    self.wf.save()
 
     # Edit
     finish = SHARE_JOBS.set_for_testing(True)
     try:
-      response = self.c.post(reverse('oozie:edit_coordinator', args=[coord.id]))
-      assert_true('MyCoord' in response.content, response.content)
-      assert_false('Permission denied' in response.content, response.content)
+      response = client_another_me.post(reverse('oozie:edit_coordinator', args=[coord.id]))
+      assert_true(workflow_select in response.content, response.content)
+      assert_true('value="Save"' in response.content, response.content)
     finally:
       finish()
 
+    finish = SHARE_JOBS.set_for_testing(False)
+    try:
+      response = client_another_me.post(reverse('oozie:edit_coordinator', args=[coord.id]))
+      assert_true('This field is required' in response.content, response.content)
+      assert_false(workflow_select in response.content, response.content)
+      assert_true('value="Save"' in response.content, response.content)
+    finally:
+      finish()
+
+
+  def test_coordinator_permissions(self):
+    coord = create_coordinator(self.wf)
+
+    response = self.c.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+    assert_true('Editor' in response.content, response.content)
+    assert_true('value="Save"' in response.content, response.content)
+
     # Login as someone else
     client_not_me = make_logged_in_client(username='not_me', is_superuser=False, groupname='test')
     grant_access("not_me", "test", "oozie")
@@ -891,8 +929,9 @@ def create_workflow():
   return wf
 
 
-def create_coordinator(workflow):
-  c = make_logged_in_client()
+def create_coordinator(workflow, c=None):
+  if c is None:
+    c = make_logged_in_client()
 
   coord_count = Coordinator.objects.count()
   response = c.get(reverse('oozie:create_coordinator'))

+ 5 - 6
apps/oozie/src/oozie/views/editor.py

@@ -555,7 +555,7 @@ def create_coordinator(request, workflow=None):
     coordinator = Coordinator(owner=request.user, schema_version="uri:oozie:coordinator:0.1")
 
   if request.method == 'POST':
-    coordinator_form = CoordinatorForm(request.POST, instance=coordinator)
+    coordinator_form = CoordinatorForm(request.POST, instance=coordinator, user=request.user)
 
     if coordinator_form.is_valid():
       coordinator = coordinator_form.save()
@@ -563,7 +563,7 @@ def create_coordinator(request, workflow=None):
     else:
       request.error(_('Errors on the form: %s') % coordinator_form.errors)
   else:
-    coordinator_form = CoordinatorForm(instance=coordinator)
+    coordinator_form = CoordinatorForm(instance=coordinator, user=request.user)
 
   return render('editor/create_coordinator.mako', request, {
     'coordinator': coordinator,
@@ -602,7 +602,7 @@ def edit_coordinator(request, coordinator):
   NewDataOutputFormSet.form = staticmethod(curry(DataOutputForm, coordinator=coordinator))
 
   if request.method == 'POST':
-    coordinator_form = CoordinatorForm(request.POST, instance=coordinator)
+    coordinator_form = CoordinatorForm(request.POST, instance=coordinator, user=request.user)
     dataset_formset = DatasetFormSet(request.POST, request.FILES, instance=coordinator)
     data_input_formset = DataInputFormSet(request.POST, request.FILES, instance=coordinator)
     data_output_formset = DataOutputFormSet(request.POST, request.FILES, instance=coordinator)
@@ -617,10 +617,10 @@ def edit_coordinator(request, coordinator):
       new_data_input_formset.save()
       new_data_output_formset.save()
 
-      request.info(_("Coordinator saved!"))
+      request.info(_('Coordinator saved!'))
       return redirect(reverse('oozie:edit_coordinator', kwargs={'coordinator': coordinator.id}))
   else:
-    coordinator_form = CoordinatorForm(instance=coordinator)
+    coordinator_form = CoordinatorForm(instance=coordinator, user=request.user)
     dataset_formset = DatasetFormSet(instance=coordinator)
     data_input_formset = DataInputFormSet(instance=coordinator)
     data_output_formset = DataOutputFormSet(instance=coordinator)
@@ -637,7 +637,6 @@ def edit_coordinator(request, coordinator):
     'new_data_input_formset': new_data_input_formset,
     'new_data_output_formset': new_data_output_formset,
     'history': history,
-    'can_edit_coordinator': coordinator.workflow.is_editable(request.user),
     'parameters': extract_field_data(coordinator_form['parameters'])
   })