Преглед на файлове

[oozie] Can clone a coordinator

Romain Rigaux преди 13 години
родител
ревизия
6b6d5bf

+ 39 - 0
apps/oozie/src/oozie/models.py

@@ -864,6 +864,45 @@ class Coordinator(Job):
     tmpl = "editor/gen/coordinator.xml.mako"
     return re.sub(re.compile('\s*\n+', re.MULTILINE), '\n', django_mako.render_to_string(tmpl, {'coord': self}))
 
+  def clone(self, new_owner=None):
+    datasets = Dataset.objects.filter(coordinator=self)
+    data_inputs = DataInput.objects.filter(coordinator=self)
+    data_outputs = DataOutput.objects.filter(coordinator=self)
+
+    copy = self
+    copy.pk = None
+    copy.id = None
+    copy.name += '-copy'
+    if new_owner is not None:
+      copy.owner = new_owner
+    copy.save()
+
+    old_dataset_mapping = {}
+
+    for dataset in datasets:
+      prev_id = dataset.id
+      dataset.pk = None
+      dataset.id = None
+      dataset.coordinator = copy
+      dataset.save()
+      old_dataset_mapping[prev_id] = dataset
+
+    for data_input in data_inputs:
+      data_input.pk = None
+      data_input.id = None
+      data_input.coordinator = copy
+      data_input.dataset = old_dataset_mapping[data_input.dataset.id]
+      data_input.save()
+
+    for data_output in data_outputs:
+      data_output.pk = None
+      data_output.id = None
+      data_output.coordinator = copy
+      data_output.dataset = old_dataset_mapping[data_output.dataset.id]
+      data_output.save()
+
+    return copy
+
   @classmethod
   def get_application_path_key(cls):
     return 'oozie.coord.application.path'

+ 10 - 1
apps/oozie/src/oozie/templates/editor/list_coordinators.mako

@@ -73,7 +73,7 @@ ${ layout.menubar(section='coordinators') }
                   data-param-url="${ url('oozie:workflow_parameters', workflow=coordinator.id) }"
                   data-delete-url="${ url('oozie:delete_coordinator', coordinator=coordinator.id) }"
               % endif
-                  data-clone-url="${ url('oozie:clone_workflow', workflow=coordinator.id) }"
+                  data-clone-url="${ url('oozie:clone_coordinator', coordinator=coordinator.id) }"
                   data-bundle-url="${ url('oozie:create_coordinator') }"
                   data-submit-url="${ url('oozie:submit_coordinator', coordinator=coordinator.id) }"
               >
@@ -245,6 +245,15 @@ ${ layout.menubar(section='coordinators') }
         $("#deleteWf").modal("show");
     });
 
+    $("#clone-btn").click(function(e){
+        var _this = $('input[name=action]:checked');
+        var _url = _this.attr("data-clone-url");
+
+      $.post(_url, function(data) {
+        window.location = data.url;
+      });
+    });
+
     $("#deleteWf .hideModal").click(function(){
         $("#deleteWf").modal("hide");
     });

+ 29 - 1
apps/oozie/src/oozie/tests.py

@@ -189,10 +189,11 @@ class TestEditor:
     response = self.c.post(reverse('oozie:clone_workflow', args=[self.wf.id]), {}, follow=True)
 
     assert_equal(workflow_count + 1, Workflow.objects.count(), response)
+
     wf2 = Workflow.objects.latest('id')
+    assert_not_equal(self.wf.id, wf2.id)
     assert_equal(self.wf.node_set.count(), wf2.node_set.count())
 
-    assert_not_equal(self.wf.id, wf2.id)
     node_ids = set(self.wf.node_set.values_list('id', flat=True))
     for node in wf2.node_set.all():
       assert_false(node.id in node_ids)
@@ -376,6 +377,33 @@ class TestEditor:
     assert_equal(200, response.status_code)
 
 
+  def test_clone_coordinator(self):
+    coord = create_coordinator(self.wf)
+    coordinator_count = Coordinator.objects.count()
+
+    response = self.c.post(reverse('oozie:clone_coordinator', args=[coord.id]), {}, follow=True)
+
+    wf2 = Coordinator.objects.latest('id')
+    assert_not_equal(coord.id, wf2.id)
+    assert_equal(coordinator_count + 1, Coordinator.objects.count(), response)
+
+    assert_equal(coord.dataset_set.count(), wf2.dataset_set.count())
+    assert_equal(coord.datainput_set.count(), wf2.datainput_set.count())
+    assert_equal(coord.dataoutput_set.count(), wf2.dataoutput_set.count())
+
+    ds_ids = set(coord.dataset_set.values_list('id', flat=True))
+    for node in wf2.dataset_set.all():
+      assert_false(node.id in ds_ids)
+
+    data_input_ids = set(coord.datainput_set.values_list('id', flat=True))
+    for node in wf2.datainput_set.all():
+      assert_false(node.id in data_input_ids)
+
+    data_output_ids = set(coord.dataoutput_set.values_list('id', flat=True))
+    for node in wf2.dataoutput_set.all():
+      assert_false(node.id in data_output_ids)
+
+
   def test_coordinator_permissions(self):
     coord = create_coordinator(self.wf)
 

+ 1 - 0
apps/oozie/src/oozie/urls.py

@@ -43,6 +43,7 @@ urlpatterns = patterns(
   url(r'^create_coordinator/(?P<workflow>[-\w]+)?$', 'create_coordinator', name='create_coordinator'),
   url(r'^edit_coordinator/(?P<coordinator>[-\w]+)$', 'edit_coordinator', name='edit_coordinator'),
   url(r'^delete_coordinator/(?P<coordinator>\d+)$', 'delete_coordinator', name='delete_coordinator'),
+  url(r'^clone_coordinator/(?P<coordinator>\d+)$', 'clone_coordinator', name='clone_coordinator'),
   url(r'^create_coordinator_dataset/(?P<coordinator>[-\w]+)$', 'create_coordinator_dataset', name='create_coordinator_dataset'),
   url(r'^create_coordinator_data/(?P<coordinator>[-\w]+)/(?P<data_type>(input|output))$', 'create_coordinator_data', name='create_coordinator_data'),
   url(r'^submit_coordinator/(?P<coordinator>\d+)$', 'submit_coordinator', name='submit_coordinator'),

+ 13 - 1
apps/oozie/src/oozie/views/editor.py

@@ -468,7 +468,7 @@ def delete_coordinator(request, coordinator):
   coordinator.delete()
   Submission(coordinator, request.fs, {}).remove_deployment_dir()
   request.info(_('Coordinator deleted!'))
-  
+
   return redirect(reverse('oozie:list_workflows'))
 
 
@@ -588,6 +588,18 @@ def create_coordinator_data(request, coordinator, data_type):
   return HttpResponse(json.dumps(response), mimetype="application/json")
 
 
+@check_job_access_permission
+def clone_coordinator(request, coordinator):
+  if request.method != 'POST':
+    raise PopupException(_('A POST request is required.'))
+
+  clone = coordinator.clone(request.user)
+
+  response = {'url': reverse('oozie:edit_coordinator', kwargs={'coordinator': clone.id})}
+
+  return HttpResponse(json.dumps(response), mimetype="application/json")
+
+
 @check_job_access_permission
 def submit_coordinator(request, coordinator):
   if request.method != 'POST':