Multihost Domains

MultihostDomain has access to the domain part of the configuration file. Its main purpose is to map role names into Python classes that will be used to create the host and role objects.

Basic example of MultihostDomain
 1class MyProjectDomain(MultihostDomain[MyProjectConfig]):
 2    @property
 3    def role_to_host_class(self) -> dict[str, Type[MultihostHost]]:
 4        """
 5        Map role to host class. Asterisk ``*`` can be used as fallback value.
 6
 7        :rtype: Class name.
 8        """
 9        from .hosts.client import ClientHost
10        from .hosts.server import ServerHost
11
12        return {
13            "client": ClientHost,
14            "server": ServerHost,
15        }
16
17    @property
18    def role_to_role_class(self) -> dict[str, Type[MultihostRole]]:
19        """
20        Map role to role class. Asterisk ``*`` can be used as fallback value.
21
22        :rtype: Class name.
23        """
24        from .roles.client import ClientRole
25        from .roles.server import ServerRole
26
27        return {
28            "client": ClientRole,
29            "server": ServerRole,
30        }

Note

It may be required to import the types inside the methods to reduce their scope and avoid circular dependency since MultihostHost is a generic class that takes the domain class as a specific type.

Similar to the MultihostConfig class, it is also possible to add custom configuration options or further extend functionality by overriding the parent class methods. The configuration dictionary can be accessed by confdict, however it is recommended to place custom options under the config field which can be accessed directly through the config attribute. This way, it is possible to avoid name collisions if pytest-mh introduces new options in the future.

It is also possible to override or extend all public methods to further affect the behavior.

Basic example of custom configuration option
 1class MyProjectDomain(MultihostDomain[MyProjectConfig]):
 2    @property
 3    def required_fields(self) -> list[str]:
 4        """
 5        Fields that must be set in the host configuration. An error is raised
 6        if any field is missing.
 7
 8        The field name may contain a ``.`` to check nested fields.
 9        """
10        return super().required_fields + ["config.my_domain_required_option"]
11
12    @property
13    def my_domain_option(self) -> bool:
14        return self.config.get("my_domain_option", False)
15
16    @property
17    def my_domain_required_option(self) -> bool:
18        # This option is required and pytest will error if
19        # it is not present in the configuration
20        return self.config.get("my_domain_required_option")
21
22    @property
23    def role_to_host_class(self) -> dict[str, Type[MultihostHost]]:
24        """
25        Map role to host class. Asterisk ``*`` can be used as fallback value.
26
27        :rtype: Class name.
28        """
29        from .hosts.client import ClientHost
30        from .hosts.server import ServerHost
31
32        return {
33            "client": ClientHost,
34            "server": ServerHost,
35        }
36
37    @property
38    def role_to_role_class(self) -> dict[str, Type[MultihostRole]]:
39        """
40        Map role to role class. Asterisk ``*`` can be used as fallback value.
41
42        :rtype: Class name.
43        """
44        from .roles.client import ClientRole
45        from .roles.server import ServerRole
46
47        return {
48            "client": ClientRole,
49            "server": ServerRole,
50        }
1domains:
2- id: example
3  config:
4    my_domain_option: True
5    my_domain_required_option: True
6  hosts:
7  - hostname: client.test
8    role: client