Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixops
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b743ad96dcf8
Choose a base ref
...
head repository: NixOS/nixops
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9dd426aedbee
Choose a head ref
  • 6 commits
  • 6 files changed
  • 1 contributor

Commits on Jul 7, 2020

  1. Make get_typed_resource mypy checkable

    By taking a type argument and infering return type from that value
    adisbladis committed Jul 7, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    34e62c5 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    99eb7b6 View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    5818a18 View commit details
  4. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    88494fb View commit details
  5. Fix deadlock in resource destruction

    `_wait_for: List["ResourceState"] = []` Results in every instance
    sharing the same list, causing a resource to wait for itself before destruction.
    adisbladis committed Jul 7, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    ffd2712 View commit details
  6. Merge pull request #1355 from adisbladis/nixops-aws-compat

    Nixops aws compat
    adisbladis authored Jul 7, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9dd426a View commit details
Showing with 63 additions and 10 deletions.
  1. +26 −5 nixops/deployment.py
  2. +1 −1 nixops/diff.py
  3. +12 −1 nixops/resources/__init__.py
  4. +13 −0 nixops/util.py
  5. +4 −3 tests/functional/vpc.py
  6. +7 −0 tests/unit/test_util.py
31 changes: 26 additions & 5 deletions nixops/deployment.py
Original file line number Diff line number Diff line change
@@ -33,6 +33,8 @@
Tuple,
Union,
cast,
TypeVar,
Type,
)
import nixops.backends
import nixops.logger
@@ -55,6 +57,9 @@ class UnknownBackend(Exception):
DEBUG = False


TypedResource = TypeVar("TypedResource")


class Deployment:
"""NixOps top-level deployment manager."""

