From b82e6e068568ba9586d5fd19ede1d47f7b0bee25 Mon Sep 17 00:00:00 2001 From: Tanner Doshier Date: Sun, 4 Sep 2022 13:34:10 -0400 Subject: [PATCH] Fix SSHKeyPairDefinition The base `ResourceDefinition` class requires the `config` property's type annotation to not be a string (added cd9319be1cc / a70af271557), but the `ssh_keypair.py` module activates postponed annotations via the `from __future__ import annotations` syntax (added e48422a9b0d), which turns all type annotations in the module into strings[1], breaking the `SSHKeyPairDefinition` class when initialized. Thus any defined `resources.sshKeyPairs` break `nixops` commands, causing failures with the message: ``` TypeError: .config's type annotation is not allowed to be a string, see: https://nixops.readthedocs.io/en/latest/plugins/authoring.html ``` A number of possible workarounds for this, but the simplest would seem to just not activate PEP 563-style postponed annotations in `ssh_keypair.py`. [1] https://peps.python.org/pep-0563/ --- nixops/resources/__init__.py | 2 +- nixops/resources/ssh_keypair.py | 8 +++----- tests/functional/ssh-key-pair-resource.nix | 5 +++++ .../functional/test_ssh_key_pair_resource.py | 20 +++++++++++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 tests/functional/ssh-key-pair-resource.nix create mode 100644 tests/functional/test_ssh_key_pair_resource.py diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index f66f16c52..84cc1ced9 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -63,7 +63,7 @@ def __init__(self, name: str, config: ResourceEval): ) else: raise TypeError( - f"{self.__class__}.config's type annotation is not allowed to be a string, see: https://nixops.readthedocs.io/en/latest/plugins/authoring.html" + f"{self.__class__}.config's type annotation is not allowed to be a string (or defined in a module using PEP 563 postponed annotations), see: https://nixops.readthedocs.io/en/latest/plugins/authoring.html" ) if not issubclass(config_type, ResourceOptions): diff --git a/nixops/resources/ssh_keypair.py b/nixops/resources/ssh_keypair.py index f618996ed..52bf96d35 100644 --- a/nixops/resources/ssh_keypair.py +++ b/nixops/resources/ssh_keypair.py @@ -1,5 +1,3 @@ -from __future__ import annotations - # Automatic provisioning of SSH key pairs. from typing import Type, Dict, Optional @@ -14,11 +12,11 @@ class SSHKeyPairDefinition(nixops.resources.ResourceDefinition): config: nixops.resources.ResourceOptions @classmethod - def get_type(cls: Type[SSHKeyPairDefinition]) -> str: + def get_type(cls: Type["SSHKeyPairDefinition"]) -> str: return "ssh-keypair" @classmethod - def get_resource_type(cls: Type[SSHKeyPairDefinition]) -> str: + def get_resource_type(cls: Type["SSHKeyPairDefinition"]) -> str: return "sshKeyPairs" def __init__(self, name: str, config: nixops.resources.ResourceEval): @@ -38,7 +36,7 @@ class SSHKeyPairState(nixops.resources.ResourceState[SSHKeyPairDefinition]): private_key: Optional[str] = nixops.util.attr_property("privateKey", None) @classmethod - def get_type(cls: Type[SSHKeyPairState]) -> str: + def get_type(cls: Type["SSHKeyPairState"]) -> str: return "ssh-keypair" def __init__(self, depl: "nixops.deployment.Deployment", name: str, id: RecordId): diff --git a/tests/functional/ssh-key-pair-resource.nix b/tests/functional/ssh-key-pair-resource.nix new file mode 100644 index 000000000..238828bc5 --- /dev/null +++ b/tests/functional/ssh-key-pair-resource.nix @@ -0,0 +1,5 @@ +{ + network = {}; + + resources.sshKeyPairs.ssh-key = {}; +} diff --git a/tests/functional/test_ssh_key_pair_resource.py b/tests/functional/test_ssh_key_pair_resource.py new file mode 100644 index 000000000..b83661297 --- /dev/null +++ b/tests/functional/test_ssh_key_pair_resource.py @@ -0,0 +1,20 @@ +from os import path + +from tests.functional.generic_deployment_test import GenericDeploymentTest + +from nixops.evaluation import NetworkFile + +parent_dir = path.dirname(__file__) + +ssh_key_pair_spec = "%s/ssh-key-pair-resource.nix" % (parent_dir) + + +class TestSSHKeyPairResource(GenericDeploymentTest): + def setup(self): + super(TestSSHKeyPairResource, self).setup() + self.depl.network_expr = NetworkFile(ssh_key_pair_spec) + + def test_evaluate(self): + self.depl.evaluate() + + assert "ssh-key" in self.depl.definitions