Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/start-with-types' into start-wit…
Browse files Browse the repository at this point in the history
…h-types-merge
  • Loading branch information
grahamc committed Mar 13, 2020
2 parents b76dc58 + 595d9be commit 4387113
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 50 deletions.
51 changes: 26 additions & 25 deletions nixops/backends/__init__.py
Expand Up @@ -3,23 +3,22 @@
import os
import re
import subprocess
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Union, Set
import nixops.util
import nixops.resources
import nixops.ssh_util
import xml.etree.ElementTree as ET


class MachineDefinition(nixops.resources.ResourceDefinition):
"""Base class for NixOps machine definitions."""

def __init__(self, xml, config={}):
def __init__(self, xml, config={}) -> None:
nixops.resources.ResourceDefinition.__init__(self, xml, config)
self.encrypted_links_to = set(
[
e.get("value")
for e in xml.findall("attrs/attr[@name='encryptedLinksTo']/list/string")
]
)
self.encrypted_links_to: Set[str] = {
e.get("value")
for e in xml.findall("attrs/attr[@name='encryptedLinksTo']/list/string")
}
self.store_keys_on_machine = (
xml.find("attrs/attr[@name='storeKeysOnMachine']/bool").get("value")
== "true"
Expand All @@ -37,7 +36,7 @@ def __init__(self, xml, config={}):
== "true"
)

def _extract_key_options(x):
def _extract_key_options(x: ET.Element) -> Dict[str, str]:
opts = {}
for (key, xmlType) in (
("text", "string"),
Expand All @@ -49,7 +48,9 @@ def _extract_key_options(x):
):
elem = x.find("attrs/attr[@name='{0}']/{1}".format(key, xmlType))
if elem is not None:
opts[key] = elem.get("value")
value = elem.get("value")
if value is not None:
opts[key] = value
return opts