@@ -164,17 +169,33 @@ def active_machines(
def active_resources(self) -> Dict[str, nixops.resources.GenericResourceState]:
return {n: r for n, r in self.resources.items() if not r.obsolete}

def get_typed_resource(
self, name: str, type: str
def get_generic_resource(
self, name: str, type_name: str
) -> nixops.resources.GenericResourceState:
res = self.active_resources.get(name, None)
if not res:
raise Exception("resource ‘{0}’ does not exist".format(name))
if res.get_type() != type:
raise Exception("resource ‘{0}’ is not of type ‘{1}’".format(name, type))
if res.get_type() != type_name:
raise Exception(
"resource ‘{0}’ is not of type ‘{1}’".format(name, type_name)
)
return res

def get_machine(self, name: str) -> nixops.resources.GenericResourceState:
def get_typed_resource(
self, name: str, type_name: str, type: Type[TypedResource]
) -> TypedResource:
res = self.get_generic_resource(name, type_name)
if not isinstance(res, type):
raise ValueError(f"{res} not of type {type}")
return res

def get_machine(self, name: str, type: Type[TypedResource]) -> TypedResource:
m = self.get_generic_machine(name)
if not isinstance(m, type):
raise ValueError(f"{m} not of type {type}")
return m

def get_generic_machine(self, name: str) -> nixops.resources.GenericResourceState:
res = self.active_resources.get(name, None)
if not res:
raise Exception("machine ‘{0}’ does not exist".format(name))
2 changes: 1 addition & 1 deletion nixops/diff.py
Original file line number Diff line number Diff line change
@@ -188,7 +188,7 @@ def retrieve_def(d):
name = d[4:].split(".")[0]
res_type = d.split(".")[1]
k = d.split(".")[2] if len(d.split(".")) > 2 else key
res = self._depl.get_typed_resource(name, res_type)
res = self._depl.get_generic_resource(name, res_type)
if res.state != res.UP:
return "computed"
try:
13 changes: 12 additions & 1 deletion nixops/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
from nixops.logger import MachineLogger
from typing_extensions import Literal


if TYPE_CHECKING:
import nixops.deployment

@@ -103,13 +102,24 @@ def get_type(cls) -> str:
_created_event: Optional[Event] = None
_destroyed_event: Optional[Event] = None
_errored: Optional[bool] = None

# While this looks like a rookie mistake where the list is going get shared
# across all class instances it's not... It's working around a Mypy crash.
#
# We're overriding this value in __init__.
# It's safe despite there being a shared list on the class level
_wait_for: List["ResourceState"] = []

depl: nixops.deployment.Deployment
id: RecordId
logger: MachineLogger

def __init__(self, depl: nixops.deployment.Deployment, name: str, id: RecordId):
# Override default class-level list.
# Previously this behaviour was missing and the _wait_for list was shared across all instances
# of ResourceState, resulting in a deadlock in resource destruction as they resource being
# destroyed had a reference to itself in the _wait_for list.
self._wait_for = []
self.depl = depl
self.name = name
self.id = id
@@ -308,6 +318,7 @@ def next_charge_time(self):

class DiffEngineResourceState(ResourceState):
_reserved_keys: List[str] = []
_state: StateDict

def __init__(self, depl, name, id):
nixops.resources.ResourceState.__init__(self, depl, name, id)
13 changes: 13 additions & 0 deletions nixops/util.py
Original file line number Diff line number Diff line change
@@ -152,6 +152,19 @@ def _transform_value(key: Any, value: Any) -> Any:
if inspect.isclass(ann) and issubclass(ann, ImmutableValidatedObject):
value = ann(**value)

# Support Sequence[ImmutableValidatedObject]
if isinstance(value, tuple) and not isinstance(ann, str):
new_value = []
for v in value:
for subann in ann.__args__:
if inspect.isclass(subann) and issubclass(
subann, ImmutableValidatedObject
):
new_value.append(subann(**v))
else:
new_value.append(v)
value = tuple(new_value)

typeguard.check_type(key, value, ann)

return value
7 changes: 4 additions & 3 deletions tests/functional/vpc.py
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
from nixops.nix_expr import RawValue, Function, Call, py2nix
import nixops.util
from tests.functional import generic_deployment_test
from typing import Any

parent_dir = path.dirname(__file__)

@@ -24,7 +25,7 @@ def setup(self):

def test_deploy_vpc(self):
self.depl.deploy()
vpc_resource = self.depl.get_typed_resource("vpc-test", "vpc")
vpc_resource = self.depl.get_generic_resource("vpc-test", "vpc")
vpc = vpc_resource.get_client().describe_vpcs(
VpcIds=[vpc_resource._state["vpcId"]]
)
@@ -45,7 +46,7 @@ def test_enable_ipv6(self):
self.compose_expressions([CFG_IPV6])
self.depl.deploy(plan_only=True)
self.depl.deploy()
vpc_resource = self.depl.get_typed_resource("vpc-test", "vpc")
vpc_resource = self.depl.get_generic_resource("vpc-test", "vpc")
vpc = vpc_resource.get_client().describe_vpcs(
VpcIds=[vpc_resource._state["vpcId"]]
)
@@ -62,7 +63,7 @@ def test_deploy_subnets(self):
self.compose_expressions([CFG_SUBNET])
self.depl.deploy(plan_only=True)
self.depl.deploy()
subnet_resource = self.depl.get_typed_resource("subnet-test", "vpc-subnet")
subnet_resource = self.depl.get_generic_resource("subnet-test", "vpc-subnet")
subnet = subnet_resource.get_client().describe_subnets(
SubnetIds=[subnet_resource._state["subnetId"]]
)
7 changes: 7 additions & 0 deletions tests/unit/test_util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import Sequence
import json
from nixops.logger import Logger
from io import StringIO
@@ -108,3 +109,9 @@ class B(A):
b = B(a, y=1)
self.assertEqual(a.x, b.x)
self.assertEqual(b.x, 1)

# Test Sequence[ImmutableValidatedObject]
class WithSequence(util.ImmutableValidatedObject):
subs: Sequence[SubResource]

WithSequence(subs=[SubResource(x=1), SubResource(x=2)])