Эх сурвалжийг харах

[oozie] Skip global configuration in 0.4 workflow definition when importing

Fix a few encoding issues as well
Abraham Elmahrek 12 жил өмнө
parent
commit
53bd036

+ 26 - 3
apps/oozie/src/oozie/import_workflow.py

@@ -40,6 +40,7 @@ import logging
 from lxml import etree
 
 from django.core import serializers
+from django.utils.encoding import smart_str
 from django.utils.translation import ugettext as _
 
 from conf import DEFINITION_XSLT_DIR
@@ -79,7 +80,10 @@ def _save_links(workflow, root):
 
   Note: The nodes that these links point to should exist already.
   Note: Nodes are looked up by workflow and name.
+  Note: Skip global configuration explicitly. Unknown knows should throw an error.
   """
+  LOG.debug("Start resolving links for workflow %s" % smart_str(workflow.name))
+
   # Iterate over nodes
   for child_el in root:
     # Skip special nodes (like comments).
@@ -90,10 +94,25 @@ def _save_links(workflow, root):
     if child_el.tag.endswith('kill'):
       continue
 
+    # Skip global configuration.
+    if child_el.tag.endswith('global'):
+      continue
+
+    tag = xml_tag(child_el)
+    name = child_el.attrib.get('name', tag)
+    LOG.debug("Getting node with data - XML TAG: %(tag)s\tLINK NAME: %(node_name)s\tWORKFLOW NAME: %(workflow_name)s" % {
+      'tag': smart_str(tag),
+      'node_name': smart_str(name),
+      'workflow_name': smart_str(workflow.name)
+    })
+
     # Iterate over node members
     # Join nodes have attributes which point to the next node
     # Start node has attribute which points to first node
-    parent = Node.objects.get(workflow=workflow, name=child_el.attrib.get('name', xml_tag(child_el))).get_full_node()
+    try:
+      parent = Node.objects.get(name=name, workflow=workflow).get_full_node()
+    except Node.DoesNotExist, e:
+      raise RuntimeError(_('Node with name %s for workflow %s does not exist.') % (name, workflow.name))
 
     if isinstance(parent, Start):
       _start_relationships(workflow, parent, child_el)
@@ -114,6 +133,8 @@ def _save_links(workflow, root):
   _resolve_fork_relationships(workflow)
   _resolve_decision_relationships(workflow)
 
+  LOG.debug("Finished resolving links for workflow %s" % smart_str(workflow.name))
+
 
 def _start_relationships(workflow, parent, child_el):
   """
@@ -417,7 +438,9 @@ def _resolve_decision_relationships(workflow):
 
 def _prepare_nodes(workflow, root):
   """
-  Deserialize
+  Prepare nodes for groking by Django
+  - Deserialize
+  - Automatically skip undefined nodes.
   """
   objs = serializers.deserialize('xml', etree.tostring(root))
 
@@ -548,7 +571,7 @@ def import_workflow(workflow, workflow_definition, fs=None):
 
   # Ensure namespace exists
   if schema_version not in OOZIE_NAMESPACES:
-    raise RuntimeError(_("Tag with namespace %(namespace)s is not a valid. Please use one of the following namespaces: %(namespaces)s") % {
+    raise RuntimeError(_("Tag with namespace %(namespace)s is not valid. Please use one of the following namespaces: %(namespaces)s") % {
       'namespace': workflow_definition_root.tag,
       'namespaces': ', '.join(OOZIE_NAMESPACES)
     })

+ 5 - 0
apps/oozie/src/oozie/test_data/0.4/test-basic-global-config.xml

@@ -0,0 +1,5 @@
+<workflow-app name="test-workflow" xmlns="uri:oozie:workflow:0.4">
+  <global></global>
+  <start to="done"/>
+  <end name="done"/>
+</workflow-app>

+ 17 - 0
apps/oozie/src/oozie/tests.py

@@ -1466,6 +1466,23 @@ class TestImportWorkflow04(OozieMockBase):
     workflow.delete(skip_trash=True)
 
 
+  def test_import_workflow_basic_global_config(self):
+    """
+    Validates import for basic workflow: start, end, and global configuration.
+    """
+    workflow = Workflow.objects.new_workflow(self.user)
+    workflow.save()
+    f = open('apps/oozie/src/oozie/test_data/0.4/test-basic-global-config.xml')
+    import_workflow(workflow, f.read())
+    f.close()
+    workflow.save()
+    assert_equal(2, len(Node.objects.filter(workflow=workflow)))
+    assert_equal(2, len(Link.objects.filter(parent__workflow=workflow)))
+    assert_equal('done', Node.objects.get(workflow=workflow, node_type='end').name)
+    assert_equal('uri:oozie:workflow:0.4', workflow.schema_version)
+    workflow.delete(skip_trash=True)
+
+
   def test_import_workflow_decision(self):
     """
     Validates import for decision node: link comments (conditions), default link, decision end.

+ 3 - 8
desktop/core/src/desktop/lib/exceptions_renderable.py

@@ -22,6 +22,8 @@ This file exists to remove circular reference caused by importing django_util.
 import sys
 import traceback
 
+from django.utils.encoding import force_unicode
+
 # Need full import statement
 import desktop.lib.django_util
 
@@ -42,14 +44,7 @@ class PopupException(Exception):
     self.traceback = traceback.extract_tb(tb)
 
   def response(self, request):
-    if self.detail:
-      if not isinstance(self.detail, basestring):
-        detail = str(self.detail).decode('utf-8', 'replace')
-      else:
-        detail = self.detail.decode('utf-8', 'replace')
-    else:
-      detail = None
-    data = dict(title=self.title, message=self.message, detail=detail, traceback=self.traceback)
+    data = dict(title=force_unicode(self.title), message=force_unicode(self.message), detail=force_unicode(self.detail), traceback=self.traceback)
     if not request.ajax:
       data['request'] = request
     response = desktop.lib.django_util.render("popup_error.mako", request, data)

+ 1 - 1
desktop/core/src/desktop/templates/popup_error.mako

@@ -24,7 +24,7 @@ ${ commonheader(title, "", user) | n,unicode }
 
   <div class="container-fluid">
     <div class="alert">
-      <p><strong>${smart_unicode(message)}</strong></p>
+      <p><strong>${message}</strong></p>
 
       % if detail:
         <p>${ detail }</p>