self.keys = {
Expand Down Expand Up @@ -90,7 +91,7 @@ class MachineState(nixops.resources.ResourceState):
# machine was created.
state_version: Optional[str] = nixops.util.attr_property("stateVersion", None, str)

def __init__(self, depl, name: str, id: int):
def __init__(self, depl, name: str, id: int) -> None:
nixops.resources.ResourceState.__init__(self, depl, name, id)
self._ssh_pinged_this_time = False
self.ssh = nixops.ssh_util.SSH(self.logger)
Expand All @@ -104,27 +105,27 @@ def prefix_definition(self, attr):
return attr

@property
def started(self):
def started(self) -> bool:
state = self.state
return state == self.STARTING or state == self.UP

def set_common_state(self, defn):
def set_common_state(self, defn) -> None:
self.store_keys_on_machine = defn.store_keys_on_machine
self.keys = defn.keys
self.ssh_port = defn.ssh_port
self.has_fast_connection = defn.has_fast_connection
if not self.has_fast_connection:
self.ssh.enable_compression()

def stop(self):
def stop(self) -> None:
"""Stop this machine, if possible."""
self.warn("don't know how to stop machine ‘{0}’".format(self.name))

def start(self):
def start(self) -> None:
"""Start this machine, if possible."""
pass

def get_load_avg(self):
def get_load_avg(self) -> Union[List[str], None]:
"""Get the load averages on the machine."""
try:
res = (
Expand All @@ -141,13 +142,13 @@ def get_load_avg(self):

# FIXME: Move this to ResourceState so that other kinds of
# resources can be checked.
def check(self):
def check(self): # TODO -> CheckResult, but supertype ResourceState -> True
"""Check machine state."""
res = CheckResult()
self._check(res)
return res

def _check(self, res):
def _check(self, res): # TODO -> None but supertype ResourceState -> True
avg = self.get_load_avg()
if avg == None:
if self.state == self.UP:
Expand Down Expand Up @@ -199,7 +200,7 @@ def _check(self, res):
continue
res.failed_units.append(match.group(1))

def restore(self, defn, backup_id, devices=[]):
def restore(self, defn, backup_id: Optional[str], devices: List[str] = []):
"""Restore persistent disks to a given backup, if possible."""
self.warn(
"don't know how to restore disks from backup for machine ‘{0}’".format(
Expand All @@ -223,7 +224,7 @@ def backup(self, defn, backup_id: str, devices: List[str] = []) -> None:
"don't know how to make backup of disks for machine ‘{0}’".format(self.name)
)

def reboot(self, hard=False):
def reboot(self, hard: bool = False) -> None:
"""Reboot this machine."""
self.log("rebooting...")
if self.state == self.RESCUE:
Expand All @@ -237,7 +238,7 @@ def reboot(self, hard=False):
self.state = self.STARTING
self.ssh.reset()

def reboot_sync(self, hard=False):
def reboot_sync(self, hard: bool = False) -> None:
"""Reboot this machine and wait until it's up again."""
self.reboot(hard=hard)
self.log_start("waiting for the machine to finish rebooting...")
Expand All @@ -257,13 +258,13 @@ def reboot_sync(self, hard=False):
self._ssh_pinged_this_time = True
self.send_keys()

def reboot_rescue(self, hard=False):
def reboot_rescue(self, hard: bool = False) -> None:
"""
Reboot machine into rescue system and wait until it is active.
"""
self.warn("machine ‘{0}’ doesn't have a rescue" " system.".format(self.name))

def send_keys(self):
def send_keys(self) -> None:
if self.state == self.RESCUE:
# Don't send keys when in RESCUE state, because we're most likely
# bootstrapping plus we probably don't have /run mounted properly
Expand Down Expand Up @@ -490,7 +491,7 @@ def get_console_output(self):


class CheckResult(object):
def __init__(self):
def __init__(self) -> None:
# Whether the resource exists.
self.exists = None

Expand All @@ -515,7 +516,7 @@ def __init__(self):
self.load = None

# Error messages.
self.messages = []
self.messages: List[str] = []

# FIXME: add a check whether the active NixOS config on the
# machine is correct.
14 changes: 8 additions & 6 deletions nixops/resources/__init__.py
Expand Up @@ -3,7 +3,7 @@
import re
import nixops.util
from threading import Event
from typing import List, Optional, Dict
from typing import List, Optional, Dict, Any
from nixops.state import StateDict
from nixops.diff import Diff, Handler

Expand Down Expand Up @@ -73,7 +73,7 @@ def __init__(self, depl, name: str, id):
self.logger = depl.logger.get_logger_for(name)
self.logger.register_index(self.index)

def _set_attrs(self, attrs):
def _set_attrs(self, attrs: Dict[str, Any]) -> None:
"""Update machine attributes in the state file."""
with self.depl._db:
c = self.depl._db.cursor()
Expand All @@ -89,19 +89,19 @@ def _set_attrs(self, attrs):
(self.id, n, v),
)

def _set_attr(self, name, value):
def _set_attr(self, name: str, value: Any) -> None:
"""Update one machine attribute in the state file."""
self._set_attrs({name: value})

def _del_attr(self, name):
def _del_attr(self, name: str) -> None:
"""Delete a machine attribute from the state file."""
with self.depl._db:
self.depl._db.execute(
"delete from ResourceAttrs where machine = ? and name = ?",
(self.id, name),
)

def _get_attr(self, name, default=nixops.util.undefined):
def _get_attr(self, name: str, default=nixops.util.undefined) -> Any:
"""Get a machine attribute from the state file."""
with self.depl._db:
c = self.depl._db.cursor()
Expand Down Expand Up @@ -201,7 +201,9 @@ def create(self, defn, check, allow_reboot, allow_recreate):
"""Create or update the resource defined by ‘defn’."""
raise NotImplementedError("create")

def check(self):
def check(
self,
): # TODO this return type is inconsistent with child class MachineState
"""
Reconcile the state file with the real world infrastructure state.
This should not do any provisionning but just sync the state.
Expand Down
42 changes: 23 additions & 19 deletions nixops/util.py
Expand Up @@ -16,7 +16,7 @@
import logging
import atexit
import re
from typing import Callable, List, Optional, Any, IO, Union, Mapping, TextIO
from typing import Callable, List, Optional, Any, IO, Union, Mapping, TextIO, Tuple

# the following ansi_ imports are for backwards compatability. They
# would belong fine in this util.py, but having them in util.py
Expand Down Expand Up @@ -51,7 +51,7 @@ def check_wait(


class CommandFailed(Exception):
def __init__(self, message: str, exitcode: int):
def __init__(self, message: str, exitcode: int) -> None:
self.message = message
self.exitcode = exitcode

Expand Down Expand Up @@ -202,7 +202,7 @@ def generate_random_string(length=256) -> str:
return base64.b64encode(s).decode()


def make_non_blocking(fd: IO[Any]):
def make_non_blocking(fd: IO[Any]) -> None:
fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)


Expand Down Expand Up @@ -243,7 +243,7 @@ def wait_for_tcp_port(
timeout: int = -1,
open: bool = True,
callback: Optional[Callable[[], Any]] = None,
):
) -> bool:
"""Wait until the specified TCP port is open or closed."""
n = 0
while True:
Expand All @@ -270,7 +270,7 @@ def _maybe_abspath(s: str) -> str:
return os.path.abspath(s)


def abs_nix_path(x):
def abs_nix_path(x: str) -> str:
xs = x.split("=", 1)
if len(xs) == 1:
return _maybe_abspath(x)
Expand Down Expand Up @@ -319,7 +319,9 @@ def set(self, x: Any) -> None:
return property(get, set)


def create_key_pair(key_name="NixOps auto-generated key", type="ed25519"):
def create_key_pair(
key_name="NixOps auto-generated key", type="ed25519"
) -> Tuple[str, str]:
key_dir = tempfile.mkdtemp(prefix="nixops-key-tmp")
res = subprocess.call(
["ssh-keygen", "-t", type, "-f", key_dir + "/key", "-N", "", "-C", key_name],
Expand All @@ -338,65 +340,67 @@ def create_key_pair(key_name="NixOps auto-generated key", type="ed25519"):


class SelfDeletingDir(str):
def __init__(self, s: str):
def __init__(self, s: str) -> None:
str.__init__(s)
atexit.register(self._delete)

def _delete(self):
def _delete(self) -> None:
shutil.rmtree(self)


class TeeStderr(StringIO):
stderr: TextIO

def __init__(self):
def __init__(self) -> None:
StringIO.__init__(self)
self.stderr = sys.stderr
self.logger = logging.getLogger("root")
sys.stderr = self

def __del__(self):
def __del__(self) -> None:
sys.stderr = self.stderr

def write(self, data):
self.stderr.write(data)
def write(self, data) -> int:
ret = self.stderr.write(data)
for l in data.split("\n"):
self.logger.warning(l)
return ret

def fileno(self) -> int:
return self.stderr.fileno()

def isatty(self) -> bool:
return self.stderr.isatty()

def flush(self):
def flush(self) -> None:
return self.stderr.flush()


class TeeStdout(StringIO):
stdout: TextIO

def __init__(self):
def __init__(self) -> None:
StringIO.__init__(self)
self.stdout = sys.stdout
self.logger = logging.getLogger("root")
sys.stdout = self

def __del__(self):
def __del__(self) -> None:
sys.stdout = self.stdout

def write(self, data):
self.stdout.write(data)
def write(self, data) -> int:
ret = self.stdout.write(data)
for l in data.split("\n"):
self.logger.info(l)
return ret

def fileno(self) -> int:
return self.stdout.fileno()

def isatty(self) -> bool:
return self.stdout.isatty()

def flush(self):
def flush(self) -> None:
return self.stdout.flush()


Expand Down Expand Up @@ -425,7 +429,7 @@ def enum(**enums):
return type("Enum", (), enums)


def write_file(path: str, contents: str):
def write_file(path: str, contents: str) -> None:
f = open(path, "w")
f.write(contents)
f.close()
Expand Down

0 comments on commit 4387113

Please sign in to comment.