codecov-io: # [Codecov](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=h1) Report
> Merging [#119](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=desc) into [master](https://codecov.io/gh/MatterMiners/tardis/commit/60d00ae8a6adc720903632ef823941418210ccd7?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/MatterMiners/tardis/pull/119/graphs/tree.svg?width=650&token=BKeuDMxoaj&height=150&src=pr)](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #119      +/-   ##
==========================================
+ Coverage    97.6%   97.61%   +<.01%     
==========================================
  Files          39       39              
  Lines        1421     1424       +3     
==========================================
+ Hits         1387     1390       +3     
  Misses         34       34
```


| [Impacted Files](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tardis/configuration/configuration.py](https://codecov.io/gh/MatterMiners/tardis/pull/119/diff?src=pr&el=tree#diff-dGFyZGlzL2NvbmZpZ3VyYXRpb24vY29uZmlndXJhdGlvbi5weQ==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=footer). Last update [60d00ae...20b478b](https://codecov.io/gh/MatterMiners/tardis/pull/119?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/docs/source/executors/executors.rst b/docs/source/executors/executors.rst
index 2bb46bb..711d444 100644
--- a/docs/source/executors/executors.rst
+++ b/docs/source/executors/executors.rst
@@ -7,9 +7,13 @@ Executors
 .. container:: left-col
 
     All executors can be loaded using YAML tags using the (`!Tag`) syntax. More details are available in the
-    `PyYAML documentation`_
+    `PyYAML documentation`_.
+
+    Alternatively you can also use the legacy `COBalD object initialisation syntax`_ to construct executors.
+    But it is discouraged.
 
     .. _PyYAML documentation: https://pyyaml.org/wiki/PyYAMLDocumentation
+    .. _COBalD object initialisation syntax: https://cobald.readthedocs.io/en/latest/source/daemon/config.html#object-references
 
 Shell Executor
 --------------
@@ -26,6 +30,12 @@ Shell Executor
 
       !ShellExecutor
 
+    .. rubric:: Example configuration (`COBalD` legacy object initialisation)
+
+    .. code-block:: yaml
+
+        __type__: tardis.utilities.executors.shellexecutor.ShellExecutor
+
 SSH Executor
 ------------
 
@@ -49,3 +59,12 @@ SSH Executor
         client_keys:
           - /opt/tardis/ssh/tardis
 
+    .. rubric:: Example configuration (`COBalD` legacy object initialisation)
+
+    .. code-block:: yaml
+
+        __type__: tardis.utilities.executors.sshexecutor.SSHExecutor
+        host: login.dorie.somewherein.de
+        username: clown
+        client_keys:
+          - /opt/tardis/ssh/tardis
diff --git a/tardis/configuration/configuration.py b/tardis/configuration/configuration.py
index b02bc0f..f5ea52d 100644
--- a/tardis/configuration/configuration.py
+++ b/tardis/configuration/configuration.py
@@ -6,22 +6,26 @@ from ..utilities.attributedict import convert_to_attribute_dict
 from ..utilities.executors import *  # noqa: F403, F401
 from ..utilities.simulators import *  # noqa: F403, F401
 
+from cobald.daemon.config.mapping import Translator
+
 from base64 import b64encode
 import os
 import yaml
 
 
-def encode_user_data(obj):
+def translate_config(obj):
     if isinstance(obj, AttributeDict):
         for key, value in obj.items():
-            if key == "user_data":
+            if key == "user_data":  # base64 encode user data
                 with open(os.path.join(os.getcwd(), obj[key]), "rb") as f:
                     obj[key] = b64encode(f.read())
+            elif key == "__type__":  # do legacy object initialisation
+                return Translator().translate_hierarchy(obj)
             else:
-                obj[key] = encode_user_data(value)
+                obj[key] = translate_config(value)
         return obj
     elif isinstance(obj, list):
-        return [encode_user_data(item) for item in obj]
+        return [translate_config(item) for item in obj]
     else:
         return obj
 
@@ -42,5 +46,5 @@ class Configuration(Borg):
         """
         with open(config_file, "r") as config_file:
             self._shared_state.update(
-                encode_user_data(convert_to_attribute_dict(yaml.safe_load(config_file)))
+                translate_config(convert_to_attribute_dict(yaml.safe_load(config_file)))
             )

AttributeError: 'str' object has no attribute 'run_command'
Trying out a site with `Slurm` adapter and `SSHExecutor`I always receive the following error:
```
File "/opt/cobald/lib64/python3.6/site-packages/tardis/adapters/sites/slurm.py", line 156, in handle_exceptions
yield
File "/opt/cobald/lib64/python3.6/site-packages/tardis/agents/siteagent.py", line 15, in deploy_resource
resource_attributes=resource_attributes
File "/opt/cobald/lib64/python3.6/site-packages/tardis/adapters/sites/slurm.py", line 100, in deploy_resource
result = await self._executor.run_command(request_command)
AttributeError: 'str' object has no attribute 'run_command'
```
Any idea what might go wrong here?
diff --git a/tests/configuration_t/Sites.yml b/tests/configuration_t/Sites.yml
index 8c5a8c9..4274fc6 100644
--- a/tests/configuration_t/Sites.yml
+++ b/tests/configuration_t/Sites.yml
@@ -1,8 +1,17 @@
 Sites:
   - name: EXOSCALE
     adapter: CloudStack
+  - name: SLURM
+    adapter: Slurm
 
 EXOSCALE:
   MachineTypeConfiguration:
     Micro:
-      user_data: tests/data/exoscale.ini
\ No newline at end of file
+      user_data: tests/data/exoscale.ini
+SLURM:
+  executor:
+    __type__: tardis.utilities.executors.sshexecutor.SSHExecutor
+    host: somehost.de
+    username: someuser
+    client_keys:
+      - "where the private key is"
diff --git a/tests/configuration_t/test_configuration.py b/tests/configuration_t/test_configuration.py
index 9c0ed59..81d1155 100644
--- a/tests/configuration_t/test_configuration.py
+++ b/tests/configuration_t/test_configuration.py
@@ -1,4 +1,5 @@
 from tardis.configuration.configuration import Configuration
+from tardis.utilities.executors.sshexecutor import SSHExecutor
 
 from unittest import TestCase
 import os
@@ -24,22 +25,37 @@ class TestConfiguration(TestCase):
         self.configuration1.load_config(os.path.join(self.test_path, "Sites.yml"))
         self.assertEqual(id(self.configuration1.Sites), id(self.configuration2.Sites))
         self.assertEqual(
-            self.configuration1.Sites, [dict(name="EXOSCALE", adapter="CloudStack")]
+            self.configuration1.Sites,
+            [
+                dict(name="EXOSCALE", adapter="CloudStack"),
+                dict(name="SLURM", adapter="Slurm"),
+            ],
         )
         self.assertEqual(
             self.configuration2.CloudStackAIO,
             {"api_key": "asdfghjkl", "api_secret": "qwertzuiop"},
         )
 
-    def test_base64_encoded_user_data(self):
-        result = (
+    def test_translate_config(self):
+        b64_result = (
             b"I2Nsb3VkLWNvbmZpZwoKd3JpdGVfZmlsZXM6CiAgLSBwYXRoOiAvZXRjL2huc2NpY2xvdWQvc2l0ZS1pZC5jZmcKICAgIGNvbn",
             b"RlbnQ6IHwKICAgICAgRXhvc2NhbGUKICAgIHBlcm1pc3Npb25zOiAnMDY0NCcK",
         )
         self.configuration1.load_config(os.path.join(self.test_path, "Sites.yml"))
         self.assertEqual(
             self.configuration1.EXOSCALE.MachineTypeConfiguration.Micro.user_data,
-            b"".join(result),
+            b"".join(b64_result),
+        )
+
+        executor = self.configuration1.SLURM.executor
+        self.assertIsInstance(executor, SSHExecutor)
+        self.assertEqual(
+            executor._parameters,
+            dict(
+                host="somehost.de",
+                username="someuser",
+                client_keys=["where the private key is"],
+            ),
         )
 
     def test_access_missing_attribute(self):

pip install -e .[contrib]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aiohttp==3.8.6
aiosignal==1.3.1
aiotelegraf==0.4.0
aiotools==1.6.1
async-timeout==4.0.3
AsyncOpenStackClient==0.9.0
asyncssh==2.14.2
asynctest==0.13.0
attrs==24.2.0
black==23.3.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
click==8.1.8
CloudStackAIO==0.0.8
cobald==0.13.0
-e git+https://github.com/MatterMiners/tardis.git@60d00ae8a6adc720903632ef823941418210ccd7#egg=cobald_tardis
cryptography==44.0.2
entrypoints==0.4
exceptiongroup==1.2.2
flake8==5.0.4
flake8-bugbear==23.3.12
frozenlist==1.3.3
idna==3.10
importlib-metadata==4.2.0
iniconfig==2.0.0
json-encoder==0.4.4
mccabe==0.7.0
multidict==6.0.5
mypy-extensions==1.0.0
outcome==1.3.0.post0
packaging==24.0
pathspec==0.11.2
platformdirs==2.6.1
pluggy==1.2.0
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
pytelegraf==0.3.3
pytest==7.4.4
python-dateutil==2.8.0
python-status==1.0.1
PyYAML==6.0.1
requests==2.31.0
simple-rest-client==0.5.4
simplejson==3.16.0
singledispatch==4.0.0
six==1.17.0
sniffio==1.3.1
sortedcontainers==2.4.0
tomli==2.0.1
toposort==1.10
trio==0.22.2
typed-ast==1.5.5
typing-extensions==3.10.0.2
urllib3==2.0.7
yarl==1.9.4
zipp==3.15.0

name: tardis
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aiohttp==3.8.6
      - aiosignal==1.3.1
      - aiotelegraf==0.4.0
      - aiotools==1.6.1
      - async-timeout==4.0.3
      - asyncopenstackclient==0.9.0
      - asyncssh==2.14.2
      - asynctest==0.13.0
      - attrs==24.2.0
      - black==23.3.0
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - cloudstackaio==0.0.8
      - cobald==0.13.0
      - cryptography==44.0.2
      - entrypoints==0.4
      - exceptiongroup==1.2.2
      - flake8==5.0.4
      - flake8-bugbear==23.3.12
      - frozenlist==1.3.3
      - idna==3.10
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - json-encoder==0.4.4
      - mccabe==0.7.0
      - multidict==6.0.5
      - mypy-extensions==1.0.0
      - outcome==1.3.0.post0
      - packaging==24.0
      - pathspec==0.11.2
      - platformdirs==2.6.1
      - pluggy==1.2.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pytelegraf==0.3.3
      - pytest==7.4.4
      - python-dateutil==2.8.0
      - python-status==1.0.1
      - pyyaml==6.0.1
      - requests==2.31.0
      - simple-rest-client==0.5.4
      - simplejson==3.16.0
      - singledispatch==4.0.0
      - six==1.17.0
      - sniffio==1.3.1
      - sortedcontainers==2.4.0
      - tomli==2.0.1
      - toposort==1.10
      - trio==0.22.2
      - typed-ast==1.5.5
      - typing-extensions==3.10.0.2
      - urllib3==2.0.7
      - yarl==1.9.4
      - zipp==3.15.0
prefix: /opt/conda/envs/tardis

tests/configuration_t/test_configuration.py::TestConfiguration::test_translate_config
tests/configuration_t/test_configuration.py::TestConfiguration::test_access_missing_attribute tests/configuration_t/test_configuration.py::TestConfiguration::test_configuration_instances tests/configuration_t/test_configuration.py::TestConfiguration::test_load_configuration tests/configuration_t/test_configuration.py::TestConfiguration::test_shared_state
docs/source/executors/executors.rst tardis/configuration/configuration.py
docs/source/executors/executors.rst tardis/configuration/configuration.py