updates for typing functions on top level modules
This commit is contained in:
parent
ab3659183e
commit
4e71759ac9
5 changed files with 209 additions and 133 deletions
|
@ -134,7 +134,7 @@ def create_nodes(
|
||||||
|
|
||||||
def create_links(
|
def create_links(
|
||||||
session: Session, link_protos: List[core_pb2.Link]
|
session: Session, link_protos: List[core_pb2.Link]
|
||||||
) -> Tuple[List[NodeBase], List[Type[Exception]]]:
|
) -> Tuple[List[NodeBase], List[Exception]]:
|
||||||
"""
|
"""
|
||||||
Create links using a thread pool and wait for completion.
|
Create links using a thread pool and wait for completion.
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,111 @@ Common support for configurable CORE objects.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from typing import TYPE_CHECKING, Dict, List, Tuple, Type, Union
|
||||||
|
|
||||||
|
from core.emane.nodes import EmaneNet
|
||||||
from core.emulator.data import ConfigData
|
from core.emulator.data import ConfigData
|
||||||
|
from core.emulator.enumerations import ConfigDataTypes
|
||||||
|
from core.nodes.network import WlanNode
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.location.mobility import WirelessModel
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigGroup:
|
||||||
|
"""
|
||||||
|
Defines configuration group tabs used for display by ConfigurationOptions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name: str, start: int, stop: int) -> None:
|
||||||
|
"""
|
||||||
|
Creates a ConfigGroup object.
|
||||||
|
|
||||||
|
:param str name: configuration group display name
|
||||||
|
:param int start: configurations start index for this group
|
||||||
|
:param int stop: configurations stop index for this group
|
||||||
|
"""
|
||||||
|
self.name = name
|
||||||
|
self.start = start
|
||||||
|
self.stop = stop
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration:
|
||||||
|
"""
|
||||||
|
Represents a configuration options.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
_id: str,
|
||||||
|
_type: ConfigDataTypes,
|
||||||
|
label: str = None,
|
||||||
|
default: str = "",
|
||||||
|
options: List[str] = None,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Creates a Configuration object.
|
||||||
|
|
||||||
|
:param str _id: unique name for configuration
|
||||||
|
:param core.enumerations.ConfigDataTypes _type: configuration data type
|
||||||
|
:param str label: configuration label for display
|
||||||
|
:param str default: default value for configuration
|
||||||
|
:param list options: list options if this is a configuration with a combobox
|
||||||
|
"""
|
||||||
|
self.id = _id
|
||||||
|
self.type = _type
|
||||||
|
self.default = default
|
||||||
|
if not options:
|
||||||
|
options = []
|
||||||
|
self.options = options
|
||||||
|
if not label:
|
||||||
|
label = _id
|
||||||
|
self.label = label
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.__class__.__name__}(id={self.id}, type={self.type}, default={self.default}, options={self.options})"
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurableOptions:
|
||||||
|
"""
|
||||||
|
Provides a base for defining configuration options within CORE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = None
|
||||||
|
bitmap = None
|
||||||
|
options = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def configurations(cls) -> List[Configuration]:
|
||||||
|
"""
|
||||||
|
Provides the configurations for this class.
|
||||||
|
|
||||||
|
:return: configurations
|
||||||
|
:rtype: list[Configuration]
|
||||||
|
"""
|
||||||
|
return cls.options
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_groups(cls) -> List[ConfigGroup]:
|
||||||
|
"""
|
||||||
|
Defines how configurations are grouped.
|
||||||
|
|
||||||
|
:return: configuration group definition
|
||||||
|
:rtype: list[ConfigGroup]
|
||||||
|
"""
|
||||||
|
return [ConfigGroup("Options", 1, len(cls.configurations()))]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_values(cls) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Provides an ordered mapping of configuration keys to default values.
|
||||||
|
|
||||||
|
:return: ordered configuration mapping default values
|
||||||
|
:rtype: OrderedDict
|
||||||
|
"""
|
||||||
|
return OrderedDict(
|
||||||
|
[(config.id, config.default) for config in cls.configurations()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConfigShim:
|
class ConfigShim:
|
||||||
|
@ -14,7 +117,7 @@ class ConfigShim:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def str_to_dict(cls, key_values):
|
def str_to_dict(cls, key_values: str) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Converts a TLV key/value string into an ordered mapping.
|
Converts a TLV key/value string into an ordered mapping.
|
||||||
|
|
||||||
|
@ -30,7 +133,7 @@ class ConfigShim:
|
||||||
return values
|
return values
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def groups_to_str(cls, config_groups):
|
def groups_to_str(cls, config_groups: List[ConfigGroup]) -> str:
|
||||||
"""
|
"""
|
||||||
Converts configuration groups to a TLV formatted string.
|
Converts configuration groups to a TLV formatted string.
|
||||||
|
|
||||||
|
@ -47,7 +150,14 @@ class ConfigShim:
|
||||||
return "|".join(group_strings)
|
return "|".join(group_strings)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def config_data(cls, flags, node_id, type_flags, configurable_options, config):
|
def config_data(
|
||||||
|
cls,
|
||||||
|
flags: int,
|
||||||
|
node_id: int,
|
||||||
|
type_flags: int,
|
||||||
|
configurable_options: ConfigurableOptions,
|
||||||
|
config: Dict[str, str],
|
||||||
|
) -> ConfigData:
|
||||||
"""
|
"""
|
||||||
Convert this class to a Config API message. Some TLVs are defined
|
Convert this class to a Config API message. Some TLVs are defined
|
||||||
by the class, but node number, conf type flags, and values must
|
by the class, but node number, conf type flags, and values must
|
||||||
|
@ -102,50 +212,22 @@ class ConfigShim:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Configuration:
|
|
||||||
"""
|
|
||||||
Represents a configuration options.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, _id, _type, label=None, default="", options=None):
|
|
||||||
"""
|
|
||||||
Creates a Configuration object.
|
|
||||||
|
|
||||||
:param str _id: unique name for configuration
|
|
||||||
:param core.enumerations.ConfigDataTypes _type: configuration data type
|
|
||||||
:param str label: configuration label for display
|
|
||||||
:param str default: default value for configuration
|
|
||||||
:param list options: list options if this is a configuration with a combobox
|
|
||||||
"""
|
|
||||||
self.id = _id
|
|
||||||
self.type = _type
|
|
||||||
self.default = default
|
|
||||||
if not options:
|
|
||||||
options = []
|
|
||||||
self.options = options
|
|
||||||
if not label:
|
|
||||||
label = _id
|
|
||||||
self.label = label
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.__class__.__name__}(id={self.id}, type={self.type}, default={self.default}, options={self.options})"
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurableManager:
|
class ConfigurableManager:
|
||||||
"""
|
"""
|
||||||
Provides convenience methods for storing and retrieving configuration options for nodes.
|
Provides convenience methods for storing and retrieving configuration options for
|
||||||
|
nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_default_node = -1
|
_default_node = -1
|
||||||
_default_type = _default_node
|
_default_type = _default_node
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
"""
|
"""
|
||||||
Creates a ConfigurableManager object.
|
Creates a ConfigurableManager object.
|
||||||
"""
|
"""
|
||||||
self.node_configurations = {}
|
self.node_configurations = {}
|
||||||
|
|
||||||
def nodes(self):
|
def nodes(self) -> List[int]:
|
||||||
"""
|
"""
|
||||||
Retrieves the ids of all node configurations known by this manager.
|
Retrieves the ids of all node configurations known by this manager.
|
||||||
|
|
||||||
|
@ -154,7 +236,7 @@ class ConfigurableManager:
|
||||||
"""
|
"""
|
||||||
return [x for x in self.node_configurations if x != self._default_node]
|
return [x for x in self.node_configurations if x != self._default_node]
|
||||||
|
|
||||||
def config_reset(self, node_id=None):
|
def config_reset(self, node_id: int = None) -> None:
|
||||||
"""
|
"""
|
||||||
Clears all configurations or configuration for a specific node.
|
Clears all configurations or configuration for a specific node.
|
||||||
|
|
||||||
|
@ -166,7 +248,13 @@ class ConfigurableManager:
|
||||||
elif node_id in self.node_configurations:
|
elif node_id in self.node_configurations:
|
||||||
self.node_configurations.pop(node_id)
|
self.node_configurations.pop(node_id)
|
||||||
|
|
||||||
def set_config(self, _id, value, node_id=_default_node, config_type=_default_type):
|
def set_config(
|
||||||
|
self,
|
||||||
|
_id: str,
|
||||||
|
value: str,
|
||||||
|
node_id: int = _default_node,
|
||||||
|
config_type: str = _default_type,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Set a specific configuration value for a node and configuration type.
|
Set a specific configuration value for a node and configuration type.
|
||||||
|
|
||||||
|
@ -180,7 +268,12 @@ class ConfigurableManager:
|
||||||
node_type_configs = node_configs.setdefault(config_type, OrderedDict())
|
node_type_configs = node_configs.setdefault(config_type, OrderedDict())
|
||||||
node_type_configs[_id] = value
|
node_type_configs[_id] = value
|
||||||
|
|
||||||
def set_configs(self, config, node_id=_default_node, config_type=_default_type):
|
def set_configs(
|
||||||
|
self,
|
||||||
|
config: Dict[str, str],
|
||||||
|
node_id: int = _default_node,
|
||||||
|
config_type: str = _default_type,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Set configurations for a node and configuration type.
|
Set configurations for a node and configuration type.
|
||||||
|
|
||||||
|
@ -196,8 +289,12 @@ class ConfigurableManager:
|
||||||
node_configs[config_type] = config
|
node_configs[config_type] = config
|
||||||
|
|
||||||
def get_config(
|
def get_config(
|
||||||
self, _id, node_id=_default_node, config_type=_default_type, default=None
|
self,
|
||||||
):
|
_id: str,
|
||||||
|
node_id: int = _default_node,
|
||||||
|
config_type: str = _default_type,
|
||||||
|
default: str = None,
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Retrieves a specific configuration for a node and configuration type.
|
Retrieves a specific configuration for a node and configuration type.
|
||||||
|
|
||||||
|
@ -214,7 +311,9 @@ class ConfigurableManager:
|
||||||
result = node_type_configs.get(_id, default)
|
result = node_type_configs.get(_id, default)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_configs(self, node_id=_default_node, config_type=_default_type):
|
def get_configs(
|
||||||
|
self, node_id: int = _default_node, config_type: str = _default_type
|
||||||
|
) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Retrieve configurations for a node and configuration type.
|
Retrieve configurations for a node and configuration type.
|
||||||
|
|
||||||
|
@ -229,7 +328,7 @@ class ConfigurableManager:
|
||||||
result = node_configs.get(config_type)
|
result = node_configs.get(config_type)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_all_configs(self, node_id=_default_node):
|
def get_all_configs(self, node_id: int = _default_node) -> List[Dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
Retrieve all current configuration types for a node.
|
Retrieve all current configuration types for a node.
|
||||||
|
|
||||||
|
@ -240,72 +339,12 @@ class ConfigurableManager:
|
||||||
return self.node_configurations.get(node_id)
|
return self.node_configurations.get(node_id)
|
||||||
|
|
||||||
|
|
||||||
class ConfigGroup:
|
|
||||||
"""
|
|
||||||
Defines configuration group tabs used for display by ConfigurationOptions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, name, start, stop):
|
|
||||||
"""
|
|
||||||
Creates a ConfigGroup object.
|
|
||||||
|
|
||||||
:param str name: configuration group display name
|
|
||||||
:param int start: configurations start index for this group
|
|
||||||
:param int stop: configurations stop index for this group
|
|
||||||
"""
|
|
||||||
self.name = name
|
|
||||||
self.start = start
|
|
||||||
self.stop = stop
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurableOptions:
|
|
||||||
"""
|
|
||||||
Provides a base for defining configuration options within CORE.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name = None
|
|
||||||
bitmap = None
|
|
||||||
options = []
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def configurations(cls):
|
|
||||||
"""
|
|
||||||
Provides the configurations for this class.
|
|
||||||
|
|
||||||
:return: configurations
|
|
||||||
:rtype: list[Configuration]
|
|
||||||
"""
|
|
||||||
return cls.options
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def config_groups(cls):
|
|
||||||
"""
|
|
||||||
Defines how configurations are grouped.
|
|
||||||
|
|
||||||
:return: configuration group definition
|
|
||||||
:rtype: list[ConfigGroup]
|
|
||||||
"""
|
|
||||||
return [ConfigGroup("Options", 1, len(cls.configurations()))]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default_values(cls):
|
|
||||||
"""
|
|
||||||
Provides an ordered mapping of configuration keys to default values.
|
|
||||||
|
|
||||||
:return: ordered configuration mapping default values
|
|
||||||
:rtype: OrderedDict
|
|
||||||
"""
|
|
||||||
return OrderedDict(
|
|
||||||
[(config.id, config.default) for config in cls.configurations()]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ModelManager(ConfigurableManager):
|
class ModelManager(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Helps handle setting models for nodes and managing their model configurations.
|
Helps handle setting models for nodes and managing their model configurations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
"""
|
"""
|
||||||
Creates a ModelManager object.
|
Creates a ModelManager object.
|
||||||
"""
|
"""
|
||||||
|
@ -313,7 +352,9 @@ class ModelManager(ConfigurableManager):
|
||||||
self.models = {}
|
self.models = {}
|
||||||
self.node_models = {}
|
self.node_models = {}
|
||||||
|
|
||||||
def set_model_config(self, node_id, model_name, config=None):
|
def set_model_config(
|
||||||
|
self, node_id: int, model_name: str, config: Dict[str, str] = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Set configuration data for a model.
|
Set configuration data for a model.
|
||||||
|
|
||||||
|
@ -341,7 +382,7 @@ class ModelManager(ConfigurableManager):
|
||||||
# set configuration
|
# set configuration
|
||||||
self.set_configs(model_config, node_id=node_id, config_type=model_name)
|
self.set_configs(model_config, node_id=node_id, config_type=model_name)
|
||||||
|
|
||||||
def get_model_config(self, node_id, model_name):
|
def get_model_config(self, node_id: int, model_name: str) -> Dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Retrieve configuration data for a model.
|
Retrieve configuration data for a model.
|
||||||
|
|
||||||
|
@ -363,7 +404,12 @@ class ModelManager(ConfigurableManager):
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def set_model(self, node, model_class, config=None):
|
def set_model(
|
||||||
|
self,
|
||||||
|
node: Union[WlanNode, EmaneNet],
|
||||||
|
model_class: "WirelessModel",
|
||||||
|
config: Dict[str, str] = None,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Set model and model configuration for node.
|
Set model and model configuration for node.
|
||||||
|
|
||||||
|
@ -379,7 +425,9 @@ class ModelManager(ConfigurableManager):
|
||||||
config = self.get_model_config(node.id, model_class.name)
|
config = self.get_model_config(node.id, model_class.name)
|
||||||
node.setmodel(model_class, config)
|
node.setmodel(model_class, config)
|
||||||
|
|
||||||
def get_models(self, node):
|
def get_models(
|
||||||
|
self, node: Union[WlanNode, EmaneNet]
|
||||||
|
) -> List[Tuple[Type, Dict[str, str]]]:
|
||||||
"""
|
"""
|
||||||
Return a list of model classes and values for a net if one has been
|
Return a list of model classes and values for a net if one has been
|
||||||
configured. This is invoked when exporting a session to XML.
|
configured. This is invoked when exporting a session to XML.
|
||||||
|
|
|
@ -1611,14 +1611,14 @@ class Session:
|
||||||
self.add_remove_control_interface(node=node, remove=False)
|
self.add_remove_control_interface(node=node, remove=False)
|
||||||
self.services.boot_services(node)
|
self.services.boot_services(node)
|
||||||
|
|
||||||
def boot_nodes(self) -> List[ServiceBootError]:
|
def boot_nodes(self) -> List[Exception]:
|
||||||
"""
|
"""
|
||||||
Invoke the boot() procedure for all nodes and send back node
|
Invoke the boot() procedure for all nodes and send back node
|
||||||
messages to the GUI for node messages that had the status
|
messages to the GUI for node messages that had the status
|
||||||
request flag.
|
request flag.
|
||||||
|
|
||||||
:return: service boot exceptions
|
:return: service boot exceptions
|
||||||
:rtype: list[core.services.coreservices.ServiceBootError]
|
:rtype: list[Exception]
|
||||||
"""
|
"""
|
||||||
with self._nodes_lock:
|
with self._nodes_lock:
|
||||||
funcs = []
|
funcs = []
|
||||||
|
|
|
@ -9,7 +9,7 @@ class CoreCommandError(subprocess.CalledProcessError):
|
||||||
Used when encountering internal CORE command errors.
|
Used when encountering internal CORE command errors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"Command({self.cmd}), Status({self.returncode}):\n"
|
f"Command({self.cmd}), Status({self.returncode}):\n"
|
||||||
f"stdout: {self.output}\nstderr: {self.stderr}"
|
f"stdout: {self.output}\nstderr: {self.stderr}"
|
||||||
|
|
|
@ -15,15 +15,33 @@ import random
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
from subprocess import PIPE, STDOUT, Popen
|
from subprocess import PIPE, STDOUT, Popen
|
||||||
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
Type,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from core.errors import CoreCommandError, CoreError
|
from core.errors import CoreCommandError, CoreError
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from core.emulator.session import Session
|
||||||
|
from core.nodes.base import CoreNode
|
||||||
|
|
||||||
DEVNULL = open(os.devnull, "wb")
|
DEVNULL = open(os.devnull, "wb")
|
||||||
|
|
||||||
|
|
||||||
def execute_file(path, exec_globals=None, exec_locals=None):
|
def execute_file(
|
||||||
|
path: str, exec_globals: Dict[str, str] = None, exec_locals: Dict[str, str] = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Provides an alternative way to run execfile to be compatible for
|
Provides an alternative way to run execfile to be compatible for
|
||||||
both python2/3.
|
both python2/3.
|
||||||
|
@ -41,7 +59,7 @@ def execute_file(path, exec_globals=None, exec_locals=None):
|
||||||
exec(data, exec_globals, exec_locals)
|
exec(data, exec_globals, exec_locals)
|
||||||
|
|
||||||
|
|
||||||
def hashkey(value):
|
def hashkey(value: Union[str, int]) -> int:
|
||||||
"""
|
"""
|
||||||
Provide a consistent hash that can be used in place
|
Provide a consistent hash that can be used in place
|
||||||
of the builtin hash, that no longer behaves consistently
|
of the builtin hash, that no longer behaves consistently
|
||||||
|
@ -57,7 +75,7 @@ def hashkey(value):
|
||||||
return int(hashlib.sha256(value).hexdigest(), 16)
|
return int(hashlib.sha256(value).hexdigest(), 16)
|
||||||
|
|
||||||
|
|
||||||
def _detach_init():
|
def _detach_init() -> None:
|
||||||
"""
|
"""
|
||||||
Fork a child process and exit.
|
Fork a child process and exit.
|
||||||
|
|
||||||
|
@ -69,7 +87,7 @@ def _detach_init():
|
||||||
os.setsid()
|
os.setsid()
|
||||||
|
|
||||||
|
|
||||||
def _valid_module(path, file_name):
|
def _valid_module(path: str, file_name: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if file is a valid python module.
|
Check if file is a valid python module.
|
||||||
|
|
||||||
|
@ -91,7 +109,7 @@ def _valid_module(path, file_name):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _is_class(module, member, clazz):
|
def _is_class(module: Any, member: Type, clazz: Type) -> bool:
|
||||||
"""
|
"""
|
||||||
Validates if a module member is a class and an instance of a CoreService.
|
Validates if a module member is a class and an instance of a CoreService.
|
||||||
|
|
||||||
|
@ -113,7 +131,7 @@ def _is_class(module, member, clazz):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def close_onexec(fd):
|
def close_onexec(fd: int) -> None:
|
||||||
"""
|
"""
|
||||||
Close on execution of a shell process.
|
Close on execution of a shell process.
|
||||||
|
|
||||||
|
@ -124,7 +142,7 @@ def close_onexec(fd):
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFD, fdflags | fcntl.FD_CLOEXEC)
|
fcntl.fcntl(fd, fcntl.F_SETFD, fdflags | fcntl.FD_CLOEXEC)
|
||||||
|
|
||||||
|
|
||||||
def which(command, required):
|
def which(command: str, required: bool) -> str:
|
||||||
"""
|
"""
|
||||||
Find location of desired executable within current PATH.
|
Find location of desired executable within current PATH.
|
||||||
|
|
||||||
|
@ -146,7 +164,7 @@ def which(command, required):
|
||||||
return found_path
|
return found_path
|
||||||
|
|
||||||
|
|
||||||
def make_tuple(obj):
|
def make_tuple(obj: Any) -> Tuple[Any]:
|
||||||
"""
|
"""
|
||||||
Create a tuple from an object, or return the object itself.
|
Create a tuple from an object, or return the object itself.
|
||||||
|
|
||||||
|
@ -160,7 +178,7 @@ def make_tuple(obj):
|
||||||
return (obj,)
|
return (obj,)
|
||||||
|
|
||||||
|
|
||||||
def make_tuple_fromstr(s, value_type):
|
def make_tuple_fromstr(s: str, value_type: Callable) -> Tuple[Any]:
|
||||||
"""
|
"""
|
||||||
Create a tuple from a string.
|
Create a tuple from a string.
|
||||||
|
|
||||||
|
@ -179,7 +197,7 @@ def make_tuple_fromstr(s, value_type):
|
||||||
return tuple(value_type(i) for i in values)
|
return tuple(value_type(i) for i in values)
|
||||||
|
|
||||||
|
|
||||||
def mute_detach(args, **kwargs):
|
def mute_detach(args: List[str], **kwargs: Dict[str, Any]) -> int:
|
||||||
"""
|
"""
|
||||||
Run a muted detached process by forking it.
|
Run a muted detached process by forking it.
|
||||||
|
|
||||||
|
@ -195,7 +213,13 @@ def mute_detach(args, **kwargs):
|
||||||
return Popen(args, **kwargs).pid
|
return Popen(args, **kwargs).pid
|
||||||
|
|
||||||
|
|
||||||
def cmd(args, env=None, cwd=None, wait=True, shell=False):
|
def cmd(
|
||||||
|
args: str,
|
||||||
|
env: Dict[str, str] = None,
|
||||||
|
cwd: str = None,
|
||||||
|
wait: bool = True,
|
||||||
|
shell: bool = False,
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Execute a command on the host and return a tuple containing the exit status and
|
Execute a command on the host and return a tuple containing the exit status and
|
||||||
result string. stderr output is folded into the stdout result string.
|
result string. stderr output is folded into the stdout result string.
|
||||||
|
@ -227,7 +251,7 @@ def cmd(args, env=None, cwd=None, wait=True, shell=False):
|
||||||
raise CoreCommandError(-1, args)
|
raise CoreCommandError(-1, args)
|
||||||
|
|
||||||
|
|
||||||
def file_munge(pathname, header, text):
|
def file_munge(pathname: str, header: str, text: str) -> None:
|
||||||
"""
|
"""
|
||||||
Insert text at the end of a file, surrounded by header comments.
|
Insert text at the end of a file, surrounded by header comments.
|
||||||
|
|
||||||
|
@ -245,7 +269,7 @@ def file_munge(pathname, header, text):
|
||||||
append_file.write(f"# END {header}\n")
|
append_file.write(f"# END {header}\n")
|
||||||
|
|
||||||
|
|
||||||
def file_demunge(pathname, header):
|
def file_demunge(pathname: str, header: str) -> None:
|
||||||
"""
|
"""
|
||||||
Remove text that was inserted in a file surrounded by header comments.
|
Remove text that was inserted in a file surrounded by header comments.
|
||||||
|
|
||||||
|
@ -273,7 +297,9 @@ def file_demunge(pathname, header):
|
||||||
write_file.write("".join(lines))
|
write_file.write("".join(lines))
|
||||||
|
|
||||||
|
|
||||||
def expand_corepath(pathname, session=None, node=None):
|
def expand_corepath(
|
||||||
|
pathname: str, session: "Session" = None, node: "CoreNode" = None
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Expand a file path given session information.
|
Expand a file path given session information.
|
||||||
|
|
||||||
|
@ -296,7 +322,7 @@ def expand_corepath(pathname, session=None, node=None):
|
||||||
return pathname
|
return pathname
|
||||||
|
|
||||||
|
|
||||||
def sysctl_devname(devname):
|
def sysctl_devname(devname: str) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Translate a device name to the name used with sysctl.
|
Translate a device name to the name used with sysctl.
|
||||||
|
|
||||||
|
@ -309,7 +335,7 @@ def sysctl_devname(devname):
|
||||||
return devname.replace(".", "/")
|
return devname.replace(".", "/")
|
||||||
|
|
||||||
|
|
||||||
def load_config(filename, d):
|
def load_config(filename: str, d: Dict[str, str]) -> None:
|
||||||
"""
|
"""
|
||||||
Read key=value pairs from a file, into a dict. Skip comments; strip newline
|
Read key=value pairs from a file, into a dict. Skip comments; strip newline
|
||||||
characters and spacing.
|
characters and spacing.
|
||||||
|
@ -332,7 +358,7 @@ def load_config(filename, d):
|
||||||
logging.exception("error reading file to dict: %s", filename)
|
logging.exception("error reading file to dict: %s", filename)
|
||||||
|
|
||||||
|
|
||||||
def load_classes(path, clazz):
|
def load_classes(path: str, clazz: Type) -> List[Type]:
|
||||||
"""
|
"""
|
||||||
Dynamically load classes for use within CORE.
|
Dynamically load classes for use within CORE.
|
||||||
|
|
||||||
|
@ -375,7 +401,7 @@ def load_classes(path, clazz):
|
||||||
return classes
|
return classes
|
||||||
|
|
||||||
|
|
||||||
def load_logging_config(config_path):
|
def load_logging_config(config_path: str) -> None:
|
||||||
"""
|
"""
|
||||||
Load CORE logging configuration file.
|
Load CORE logging configuration file.
|
||||||
|
|
||||||
|
@ -387,7 +413,9 @@ def load_logging_config(config_path):
|
||||||
logging.config.dictConfig(log_config)
|
logging.config.dictConfig(log_config)
|
||||||
|
|
||||||
|
|
||||||
def threadpool(funcs, workers=10):
|
def threadpool(
|
||||||
|
funcs: List[Tuple[Callable, Iterable[Any], Dict[Any, Any]]], workers: int = 10
|
||||||
|
) -> Tuple[List[Any], List[Exception]]:
|
||||||
"""
|
"""
|
||||||
Run provided functions, arguments, and keywords within a threadpool
|
Run provided functions, arguments, and keywords within a threadpool
|
||||||
collecting results and exceptions.
|
collecting results and exceptions.
|
||||||
|
@ -413,7 +441,7 @@ def threadpool(funcs, workers=10):
|
||||||
return results, exceptions
|
return results, exceptions
|
||||||
|
|
||||||
|
|
||||||
def random_mac():
|
def random_mac() -> str:
|
||||||
"""
|
"""
|
||||||
Create a random mac address using Xen OID 00:16:3E.
|
Create a random mac address using Xen OID 00:16:3E.
|
||||||
|
|
||||||
|
@ -427,7 +455,7 @@ def random_mac():
|
||||||
return str(mac)
|
return str(mac)
|
||||||
|
|
||||||
|
|
||||||
def validate_mac(value):
|
def validate_mac(value: str) -> str:
|
||||||
"""
|
"""
|
||||||
Validate mac and return unix formatted version.
|
Validate mac and return unix formatted version.
|
||||||
|
|
||||||
|
@ -443,7 +471,7 @@ def validate_mac(value):
|
||||||
raise CoreError(f"invalid mac address {value}: {e}")
|
raise CoreError(f"invalid mac address {value}: {e}")
|
||||||
|
|
||||||
|
|
||||||
def validate_ip(value):
|
def validate_ip(value: str) -> str:
|
||||||
"""
|
"""
|
||||||
Validate ip address with prefix and return formatted version.
|
Validate ip address with prefix and return formatted version.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue