Repository: xlab-si/xopera-opera

Issue:
Some files linked to the main TOSCA yaml are not accessible to the orchestrator. 
In the case of the CSAR-tree, the orchestrator ignores the referenced file defined in the main TOSCA yaml and returns a

`[Path] Path <path to the file> does not exist.`

type of error. The referenced file is in the same folder then the main file.


Discussion:

Patch:
diff --git a/src/opera/parser/tosca/__init__.py b/src/opera/parser/tosca/__init__.py
index 74ba731..ca5a888 100644
--- a/src/opera/parser/tosca/__init__.py
+++ b/src/opera/parser/tosca/__init__.py
@@ -24,7 +24,7 @@ def load(base_path, template_name):
 
     stdlib_yaml = stdlib.load(tosca_version)
     service = parser.parse(stdlib_yaml, base_path, PurePath("STDLIB"))
-    service.merge(parser.parse(input_yaml, base_path, PurePath()))
+    service.merge(parser.parse(input_yaml, base_path, template_name.parent))
     service.visit("resolve_path", base_path)
     service.visit("resolve_reference", service)
 


Test patch:
diff --git a/tests/opera/parser/test_tosca.py b/tests/opera/parser/test_tosca.py
index c74fd47..f7a5426 100644
--- a/tests/opera/parser/test_tosca.py
+++ b/tests/opera/parser/test_tosca.py
@@ -1,3 +1,5 @@
+import pathlib
+
 import pytest
 
 from opera.error import ParseError
@@ -6,17 +8,19 @@ from opera.parser import tosca
 
 class TestLoad:
     def test_load_minimal_document(self, tmp_path):
-        root = tmp_path / "root.yaml"
-        root.write_text("tosca_definitions_version: tosca_simple_yaml_1_3")
+        name = pathlib.PurePath("root.yaml")
+        (tmp_path / name).write_text(
+            "tosca_definitions_version: tosca_simple_yaml_1_3",
+        )
 
-        doc = tosca.load(root.parent, root.name)
+        doc = tosca.load(tmp_path, name)
         assert doc.tosca_definitions_version.data == "tosca_simple_yaml_1_3"
 
     def test_empty_document_is_invalid(self, tmp_path):
-        root = tmp_path / "root.yaml"
-        root.write_text("{}")
+        name = pathlib.PurePath("empty.yaml")
+        (tmp_path / name).write_text("{}")
         with pytest.raises(ParseError):
-            tosca.load(root.parent, root.name)
+            tosca.load(tmp_path, name)
 
     @pytest.mark.parametrize("typ", [
         ("data_types", "tosca.datatypes.xml"),
@@ -29,10 +33,12 @@ class TestLoad:
         ("policy_types", "tosca.policies.Root"),
     ])
     def test_stdlib_is_present(self, tmp_path, typ):
-        root = tmp_path / "root.yaml"
-        root.write_text("tosca_definitions_version: tosca_simple_yaml_1_3")
+        name = pathlib.PurePath("stdlib.yaml")
+        (tmp_path / name).write_text(
+            "tosca_definitions_version: tosca_simple_yaml_1_3",
+        )
 
-        doc = tosca.load(root.parent, root.name)
+        doc = tosca.load(tmp_path, name)
         assert doc.dig(*typ) is not None
 
     @pytest.mark.parametrize("typ", [
@@ -46,8 +52,8 @@ class TestLoad:
         ("policy_types", "tosca.policies.Root"),
     ])
     def test_custom_type_is_present(self, tmp_path, yaml_text, typ):
-        root = tmp_path / "root.yaml"
-        root.write_text(yaml_text(
+        name = pathlib.PurePath("custom.yaml")
+        (tmp_path / name).write_text(yaml_text(
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             {}:
@@ -56,12 +62,12 @@ class TestLoad:
             """.format(*typ)
         ))
 
-        doc = tosca.load(root.parent, root.name)
+        doc = tosca.load(tmp_path, name)
         assert doc.dig(typ[0], "my.custom.Type") is not None
 
     def test_loads_template_part(self, tmp_path, yaml_text):
-        root = tmp_path / "root.yaml"
-        root.write_text(yaml_text(
+        name = pathlib.PurePath("template.yaml")
+        (tmp_path / name).write_text(yaml_text(
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
@@ -71,5 +77,27 @@ class TestLoad:
             """
         ))
 
-        doc = tosca.load(root.parent, root.name)
+        doc = tosca.load(tmp_path, name)
         assert doc.topology_template.node_templates["my_node"] is not None
+
+    def test_load_from_csar_subfolder(self, tmp_path, yaml_text):
+        name = pathlib.PurePath("sub/folder/file.yaml")
+        (tmp_path / name).parent.mkdir(parents=True)
+        (tmp_path / name).write_text(yaml_text(
+            """
+            tosca_definitions_version: tosca_simple_yaml_1_3
+            imports:
+              - imp.yaml
+            """
+        ))
+        (tmp_path / "sub/folder/imp.yaml").write_text(yaml_text(
+            """
+            tosca_definitions_version: tosca_simple_yaml_1_3
+            data_types:
+              my_type:
+                derived_from: tosca.datatypes.xml
+            """
+        ))
+
+        doc = tosca.load(tmp_path, name)
+        assert doc.data_types["my_type"]