diff --git a/.env b/.env index 5a8ea024..5576df7c 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # Globals -VERSION="1.3.3" +VERSION="1.4.1" CEPH_VERSION="19.2.0" SPDK_VERSION="24.09" CONTAINER_REGISTRY="quay.io/ceph" @@ -101,3 +101,5 @@ DHCHAP_KEY6="DHHC-1:01:Bu4tZd7X2oW7XxmVH5tGCdoS30pDX6bZvexHYoudeVlJW9yz:" DHCHAP_KEY7="DHHC-1:01:JPJkDQ2po2FfLmKYlTF/sJ2HzVO/FKWxgXKE/H6XfL8ogQ1T:" DHCHAP_KEY8="DHHC-1:01:e0B0vDxKleDzYVtG42xqFvoWZfiufkoywmfRKrETzayRdf1j:" DHCHAP_KEY9="DHHC-1:01:KD+sfH3/o2bRQoV0ESjBUywQlMnSaYpZISUbVa0k0nsWpNST:" +DHCHAP_KEY10="DHHC-1:00:rWf0ZFYO7IgWGttM8w6jUrAY4cTQyqyXPdmxHeOSve3w5QU9:" +DHCHAP_KEY11="DHHC-1:02:j3uUz05r5aQy42vX4tDXqVf9HgUPPdEp3kXTgUWl9EphsG7jwpr9KSIt3bmRLXBijPTIDQ==:" diff --git a/ceph-nvmeof.conf b/ceph-nvmeof.conf index d2167551..f25e2e7a 100644 --- a/ceph-nvmeof.conf +++ b/ceph-nvmeof.conf @@ -17,6 +17,8 @@ state_update_notify = True state_update_timeout_in_msec = 2000 state_update_interval_sec = 5 enable_spdk_discovery_controller = False +enable_key_encryption = True +encryption_key = /etc/ceph/encryption.key #omap_file_lock_duration = 20 #omap_file_lock_retries = 30 #omap_file_lock_retry_sleep_interval = 1.0 @@ -29,7 +31,7 @@ enable_spdk_discovery_controller = False #verify_nqns = True #allowed_consecutive_spdk_ping_failures = 1 #spdk_ping_interval_in_seconds = 2.0 -#max_hosts_per_namespace = 1 +#max_hosts_per_namespace = 8 #max_namespaces_with_netmask = 1000 #max_subsystems = 128 #max_namespaces = 1024 diff --git a/control/discovery.py b/control/discovery.py index eae1a504..db3bc88b 100644 --- a/control/discovery.py +++ b/control/discovery.py @@ -13,6 +13,7 @@ from .config import GatewayConfig from .state import GatewayState, LocalGatewayState, OmapGatewayState, GatewayStateHandler from .utils import GatewayLogger +from .utils import GatewayUtilsCrypto from .proto import gateway_pb2 as pb2 import rados @@ -1129,8 +1130,10 @@ def start_service(self): t.start() local_state = LocalGatewayState() + dummy_crypto = GatewayUtilsCrypto(None) gateway_state = GatewayStateHandler(self.config, local_state, - self.omap_state, self._state_notify_update, f"discovery-{socket.gethostname()}") + self.omap_state, self._state_notify_update, + dummy_crypto, f"discovery-{socket.gethostname()}") gateway_state.start_update() try: diff --git a/control/grpc.py b/control/grpc.py index 1ff0e252..0d13f3d9 100644 --- a/control/grpc.py +++ b/control/grpc.py @@ -65,7 +65,8 @@ def group_id(self, request: monitor_pb2.group_id_req, context = None) -> Empty: class SubsystemHostAuth: MAX_PSK_KEY_NAME_LENGTH = 200 # taken from SPDK SPDK_TLS_PSK_MAX_LEN - def __init__(self): + def __init__(self, logger): ####################### + self.logger = logger ######################## self.subsys_allow_any_hosts = defaultdict(dict) self.subsys_dhchap_key = defaultdict(dict) self.host_dhchap_key = defaultdict(dict) @@ -148,9 +149,11 @@ def is_any_host_allowed(self, subsys) -> bool: def add_dhchap_key_to_subsystem(self, subsys, key): if key: + self.logger.error(f"XXXXX add dhchap key {key} to subsystem {subsys}") #################### self.subsys_dhchap_key[subsys] = key def remove_dhchap_key_from_subsystem(self, subsys): + self.logger.error(f"XXXXX remove dhchap key from subsystem {subsys}") #################### self.subsys_dhchap_key.pop(subsys, None) def does_subsystem_have_dhchap_key(self, subsys) -> bool: @@ -161,6 +164,7 @@ def get_subsystem_dhchap_key(self, subsys) -> str: key = None if subsys in self.subsys_dhchap_key: key = self.subsys_dhchap_key[subsys] + self.logger.error(f"XXXXX return key {key} for subsystem {subsys}") ################ return key class NamespaceInfo: @@ -324,13 +328,14 @@ def __init__(self, config: GatewayConfig, gateway_state: GatewayStateHandler, rp self.host_name = socket.gethostname() self.verify_nqns = self.config.getboolean_with_default("gateway", "verify_nqns", True) self.gateway_group = self.config.get_with_default("gateway", "group", "") - self.max_hosts_per_namespace = self.config.getint_with_default("gateway", "max_hosts_per_namespace", 1) + self.max_hosts_per_namespace = self.config.getint_with_default("gateway", "max_hosts_per_namespace", 8) self.max_namespaces_with_netmask = self.config.getint_with_default("gateway", "max_namespaces_with_netmask", 1000) self.max_subsystems = self.config.getint_with_default("gateway", "max_subsystems", GatewayService.MAX_SUBSYSTEMS_DEFAULT) self.max_namespaces = self.config.getint_with_default("gateway", "max_namespaces", GatewayService.MAX_NAMESPACES_DEFAULT) self.max_namespaces_per_subsystem = self.config.getint_with_default("gateway", "max_namespaces_per_subsystem", GatewayService.MAX_NAMESPACES_PER_SUBSYSTEM_DEFAULT) self.max_hosts_per_subsystem = self.config.getint_with_default("gateway", "max_hosts_per_subsystem", GatewayService.MAX_HOSTS_PER_SUBSYS_DEFAULT) self.gateway_pool = self.config.get_with_default("ceph", "pool", "") + self.enable_key_encryption = self.config.getboolean_with_default("gateway", "enable_key_encryption", True) self.ana_map = defaultdict(dict) self.cluster_nonce = {} self.bdev_cluster = {} @@ -339,7 +344,8 @@ def __init__(self, config: GatewayConfig, gateway_state: GatewayStateHandler, rp self.subsystem_listeners = defaultdict(set) self._init_cluster_context() self.subsys_max_ns = {} - self.host_info = SubsystemHostAuth() + self.subsys_serial = {} + self.host_info = SubsystemHostAuth(self.logger) ####################### def get_directories_for_key_file(self, key_type : str, subsysnqn : str, create_dir : bool = False) -> []: tmp_dirs = [] @@ -672,6 +678,7 @@ def create_bdev(self, anagrp: int, name, uuid, rbd_pool_name, rbd_image_name, bl self.logger.exception(errmsg) return BdevStatus(status=errcode, error_message=f"Failure creating bdev {name}: {errmsg}") + cluster_name = None try: cluster_name=self._get_cluster(anagrp) bdev_name = rpc_bdev.bdev_rbd_create( @@ -689,7 +696,8 @@ def create_bdev(self, anagrp: int, name, uuid, rbd_pool_name, rbd_image_name, bl self.logger.debug(f"bdev_rbd_create: {bdev_name}, cluster_name {cluster_name}") except Exception as ex: - self._put_cluster(cluster_name) + if cluster_name != None: + self._put_cluster(cluster_name) errmsg = f"bdev_rbd_create {name} failed" self.logger.exception(errmsg) errmsg = f"{errmsg} with:\n{ex}" @@ -802,39 +810,6 @@ def delete_bdev(self, bdev_name, recycling_mode=False, peer_msg=""): return pb2.req_status(status=0, error_message=os.strerror(0)) - def subsystem_already_exists(self, context, nqn) -> bool: - if not context: - return False - state = self.gateway_state.local.get_state() - for key, val in state.items(): - if not key.startswith(self.gateway_state.local.SUBSYSTEM_PREFIX): - continue - try: - subsys = json.loads(val) - subnqn = subsys["subsystem_nqn"] - if subnqn == nqn: - return True - except Exception: - self.logger.exception(f"Got exception while parsing {val}, will continue") - continue - return False - - def serial_number_already_used(self, context, serial) -> str: - if not context: - return None - state = self.gateway_state.local.get_state() - for key, val in state.items(): - if not key.startswith(self.gateway_state.local.SUBSYSTEM_PREFIX): - continue - try: - subsys = json.loads(val) - if serial == subsys["serial_number"]: - return subsys["subsystem_nqn"] - except Exception: - self.logger.exception(f"Got exception while parsing {val}") - continue - return None - def get_peer_message(self, context) -> str: if not context: return "" @@ -867,7 +842,8 @@ def create_subsystem_safe(self, request, context): peer_msg = self.get_peer_message(context) self.logger.info( - f"Received request to create subsystem {request.subsystem_nqn}, enable_ha: {request.enable_ha}, max_namespaces: {request.max_namespaces}, no group append: {request.no_group_append}, dhchap_key: {request.dhchap_key}, context: {context}{peer_msg}") + f"Received request to create subsystem {request.subsystem_nqn}, enable_ha: {request.enable_ha}, max_namespaces: {request.max_namespaces}, no group append: {request.no_group_append}, context: {context}{peer_msg}") + self.logger.error(f"XXXXX dhchap key: {request.dhchap_key}, encrypted: {request.key_encrypted}") ##################### if not request.enable_ha: errmsg = f"{create_subsystem_error_prefix}: HA must be enabled for subsystems" @@ -935,13 +911,16 @@ def create_subsystem_safe(self, request, context): errmsg = "" try: subsys_using_serial = None - subsys_already_exists = self.subsystem_already_exists(context, request.subsystem_nqn) + subsys_already_exists = True if request.subsystem_nqn in self.subsys_serial else False if subsys_already_exists: errmsg = f"Subsystem already exists" else: - subsys_using_serial = self.serial_number_already_used(context, request.serial_number) - if subsys_using_serial: - errmsg = f"Serial number {request.serial_number} already used by subsystem {subsys_using_serial}" + subsys_using_serial = None + for subsys, sn in self.subsys_serial.items(): + if sn == request.serial_number: + subsys_using_serial = subsys + errmsg = f"Serial number {request.serial_number} is already used by subsystem {subsys}" + break if subsys_already_exists or subsys_using_serial: errmsg = f"{create_subsystem_error_prefix}: {errmsg}" self.logger.error(f"{errmsg}") @@ -957,6 +936,7 @@ def create_subsystem_safe(self, request, context): ana_reporting = True, ) self.subsys_max_ns[request.subsystem_nqn] = request.max_namespaces + self.subsys_serial[request.subsystem_nqn] = request.serial_number if request.dhchap_key: self.host_info.add_dhchap_key_to_subsystem(request.subsystem_nqn, request.dhchap_key) self.logger.debug(f"create_subsystem {request.subsystem_nqn}: {ret}") @@ -978,6 +958,9 @@ def create_subsystem_safe(self, request, context): if context: # Update gateway state try: + if self.enable_key_encryption and request.dhchap_key: + request.dhchap_key = self.gateway_state.crypto.encrypt_text(request.dhchap_key) + request.key_encrypted = True json_req = json_format.MessageToJson( request, preserving_proto_field_name=True, including_default_value_fields=True) self.gateway_state.add_subsystem(request.subsystem_nqn, json_req) @@ -1052,6 +1035,7 @@ def delete_subsystem_safe(self, request, context): nqn=request.subsystem_nqn, ) self.subsys_max_ns.pop(request.subsystem_nqn) + self.subsys_serial.pop(request.subsystem_nqn) if request.subsystem_nqn in self.subsystem_listeners: self.subsystem_listeners.pop(request.subsystem_nqn, None) self.host_info.clean_subsystem(request.subsystem_nqn) @@ -1167,13 +1151,17 @@ def create_namespace(self, subsystem_nqn, bdev_name, nsid, anagrpid, uuid, no_au peer_msg = self.get_peer_message(context) self.logger.info(f"Received request to add {bdev_name} to {subsystem_nqn} with ANA group id {anagrpid}{nsid_msg}, no_auto_visible: {no_auto_visible}, context: {context}{peer_msg}") - if subsystem_nqn not in self.subsys_max_ns: + if subsystem_nqn not in self.subsys_serial: errmsg = f"{add_namespace_error_prefix}: No such subsystem" self.logger.error(errmsg) return pb2.nsid_status(status=errno.ENOENT, error_message=errmsg) - if anagrpid > self.subsys_max_ns[subsystem_nqn]: - errmsg = f"{add_namespace_error_prefix}: Group ID {anagrpid} is bigger than configured maximum {self.subsys_max_ns[subsystem_nqn]}" + subsys_max_ns = 0 + if subsystem_nqn in self.subsys_max_ns: + subsys_max_ns = self.subsys_max_ns[subsystem_nqn] + + if anagrpid > subsys_max_ns: + errmsg = f"{add_namespace_error_prefix}: Group ID {anagrpid} is bigger than configured maximum {subsys_max_ns}" self.logger.error(errmsg) return pb2.nsid_status(status=errno.EINVAL, error_message=errmsg) @@ -1188,14 +1176,14 @@ def create_namespace(self, subsystem_nqn, bdev_name, nsid, anagrpid, uuid, no_au self.logger.error(f"{errmsg}") return pb2.req_status(status=errno.E2BIG, error_message=errmsg) - if nsid and nsid > self.subsys_max_ns[subsystem_nqn]: - errmsg = f"{add_namespace_error_prefix}: Requested NSID {nsid} is bigger than the maximal one ({self.subsys_max_ns[subsystem_nqn]})" + if nsid and nsid > subsys_max_ns: + errmsg = f"{add_namespace_error_prefix}: Requested NSID {nsid} is bigger than the maximal one ({subsys_max_ns})" self.logger.error(f"{errmsg}") return pb2.req_status(status=errno.E2BIG, error_message=errmsg) if not nsid and self.subsystem_nsid_bdev_and_uuid.get_namespace_count(subsystem_nqn, - None, 0) >= self.subsys_max_ns[subsystem_nqn]: - errmsg = f"{add_namespace_error_prefix}: Subsystem's maximal number of namespaces ({self.subsys_max_ns[subsystem_nqn]}) has already been reached" + None, 0) >= subsys_max_ns: + errmsg = f"{add_namespace_error_prefix}: Subsystem's maximal number of namespaces ({subsys_max_ns}) has already been reached" self.logger.error(f"{errmsg}") return pb2.req_status(status=errno.E2BIG, error_message=errmsg) @@ -1204,8 +1192,8 @@ def create_namespace(self, subsystem_nqn, bdev_name, nsid, anagrpid, uuid, no_au self.logger.error(f"{errmsg}") return pb2.req_status(status=errno.E2BIG, error_message=errmsg) - if self.subsystem_nsid_bdev_and_uuid.get_namespace_count(subsystem_nqn, None, 0) >= self.subsys_max_ns[subsystem_nqn]: - errmsg = f"{add_namespace_error_prefix}: Maximal number of namespaces per subsystem ({self.subsys_max_ns[subsystem_nqn]}) has already been reached" + if self.subsystem_nsid_bdev_and_uuid.get_namespace_count(subsystem_nqn, None, 0) >= subsys_max_ns: + errmsg = f"{add_namespace_error_prefix}: Maximal number of namespaces per subsystem ({subsys_max_ns}) has already been reached" self.logger.error(f"{errmsg}") return pb2.req_status(status=errno.E2BIG, error_message=errmsg) @@ -1263,7 +1251,7 @@ def set_ana_state_safe(self, ana_info: pb2.ana_info, context=None): self.ana_map[nqn][gs.grp_id] = gs.state # If this is not set the subsystem was not created yet - if not nqn in self.subsys_max_ns: + if not nqn in self.subsys_serial: continue self.logger.debug(f"Iterate over {nqn=} {self.subsystem_listeners[nqn]=}") @@ -2357,7 +2345,8 @@ def add_host_safe(self, request, context): self.logger.info(f"Received request to allow any host access for {request.subsystem_nqn}, context: {context}{peer_msg}") else: self.logger.info( - f"Received request to add host {request.host_nqn} to {request.subsystem_nqn}, psk: {request.psk}, dhchap: {request.dhchap_key}, context: {context}{peer_msg}") + f"Received request to add host {request.host_nqn} to {request.subsystem_nqn}, context: {context}{peer_msg}") + self.logger.error(f"XXXXX dhchap key: {request.dhchap_key}, encrypted: {request.key_encrypted}") ##################### all_host_failure_prefix=f"Failure allowing open host access to {request.subsystem_nqn}" host_failure_prefix=f"Failure adding host {request.host_nqn} to {request.subsystem_nqn}" @@ -2440,7 +2429,8 @@ def add_host_safe(self, request, context): dhchap_ctrlr_key = self.host_info.get_subsystem_dhchap_key(request.subsystem_nqn) if dhchap_ctrlr_key: - self.logger.info(f"Got DHCHAP key {dhchap_ctrlr_key} for subsystem {request.subsystem_nqn}") + self.logger.info(f"Got DHCHAP key for subsystem {request.subsystem_nqn}") + self.logger.error(f"XXXXX Got dhchap controller key: {dhchap_ctrlr_key}") ##################### if dhchap_ctrlr_key and not request.dhchap_key: errmsg=f"{host_failure_prefix}: Host must have a DH-HMAC-CHAP key if the subsystem has one" @@ -2547,6 +2537,13 @@ def add_host_safe(self, request, context): if context: # Update gateway state try: + if self.enable_key_encryption: + if request.dhchap_key: + request.dhchap_key = self.gateway_state.crypto.encrypt_text(request.dhchap_key) + request.key_encrypted = True + if request.psk: + request.psk = self.gateway_state.crypto.encrypt_text(request.psk) + request.psk_encrypted = True json_req = json_format.MessageToJson( request, preserving_proto_field_name=True, including_default_value_fields=True) self.gateway_state.add_host(request.subsystem_nqn, request.host_nqn, json_req) @@ -2678,7 +2675,8 @@ def change_host_key_safe(self, request, context): peer_msg = self.get_peer_message(context) failure_prefix=f"Failure changing DH-HMAC-CHAP key for host {request.host_nqn} on subsystem {request.subsystem_nqn}" self.logger.info( - f"Received request to change inband authentication key for host {request.host_nqn} on subsystem {request.subsystem_nqn}, dhchap: {request.dhchap_key}, context: {context}{peer_msg}") + f"Received request to change inband authentication key for host {request.host_nqn} on subsystem {request.subsystem_nqn}, context: {context}{peer_msg}") + self.logger.error(f"XXXXX dhchap key: {request.dhchap_key}") ##################### if request.host_nqn == "*": errmsg=f"{failure_prefix}: Host NQN can't be '*'" @@ -2793,12 +2791,22 @@ def change_host_key_safe(self, request, context): if context: # Update gateway state try: + key_encrypted = False + if self.enable_key_encryption and request.dhchap_key: + request.dhchap_key = self.gateway_state.crypto.encrypt_text(request.dhchap_key) + key_encrypted = True + psk_encrypted = False + if self.enable_key_encryption and host_psk: + host_psk = self.gateway_state.crypto.encrypt_text(host_psk) + psk_encrypted = True add_req = pb2.add_host_req(subsystem_nqn=request.subsystem_nqn, host_nqn=request.host_nqn, psk=host_psk, - dhchap_key=request.dhchap_key) + dhchap_key=request.dhchap_key, + key_encrypted=key_encrypted, + psk_encrypted=psk_encrypted) json_req = json_format.MessageToJson( - add_req, preserving_proto_field_name=True, including_default_value_fields=True) + add_req, preserving_proto_field_name=True, including_default_value_fields=True) self.gateway_state.add_host(request.subsystem_nqn, request.host_nqn, json_req) except Exception as ex: errmsg = f"Error persisting host change key for host {request.host_nqn} in {request.subsystem_nqn}" @@ -3454,7 +3462,8 @@ def change_subsystem_key_safe(self, request, context): peer_msg = self.get_peer_message(context) failure_prefix=f"Failure changing DH-HMAC-CHAP key for subsystem {request.subsystem_nqn}" self.logger.info( - f"Received request to change inband authentication key for subsystem {request.subsystem_nqn}, dhchap: {request.dhchap_key}, context: {context}{peer_msg}") + f"Received request to change inband authentication key for subsystem {request.subsystem_nqn}, context: {context}{peer_msg}") + self.logger.error(f"XXXXX dhchap key: {request.dhchap_key}") ##################### if not GatewayState.is_key_element_valid(request.subsystem_nqn): errmsg = f"{failure_prefix}: Invalid subsystem NQN \"{request.subsystem_nqn}\", contains invalid characters" @@ -3501,12 +3510,17 @@ def change_subsystem_key_safe(self, request, context): assert subsys_entry, f"Can't find entry for subsystem {request.subsystem_nqn}" try: + key_encrypted = False + if self.enable_key_encryption and request.dhchap_key: + request.dhchap_key = self.gateway_state.crypto.encrypt_text(request.dhchap_key) + key_encrypted = True create_req = pb2.create_subsystem_req(subsystem_nqn=request.subsystem_nqn, serial_number=subsys_entry["serial_number"], max_namespaces=subsys_entry["max_namespaces"], enable_ha=subsys_entry["enable_ha"], no_group_append=subsys_entry["no_group_append"], - dhchap_key=request.dhchap_key) + dhchap_key=request.dhchap_key, + key_encrypted=key_encrypted) json_req = json_format.MessageToJson( create_req, preserving_proto_field_name=True, including_default_value_fields=True) self.gateway_state.add_subsystem(request.subsystem_nqn, json_req) @@ -3532,7 +3546,6 @@ def change_subsystem_key_safe(self, request, context): except Excpetion: pass - return pb2.req_status(status=0, error_message=os.strerror(0)) def change_subsystem_key(self, request, context=None): diff --git a/control/proto/gateway.proto b/control/proto/gateway.proto index 693948c7..32ca3105 100644 --- a/control/proto/gateway.proto +++ b/control/proto/gateway.proto @@ -192,6 +192,7 @@ message create_subsystem_req { bool enable_ha = 4; optional bool no_group_append = 5; optional string dhchap_key = 6; + optional bool key_encrypted = 7; } message delete_subsystem_req { @@ -215,6 +216,8 @@ message add_host_req { string host_nqn = 2; optional string psk = 3; optional string dhchap_key = 4; + optional bool psk_encrypted = 5; + optional bool key_encrypted = 6; } message change_host_key_req { diff --git a/control/server.py b/control/server.py index 51bfa69c..35740262 100644 --- a/control/server.py +++ b/control/server.py @@ -33,6 +33,7 @@ from .config import GatewayConfig from .utils import GatewayLogger from .utils import GatewayUtils +from .utils import GatewayUtilsCrypto from .cephutils import CephUtils from .prometheus import start_exporter @@ -114,6 +115,20 @@ def __init__(self, config: GatewayConfig): self.monitor_client_log_file_path = None self.omap_state = None self.omap_lock = None + enc_key = None + enc_key_file = self.config.get_with_default("gateway", "encryption_key", "") + if enc_key_file: + try: + enc_key = GatewayUtilsCrypto.read_encryption_key(enc_key_file) + except Exception: + self.logger.exception(f"Got an error trying to read encryption key {enc_key_file}, will use fallback key") + if enc_key: + self.logger.info(f"Read encryption key from {enc_key_file}") + else: + # Use this key as the fallback in case the user didn't set his/her own key + self.logger.warning(f"No valid key file was set, will use fallback encryption key") + enc_key = b"Ubp_Ll9pnyXtluCvqyBrnta2Y7ju9qexc_f0iWYnhWI=" + self.crypto = GatewayUtilsCrypto(enc_key) self.name = self.config.get("gateway", "name") if not self.name: @@ -235,7 +250,8 @@ def serve(self): self._start_discovery_service() # Register service implementation with server - gateway_state = GatewayStateHandler(self.config, local_state, omap_state, self.gateway_rpc_caller, f"gateway-{self.name}") + gateway_state = GatewayStateHandler(self.config, local_state, omap_state, + self.gateway_rpc_caller, self.crypto, f"gateway-{self.name}") self.omap_lock = OmapLock(omap_state, gateway_state, self.rpc_lock) self.gateway_rpc = GatewayService(self.config, gateway_state, self.rpc_lock, self.omap_lock, self.group_id, self.spdk_rpc_client, self.spdk_rpc_subsystems_client, self.ceph_utils) self.server = self._grpc_server(self._gateway_address()) @@ -764,6 +780,9 @@ def gateway_rpc_caller(self, requests, is_add_req): if key.startswith(GatewayState.SUBSYSTEM_PREFIX): if is_add_req: req = json_format.Parse(val, pb2.create_subsystem_req(), ignore_unknown_fields=True) + if req.key_encrypted and req.dhchap_key: + req.dhchap_key = self.crypto.decrypt_text(req.dhchap_key) + req.key_encrypted = False self.gateway_rpc.create_subsystem(req) else: req = json_format.Parse(val, @@ -789,6 +808,12 @@ def gateway_rpc_caller(self, requests, is_add_req): elif key.startswith(GatewayState.HOST_PREFIX): if is_add_req: req = json_format.Parse(val, pb2.add_host_req(), ignore_unknown_fields=True) + if req.key_encrypted and req.dhchap_key: + req.dhchap_key = self.crypto.decrypt_text(req.dhchap_key) + req.key_encrypted = False + if req.psk_encrypted and req.psk: + req.psk = self.crypto.decrypt_text(req.psk) + req.psk_encrypted = False self.gateway_rpc.add_host(req) else: req = json_format.Parse(val, pb2.remove_host_req(), ignore_unknown_fields=True) diff --git a/control/state.py b/control/state.py index 27e5d523..eb4553a8 100644 --- a/control/state.py +++ b/control/state.py @@ -17,6 +17,7 @@ from abc import ABC, abstractmethod from .utils import GatewayLogger from .utils import GatewayUtils +from .utils import GatewayUtilsCrypto from google.protobuf import json_format from .proto import gateway_pb2 as pb2 @@ -629,8 +630,9 @@ class GatewayStateHandler: use_notify: Flag to indicate use of OMAP watch/notify """ - def __init__(self, config, local, omap, gateway_rpc_caller, id_text=""): + def __init__(self, config, local, omap, gateway_rpc_caller, crypto, id_text=""): self.config = config + self.crypto = crypto self.local = local self.omap = omap self.gateway_rpc_caller = gateway_rpc_caller @@ -770,26 +772,35 @@ def host_only_key_changed(self, old_val, new_val): old_req = json_format.Parse(old_val, pb2.add_host_req(), ignore_unknown_fields=True ) except json_format.ParseError: self.logger.exception(f"Got exception parsing {old_val}") - return (False, None) + return (False, None, b"") try: new_req = json_format.Parse(new_val, pb2.add_host_req(), ignore_unknown_fields=True) except json_format.ParseError: self.logger.exeption(f"Got exception parsing {new_val}") - return (False, None) + return (False, None, b"") if not old_req or not new_req: self.logger.debug(f"Failed to parse requests, old: {old_val} -> {old_req}, new: {new_val} -> {new_req}") - return (False, None) + return (False, None, b"") assert old_req != new_req, f"Something was wrong we shouldn't get identical old and new values ({old_req})" # Because of Json formatting of empty fields we might get a difference here, so just use the same values for empty if not old_req.dhchap_key: old_req.dhchap_key = "" if not new_req.dhchap_key: new_req.dhchap_key = "" + if not old_req.key_encrypted: + old_req.key_encrypted = False + if not new_req.key_encrypted: + new_req.key_encrypted = False + if not old_req.psk_encrypted: + old_req.psk_encrypted = False + if not new_req.psk_encrypted: + new_req.psk_encrypted = False old_req.dhchap_key = new_req.dhchap_key + old_req.key_encrypted = new_req.key_encrypted if old_req != new_req: # Something besides the keys is different - return (False, None) - return (True, new_req.dhchap_key) + return (False, None, b"") + return (True, new_req.dhchap_key, new_req.key_encrypted) def subsystem_only_key_changed(self, old_val, new_val): # If only the dhchap key field has changed we can use change_key request instead of re-adding the subsystem @@ -799,15 +810,15 @@ def subsystem_only_key_changed(self, old_val, new_val): old_req = json_format.Parse(old_val, pb2.create_subsystem_req(), ignore_unknown_fields=True ) except json_format.ParseError: self.logger.exception(f"Got exception parsing {old_val}") - return (False, None) + return (False, None, b"") try: new_req = json_format.Parse(new_val, pb2.create_subsystem_req(), ignore_unknown_fields=True) except json_format.ParseError: self.logger.exeption(f"Got exception parsing {new_val}") - return (False, None) + return (False, None, b"") if not old_req or not new_req: self.logger.debug(f"Failed to parse requests, old: {old_val} -> {old_req}, new: {new_val} -> {new_req}") - return (False, None) + return (False, None, b"") assert old_req != new_req, f"Something was wrong we shouldn't get identical old and new values ({old_req})" # Because of Json formatting of empty fields we might get a difference here, so just use the same values for empty if not old_req.dhchap_key: @@ -815,10 +826,11 @@ def subsystem_only_key_changed(self, old_val, new_val): if not new_req.dhchap_key: new_req.dhchap_key = "" old_req.dhchap_key = new_req.dhchap_key + old_req.key_encrypted = new_req.key_encrypted if old_req != new_req: # Something besides the keys is different - return (False, None) - return (True, new_req.dhchap_key) + return (False, None, b"") + return (True, new_req.dhchap_key, new_req.key_encrypted) def break_namespace_key(self, ns_key: str): if not ns_key.startswith(GatewayState.NAMESPACE_PREFIX): @@ -940,35 +952,26 @@ def update(self) -> bool: subsystem_prefix = GatewayState.build_subsystem_key("nqn") for key in changed.keys(): if key.startswith(ns_prefix): - try: - (should_process, new_lb_grp_id) = self.namespace_only_lb_group_id_changed(local_state_dict[key], - omap_state_dict[key]) - if should_process: - assert new_lb_grp_id, "Shouldn't get here with an empty lb group id" - self.logger.debug(f"Found {key} where only the load balancing group id has changed. The new group id is {new_lb_grp_id}") - only_lb_group_changed.append((key, new_lb_grp_id)) - except Exception as ex: - self.logger.warning("Got exception checking namespace for load balancing group id change") + (should_process, + new_lb_grp_id) = self.namespace_only_lb_group_id_changed(local_state_dict[key], omap_state_dict[key]) + if should_process: + assert new_lb_grp_id, "Shouldn't get here with an empty load balancing group id" + self.logger.debug(f"Found {key} where only the load balancing group id has changed. The new group id is {new_lb_grp_id}") + only_lb_group_changed.append((key, new_lb_grp_id)) elif key.startswith(host_prefix): - try: - (should_process, - new_dhchap_key) = self.host_only_key_changed(local_state_dict[key], omap_state_dict[key]) - if should_process: - assert new_dhchap_key, "Shouldn't get here with an empty dhchap key" - self.logger.debug(f"Found {key} where only the key has changed. The new DHCHAP key is {new_dhchap_key}") - only_host_key_changed.append((key, new_dhchap_key)) - except Exception as ex: - self.logger.warning("Got exception checking host for key change") + (should_process, + new_dhchap_key, + new_key_encrypted) = self.host_only_key_changed(local_state_dict[key], omap_state_dict[key]) + if should_process: + self.logger.debug(f"Found {key} where only the key has changed.") + only_host_key_changed.append((key, new_dhchap_key, new_key_encrypted)) elif key.startswith(subsystem_prefix): - try: - (should_process, - new_dhchap_key) = self.subsystem_only_key_changed(local_state_dict[key], omap_state_dict[key]) - if should_process: - assert new_dhchap_key, "Shouldn't get here with an empty dhchap key" - self.logger.debug(f"Found {key} where only the key has changed. The new DHCHAP key is {new_dhchap_key}") - only_subsystem_key_changed.append((key, new_dhchap_key)) - except Exception as ex: - self.logger.warning("Got exception checking subsystem for key change") + (should_process, + new_dhchap_key, + new_key_encrypted) = self.subsystem_only_key_changed(local_state_dict[key], omap_state_dict[key]) + if should_process: + self.logger.debug(f"Found {key} where only the key has changed.") + only_subsystem_key_changed.append((key, new_dhchap_key, new_key_encrypted)) for ns_key, new_lb_grp in only_lb_group_changed: ns_nqn = None @@ -989,7 +992,7 @@ def update(self) -> bool: except Exception as ex: self.logger.error(f"Exception formatting change namespace load balancing group request:\n{ex}") - for host_key, new_dhchap_key in only_host_key_changed: + for host_key, new_dhchap_key, new_key_encrypted in only_host_key_changed: subsys_nqn = None host_nqn = None try: @@ -1003,15 +1006,16 @@ def update(self) -> bool: if subsys_nqn and host_nqn: try: host_key_key = GatewayState.build_host_key_key(subsys_nqn, host_nqn) - req = pb2.change_host_key_req(subsystem_nqn=subsys_nqn, host_nqn=host_nqn, - dhchap_key=new_dhchap_key) + if new_key_encrypted and new_dhchap_key: + new_dhchap_key = self.crypto.decrypt_text(new_dhchap_key) + req = pb2.change_host_key_req(subsystem_nqn=subsys_nqn, host_nqn=host_nqn, dhchap_key=new_dhchap_key) json_req = json_format.MessageToJson(req, preserving_proto_field_name=True, including_default_value_fields=True) added[host_key_key] = json_req except Exception as ex: self.logger.error(f"Exception formatting change host key request:\n{ex}") - for subsys_key, new_dhchap_key in only_subsystem_key_changed: + for subsys_key, new_dhchap_key, new_key_encrypted in only_subsystem_key_changed: subsys_nqn = None try: changed.pop(subsys_key) @@ -1021,6 +1025,8 @@ def update(self) -> bool: if subsys_nqn: try: subsys_key_key = GatewayState.build_subsystem_key_key(subsys_nqn) + if new_key_encrypted and new_dhchap_key: + new_dhchap_key = self.crypto.decrypt_text(new_dhchap_key) req = pb2.change_subsystem_key_req(subsystem_nqn=subsys_nqn, dhchap_key=new_dhchap_key) json_req = json_format.MessageToJson(req, preserving_proto_field_name=True, including_default_value_fields=True) diff --git a/control/utils.py b/control/utils.py index 570f5415..81d5a364 100644 --- a/control/utils.py +++ b/control/utils.py @@ -18,7 +18,8 @@ import shutil import netifaces from typing import Tuple, List - +from cryptography.fernet import Fernet +import base64 class GatewayEnumUtils: def get_value_from_key(e_type, keyval, ignore_case = False): @@ -182,6 +183,48 @@ def is_valid_nqn(nqn): return (0, os.strerror(0)) +class GatewayUtilsCrypto: + KEY_SIZE = 32 + + def __init__(self, encryption_key: bytes): + if encryption_key: + self.__secret_box = Fernet(encryption_key) + else: + self.__secret_box = None + + @classmethod + def read_encryption_key(cls, keyfile : str) -> bytes: + keyval = "" + encoded_key = None + with open(keyfile) as f: + for line in f: + if line.startswith("-----BEGIN PRIVATE KEY-----"): + continue + if line.startswith("-----END PRIVATE KEY-----"): + continue + keyval += line.rstrip('\n') + + keybytes = base64.b64decode(keyval) + if len(keybytes) < cls.KEY_SIZE: + raise RuntimeError(f"Encryption key has length {len(keybytes)} which is too short. The minimal length is {cls.KEY_SIZE}") + encoded_key = base64.urlsafe_b64encode(keybytes[:cls.KEY_SIZE]) + + return encoded_key + + def encrypt_text(self, msg : str) -> str: + if self.__secret_box: + encrypted = base64.b64encode(self.__secret_box.encrypt(msg.encode("utf-8"))).decode("utf-8") + else: + encrypted = msg + return encrypted + + def decrypt_text(self, msg : str) -> str: + if self.__secret_box: + plain = self.__secret_box.decrypt(base64.b64decode(msg.encode("utf-8"))).decode("utf-8") + else: + plain = msg + return plain + class GatewayLogger: CEPH_LOG_DIRECTORY = "/var/log/ceph/" MAX_LOG_FILE_SIZE_DEFAULT = 10 diff --git a/docker-compose.yaml b/docker-compose.yaml index 1e24a0da..a5655ea2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -69,8 +69,9 @@ services: sh -c './vstart.sh --new $$CEPH_VSTART_ARGS && echo ceph dashboard nvmeof-gateway-add -i <(echo nvmeof-devel:5500) nvmeof.1 && pushd /etc/ceph && - openssl req -x509 -newkey rsa:4096 -nodes -keyout server.key -out server.crt -days 3650 -subj /CN=my.server -addext "subjectAltName = IP:192.168.13.3, IP:0.0.0.0" && - openssl req -x509 -newkey rsa:4096 -nodes -keyout client.key -out client.crt -days 3650 -subj /CN=client1 && + openssl req -x509 -newkey rsa:4096 -noenc -keyout server.key -out server.crt -days 3650 -subj /CN=my.server -addext "subjectAltName = IP:192.168.13.3, IP:0.0.0.0" && + openssl req -x509 -newkey rsa:4096 -noenc -keyout client.key -out client.crt -days 3650 -subj /CN=client1 && + openssl req -newkey rsa:512 -noenc -noout -keyout encryption.key -batch 2> /dev/null && popd && ceph osd pool create rbd && sleep infinity' @@ -80,6 +81,7 @@ services: [ -f /etc/ceph/server.key ] && [ -f /etc/ceph/client.crt ] && [ -f /etc/ceph/client.key ] && + [ -f /etc/ceph/encryption.key ] && ceph osd pool stats rbd start_period: 6s interval: 3s diff --git a/pdm.lock b/pdm.lock index ebf1f322..ab256781 100644 --- a/pdm.lock +++ b/pdm.lock @@ -1,23 +1,178 @@ # This file is @generated by PDM. # It is not intended for manual editing. +[metadata] +groups = ["default", "test"] +strategy = ["cross_platform"] +lock_version = "4.5.0" +content_hash = "sha256:50fa7dbfb610c6fbde576fcc8853f0ab80a0e6ac4254a13fa40a676ce7d80919" + +[[metadata.targets]] +requires_python = "~=3.9" + +[[package]] +name = "cffi" +version = "1.17.1" +requires_python = ">=3.8" +summary = "Foreign Function Interface for Python calling C code." +dependencies = [ + "pycparser", +] +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + [[package]] name = "colorama" version = "0.4.6" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Cross-platform colored terminal text." +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cryptography" +version = "43.0.3" +requires_python = ">=3.7" +summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +dependencies = [ + "cffi>=1.12; platform_python_implementation != \"PyPy\"", +] +files = [ + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, +] [[package]] name = "exceptiongroup" -version = "1.1.2" +version = "1.2.2" requires_python = ">=3.7" summary = "Backport of PEP 654 (exception groups)" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] [[package]] name = "grpcio" version = "1.53.2" requires_python = ">=3.7" summary = "HTTP/2-based RPC framework" +files = [ + {file = "grpcio-1.53.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:18afdda2bbe0c615da4daff754cab0df9bbd859c415d85e7e741a2975b3208b4"}, + {file = "grpcio-1.53.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33f7678287ac330c94e25f96cdb951e0861e206115ba4d8ea66cf6546b1a09d0"}, + {file = "grpcio-1.53.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:1af074f28a56425e4f4d99761708981543a27ae963f5b4b0a36ff71f3483479d"}, + {file = "grpcio-1.53.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df07843c8c0dc71a56d3af3dfe19165fb0d3af7d3354a72185f6fa1b4ac05cab"}, + {file = "grpcio-1.53.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b403c4ad22f3ba37c7720547d8888a1e4b74ad980a94332bbbc50330b623abc"}, + {file = "grpcio-1.53.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6275a54b41d6b1ec539b019bc3affaf6d05b0a0ba36af1a65b8a2810ef69e07d"}, + {file = "grpcio-1.53.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0e92dc6a85cd1de42527812ef1276095e62169d002d86c888b6e889fcda1dd29"}, + {file = "grpcio-1.53.2-cp310-cp310-win32.whl", hash = "sha256:6be86e8d5cf47415968588e5dfbfb92ee8757fb41139584192b67050d1a72c58"}, + {file = "grpcio-1.53.2-cp310-cp310-win_amd64.whl", hash = "sha256:5b49f372df33f5f84865aef5d46cacd23180b586c80e8cbe0ce149b96dfa8c4c"}, + {file = "grpcio-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:8166ac6671472d172cc0db50323b7a7504bd534de54aa31354465a00ca44409d"}, + {file = "grpcio-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:f7e66d8b31ef2bada7029275debbe12c97397ec7ac70a659837a7b8a6a9dc916"}, + {file = "grpcio-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:712113946b303db9ae4245a13de213710367850a6c3c53530b70e87989feb8e0"}, + {file = "grpcio-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3761f9a6817e32898eaa5aecd0b0ad69d0c68ab45ea7bf206e8dc4548f025f0"}, + {file = "grpcio-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c63592103fded38b258f1e520ba8b0a7a0bbc397cddd6520a1f74dc4b5dec0"}, + {file = "grpcio-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:53d34cbf212f03634d74ba366d595b4a06a3b60fcc731eddbd6fd7ebe4acf981"}, + {file = "grpcio-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b789472e9ef75d179295d0c6a1f7f0aefd08189cd1c822b068b0523365a1dbe"}, + {file = "grpcio-1.53.2-cp311-cp311-win32.whl", hash = "sha256:7b44ed75b9d67d17e5a098a0f99a8fd3e5861fd3c4eb54212277a0acdf298434"}, + {file = "grpcio-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:1d1a320230e0d020880178b8eb453300bd57700b44c3744268370502e7376a9b"}, + {file = "grpcio-1.53.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:8fc7667564c8c15748354dea1bb4035c5118df4e9dc5154ccdb6e62a3e5a2bac"}, + {file = "grpcio-1.53.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:80a8867746cff41c2db436dd9eea18ebbfcd0449d65b64b3ed3c995207898971"}, + {file = "grpcio-1.53.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:431f864f2642a97d0aa8c6b606c307f03d22f919b1a226af90488426aed35809"}, + {file = "grpcio-1.53.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea6a20c5a732a27b64623d43614b3022e6fcfc081a75236b7f9aa069d2eaa4d"}, + {file = "grpcio-1.53.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504af9e86ab01c9c33d8a452fe846aa931d024945f2e897537ccb8f7d76778ee"}, + {file = "grpcio-1.53.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2b4f5671f9e88b7f51f54adda37a23277b7fdebd1557c47543b3e8a8044dd510"}, + {file = "grpcio-1.53.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d9c51ca201326b49cfee38336c6e7dd1cb8a6b6d0dcf84aeaecbae310a736dbc"}, + {file = "grpcio-1.53.2-cp39-cp39-win32.whl", hash = "sha256:7e6885a8431939f1ee547e965fa3cb801a518b83d3d3509e90dbef78f0b5fd29"}, + {file = "grpcio-1.53.2-cp39-cp39-win_amd64.whl", hash = "sha256:ea84becb5cbd6a94a810c5214eb263ae57e915a9ed1bdcd5b4a6baf13d8c5177"}, + {file = "grpcio-1.53.2.tar.gz", hash = "sha256:0c9e42f2499c8603af1d88771dc97e2c6b0310c278337058fd7fd1ddb35ab853"}, +] [[package]] name = "grpcio-tools" @@ -29,45 +184,119 @@ dependencies = [ "protobuf<5.0dev,>=4.21.6", "setuptools", ] +files = [ + {file = "grpcio-tools-1.53.2.tar.gz", hash = "sha256:1b10f95d1f4af2b9d63c9beccf386b3a5e1a92f14b3f64a9a8385b6ba091e0dc"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:8d047f35c04a78176ad61a2336bfc13bc7d773bcaf4bdbf34420faa93f52a30f"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:56dba5debe2d805d30a336302d696a32c8a8d7bd9951cb9eddbbc514f95a3afc"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0a24c1f0b03069290095d7d0467ef6b9db4a2ac6df505ac066025990f490dbb5"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccee441cbe40b2f40a8e1c1967fe71647b02914993e606dc1fd9ac216d8916a4"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e438248bdd092bfa74ddec74de86808b952fe65b23911b68d649160a26449d90"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f855784689e3162a9e1811299c7745f84a856d8085b8e34ae6db27318a28d42e"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:34d0227356b4dc2533b800f941a714100a35f93a97ddf44b25a4dcb3b7c8559b"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-win32.whl", hash = "sha256:85e933f52e85476d70fddc0112952cfe8537166a3b05b41bde5eb9ae71cd2328"}, + {file = "grpcio_tools-1.53.2-cp310-cp310-win_amd64.whl", hash = "sha256:86e381816730c6459c0a4be780704098865083dcc66d4ea6f0603a7f3abbc376"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:968c94cb210da93d02c3d41605fc3400cdbd8e30e5ef5910638570a6d9b1be1d"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:a71e2a881eb8e821b6f5eeab2ee450b56597000ec34bfcd0c35b666ad7e64eb9"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:621e6aa0ee0ca6d24cd0dc0a3ea4e8dd585ee9a7c665f0b5247a08032d89ac9f"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f073ee3d1088d54fd1da5df2f39ae8767397a6e60baaabbf22525e5dc86b759c"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556f6997fe369a6cfd230335c46cb89d5ac2be65c093b25b8a0e9bfee76cb705"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:049b16c36c3b0e9e52aa35dec6655000c97f5a26215322804d4149c5690997e4"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ba8cdc56b713e6b27b2f5777e449b4617b549af6ab548aaf265eeda12a4ac6f"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-win32.whl", hash = "sha256:f1bb5564e7dec518b163761771372a010514c1845cc8e96b6e84af3cac4fd864"}, + {file = "grpcio_tools-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:c57cd3d0ef5d2ac8cc0ffc7b9226e85364adf50e91aaf3c34589d15e574a7215"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:95a2563ff4928a71815815d8ab50ebc7143eaf9f69062e557e3dd9b1ce029167"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:161f6ca5786dbabe451e80f520b767f244ff0559a91d9148b82f0a4cefa1968f"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:0c8bb2ac4f17b53cc4bbd51da87ee111704003a618fa6903edd6013aa0beffe3"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d27bbcb89e7dee2d5e03caffa48f9ecdbc1a0384e4d2bbd5691ab9902bf63c10"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330ec5a90c56d8c90b7668b8e85228fd64d85fb7909525f559ba4471a3c84b8d"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ecf297f8fecdce591716794a1ec5212b03d8302452d6ea0a4f88479592e09bfa"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a554d24b0500e3cd84623998a8c6ce44ded62ffaaa5ef9c1252dbe6fdb614edf"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-win32.whl", hash = "sha256:32e6921291586e897dbcdf54c1dbfb95c3bb2446b28b76dcbd85a01807712e4e"}, + {file = "grpcio_tools-1.53.2-cp39-cp39-win_amd64.whl", hash = "sha256:82cbdec632c5ddefaf55077100313edacb99c3c72a3f1b7d224c6bb240709d11"}, +] [[package]] name = "iniconfig" version = "2.0.0" requires_python = ">=3.7" summary = "brain-dead simple config-ini parsing" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] [[package]] name = "netifaces" version = "0.11.0" summary = "Portable network interface information." +files = [ + {file = "netifaces-0.11.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5be83986100ed1fdfa78f11ccff9e4757297735ac17391b95e17e74335c2047d"}, + {file = "netifaces-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54ff6624eb95b8a07e79aa8817288659af174e954cca24cdb0daeeddfc03c4ff"}, + {file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:841aa21110a20dc1621e3dd9f922c64ca64dd1eb213c47267a2c324d823f6c8f"}, + {file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1"}, + {file = "netifaces-0.11.0.tar.gz", hash = "sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32"}, +] [[package]] name = "packaging" -version = "23.1" -requires_python = ">=3.7" +version = "24.2" +requires_python = ">=3.8" summary = "Core utilities for Python packages" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" requires_python = ">=3.8" summary = "plugin and hook calling mechanisms for python" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] [[package]] name = "prometheus-client" version = "0.19.0" requires_python = ">=3.8" summary = "Python client for the Prometheus monitoring system." +files = [ + {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, + {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"}, +] [[package]] name = "protobuf" -version = "4.22.3" -requires_python = ">=3.7" +version = "4.25.5" +requires_python = ">=3.8" summary = "" +files = [ + {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"}, + {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"}, + {file = "protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331"}, + {file = "protobuf-4.25.5-cp39-cp39-win32.whl", hash = "sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f"}, + {file = "protobuf-4.25.5-cp39-cp39-win_amd64.whl", hash = "sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45"}, + {file = "protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41"}, + {file = "protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +requires_python = ">=3.8" +summary = "C parser in Python" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] [[package]] name = "pytest" -version = "8.1.1" +version = "8.3.3" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" dependencies = [ @@ -75,257 +304,94 @@ dependencies = [ "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", "iniconfig", "packaging", - "pluggy<2.0,>=1.4", + "pluggy<2,>=1.5", "tomli>=1; python_version < \"3.11\"", ] +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] [[package]] name = "pyyaml" -version = "6.0.1" -requires_python = ">=3.6" +version = "6.0.2" +requires_python = ">=3.8" summary = "YAML parser and emitter for Python" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] [[package]] name = "setuptools" -version = "67.6.1" -requires_python = ">=3.7" +version = "75.6.0" +requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" +files = [ + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, +] [[package]] name = "tabulate" version = "0.9.0" requires_python = ">=3.7" summary = "Pretty-print tabular data" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] [[package]] name = "tomli" -version = "2.0.1" -requires_python = ">=3.7" +version = "2.1.0" +requires_python = ">=3.8" summary = "A lil' TOML parser" - -[metadata] -lock_version = "4.2" -cross_platform = true -groups = ["default", "dev", "test"] -content_hash = "sha256:a208e870ff545a083e7580ac5744c6d914a61b1e44eb075473e72f3db6750ca3" - -[metadata.files] -"colorama 0.4.6" = [ - {url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, -] -"exceptiongroup 1.1.2" = [ - {url = "https://files.pythonhosted.org/packages/fe/17/f43b7c9ccf399d72038042ee72785c305f6c6fdc6231942f8ab99d995742/exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, -] -"grpcio 1.53.2" = [ - {url = "https://files.pythonhosted.org/packages/05/71/fd97d7aca7b3d476de623073f89598ba06213340fe816efe0383b248061f/grpcio-1.53.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d9c51ca201326b49cfee38336c6e7dd1cb8a6b6d0dcf84aeaecbae310a736dbc"}, - {url = "https://files.pythonhosted.org/packages/0e/84/5dee051586b07acd0384550c7b67842900bcba97295d58ecde23df49c2db/grpcio-1.53.2-cp38-cp38-win_amd64.whl", hash = "sha256:b676c4365a5753bc8c49f922a5f88bdb5df6746c670a9d859d2ba2f5f97d9269"}, - {url = "https://files.pythonhosted.org/packages/0e/a7/03b9408c3a1204501bda1699b050b3bd74c95ccba01b2ef65b96fbf43cfd/grpcio-1.53.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9efbedc737ba342d8a2459afc9bd5c5df31adcdf774b772a4e663739f2cf0d06"}, - {url = "https://files.pythonhosted.org/packages/13/b9/072790ace42e9c8d0f7ed8cc56a33c11ed362e23dc8c73eb5ad2ca028aa4/grpcio-1.53.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:f9f7c0dd17f24e1774cc3a8df738246772994e853c28b28ed6ba7711ccf0abb4"}, - {url = "https://files.pythonhosted.org/packages/1b/18/dac3632611a671a101f6749a9b16bca3064f1f4d1d4d4090da1acd321094/grpcio-1.53.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df07843c8c0dc71a56d3af3dfe19165fb0d3af7d3354a72185f6fa1b4ac05cab"}, - {url = "https://files.pythonhosted.org/packages/22/40/5fd5ce6d5b5e890b9d6571114be8a6a5aa1d317bd779b29afcf528060f2f/grpcio-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:53d34cbf212f03634d74ba366d595b4a06a3b60fcc731eddbd6fd7ebe4acf981"}, - {url = "https://files.pythonhosted.org/packages/29/99/4bfd7575f903b24d4ca998f79bd49cc2d6afa819a9e4b5343eb2115c9d28/grpcio-1.53.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:431f864f2642a97d0aa8c6b606c307f03d22f919b1a226af90488426aed35809"}, - {url = "https://files.pythonhosted.org/packages/2e/3c/f3f0bcc42beb3b5e2b8284b54e8bf6c51e764fffcc3f839efea50284307b/grpcio-1.53.2-cp37-cp37m-win_amd64.whl", hash = "sha256:d406cf2f6ccf39883a24b048c448a37bac16939408c1b6fbb4d021f3cd961448"}, - {url = "https://files.pythonhosted.org/packages/30/98/96b6499fd5099ab6a2ab7ddabde4644fea064aafa41db8e5952fd6e49a07/grpcio-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:8166ac6671472d172cc0db50323b7a7504bd534de54aa31354465a00ca44409d"}, - {url = "https://files.pythonhosted.org/packages/31/02/816d17300481aee271a3c9bc13958af7a19653a967b2cadbea52e513cb2f/grpcio-1.53.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:69e99fe6bdc2cdacd04cef6b6585b00630d958c98e36d825de3eea406e15fb31"}, - {url = "https://files.pythonhosted.org/packages/37/ae/791921c114f2a8cebe3ded45938d7e161305b18d1247690b2a8d6196d316/grpcio-1.53.2-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:f14a82d12d53eb93298c35edf88d8c3ef37243b95f94dd3c75fddcba575d34ab"}, - {url = "https://files.pythonhosted.org/packages/3b/a1/652bbe3f6b62b246b03d00e6492a07b45967db8fbba30485323ab57458b5/grpcio-1.53.2-cp310-cp310-win_amd64.whl", hash = "sha256:5b49f372df33f5f84865aef5d46cacd23180b586c80e8cbe0ce149b96dfa8c4c"}, - {url = "https://files.pythonhosted.org/packages/42/6a/fc61080da07a0cd42794569ca6dc4cc4aad4ab15caf85481e2862e4da274/grpcio-1.53.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:1fcced1abb13cdb6a5d8b105765d30212a6cb29ab0dfb01eedecf2ff6c84371b"}, - {url = "https://files.pythonhosted.org/packages/43/7c/c5b709353b555437127189d0e8dbc6c65d8dbc7d0cd5554690be61cc6316/grpcio-1.53.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:80a8867746cff41c2db436dd9eea18ebbfcd0449d65b64b3ed3c995207898971"}, - {url = "https://files.pythonhosted.org/packages/49/50/82eea5269c5e69c208799cad6448ed36008617b19014ba797edb1620e9b2/grpcio-1.53.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0f76287d98ec79a38cba8292d0bdcd6ab9b9daf568dce1d53b9eb0135fc14d26"}, - {url = "https://files.pythonhosted.org/packages/4e/74/8caf7d6ee177aaa3b4d8dee7a0d74689264506726da52431a77f03bd237f/grpcio-1.53.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0e92dc6a85cd1de42527812ef1276095e62169d002d86c888b6e889fcda1dd29"}, - {url = "https://files.pythonhosted.org/packages/52/57/85a0055321a205530ca873e237508092ddcee9b59cd68e820283cb17f0f2/grpcio-1.53.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ea235cecb9df14b49a75cbd27a634683a96bb76576363407ec820ae454ce2b2"}, - {url = "https://files.pythonhosted.org/packages/53/70/6c50cffa387319e80689a41487fe3d604243bd3bc7057035782692e1e042/grpcio-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:1d1a320230e0d020880178b8eb453300bd57700b44c3744268370502e7376a9b"}, - {url = "https://files.pythonhosted.org/packages/56/19/16a81e3dddaa89fdd2c0589b1b6f2ec698e770fc8aa04fc794abcb90712e/grpcio-1.53.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1df931fbb4c36363d2cb985c2c26fda8f060b541a89c6c1191fdb59151a8c934"}, - {url = "https://files.pythonhosted.org/packages/56/c2/72585ea14b9bb6314ac3a66ccbff2ff1981f10f4a1d556062f79274c2281/grpcio-1.53.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b403c4ad22f3ba37c7720547d8888a1e4b74ad980a94332bbbc50330b623abc"}, - {url = "https://files.pythonhosted.org/packages/5b/bf/a618f8161c6b1d994b6739f6c36d30576649648fd57fe04e1dd0d5d55642/grpcio-1.53.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6275a54b41d6b1ec539b019bc3affaf6d05b0a0ba36af1a65b8a2810ef69e07d"}, - {url = "https://files.pythonhosted.org/packages/5d/9b/b341e3935b350e014a7fcb047f398145e89e24d59a8fb5413b837a286a4d/grpcio-1.53.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07b83c06e7d113044cf3da15ca52f578c5f3dca299af711e9a589c1b71eb8be5"}, - {url = "https://files.pythonhosted.org/packages/77/ca/04102d5ea1ac86948137e3161e701f31cb31e67f34d8f1cef37802e90e2a/grpcio-1.53.2-cp38-cp38-win32.whl", hash = "sha256:b16258a31269b97e26a08d71b5deb56499e86077d26e453fad8f6ec4c06fe666"}, - {url = "https://files.pythonhosted.org/packages/7c/02/9c112b966d26cc69c6e60aa8005ded6e7802597c6a147ae2ac6a21ec94ba/grpcio-1.53.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33f7678287ac330c94e25f96cdb951e0861e206115ba4d8ea66cf6546b1a09d0"}, - {url = "https://files.pythonhosted.org/packages/81/5a/24d5d08993ed178601db9691dad3c476e5303f90a8fde80329f6e62f5773/grpcio-1.53.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea6a20c5a732a27b64623d43614b3022e6fcfc081a75236b7f9aa069d2eaa4d"}, - {url = "https://files.pythonhosted.org/packages/8a/65/32f100de0f4e8eb260c8416886be1f5048091302cf6c1ccf51e898d22cae/grpcio-1.53.2-cp311-cp311-win32.whl", hash = "sha256:7b44ed75b9d67d17e5a098a0f99a8fd3e5861fd3c4eb54212277a0acdf298434"}, - {url = "https://files.pythonhosted.org/packages/94/e5/5f070c27e7851a97dd0aebdd8791ddb8273269aefc2e9a94b9856cdcfd33/grpcio-1.53.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7734d1b91f1f3b1f186debf8ec4d168ee088a54e8186c14d89a95f7e51d3198d"}, - {url = "https://files.pythonhosted.org/packages/9a/e1/a56dcd844a4ad96082b7fed4c4b9622d03bd33eca7505c2a927a4c1bca4b/grpcio-1.53.2-cp39-cp39-win_amd64.whl", hash = "sha256:ea84becb5cbd6a94a810c5214eb263ae57e915a9ed1bdcd5b4a6baf13d8c5177"}, - {url = "https://files.pythonhosted.org/packages/ac/42/e18ddb6aac03d9d6c2a478c23642f792c0c0ca76c91d443f47d549c407de/grpcio-1.53.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1deeb84bb344351434f999cea4704ac6f1e07b3d861e34c44b50d8afa06caaa1"}, - {url = "https://files.pythonhosted.org/packages/ac/8a/421ff1b4ae7b41ae486c11c1ac47f498f06eb5a5bc6fc73c2f7a9132cafd/grpcio-1.53.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:1af074f28a56425e4f4d99761708981543a27ae963f5b4b0a36ff71f3483479d"}, - {url = "https://files.pythonhosted.org/packages/b0/a8/fca7ba2bff41fc1841bc788fab3e57cdb64852d9b4ac395fc81d995ae9a8/grpcio-1.53.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:8fc7667564c8c15748354dea1bb4035c5118df4e9dc5154ccdb6e62a3e5a2bac"}, - {url = "https://files.pythonhosted.org/packages/c0/22/27cdd4eaaf3e250d1b0ab7f8e10262fafcc9ae1067013586b0843526fa69/grpcio-1.53.2-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:590c7206f764cfe37a65003a75977358e20919ed488f970935f54efa2741b497"}, - {url = "https://files.pythonhosted.org/packages/c2/52/549f29c0d41baab9642ab09916b81912f49e90a5c7d4dbaeb646502622b3/grpcio-1.53.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2b4f5671f9e88b7f51f54adda37a23277b7fdebd1557c47543b3e8a8044dd510"}, - {url = "https://files.pythonhosted.org/packages/c8/d8/7ac01cc692eaf752a000747aebba64f8142874a13de218ff0ab9b1e1a726/grpcio-1.53.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:18afdda2bbe0c615da4daff754cab0df9bbd859c415d85e7e741a2975b3208b4"}, - {url = "https://files.pythonhosted.org/packages/cc/77/44d5a25d45756a8b8b1d09b8ef7ef695c6edd8489e320488db1925917d8e/grpcio-1.53.2-cp39-cp39-win32.whl", hash = "sha256:7e6885a8431939f1ee547e965fa3cb801a518b83d3d3509e90dbef78f0b5fd29"}, - {url = "https://files.pythonhosted.org/packages/d4/2c/b05d13e8bd712fd6128b9c832dd87d7c9cb8873487479bb32e249d40a2ae/grpcio-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:712113946b303db9ae4245a13de213710367850a6c3c53530b70e87989feb8e0"}, - {url = "https://files.pythonhosted.org/packages/da/4a/f0444ac37a2bb120c41ed02970125814a991caa9b833386f8a85aea442cf/grpcio-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c63592103fded38b258f1e520ba8b0a7a0bbc397cddd6520a1f74dc4b5dec0"}, - {url = "https://files.pythonhosted.org/packages/e0/ac/6bf874a7f5d8576a657ae5b956006046b470491a6382db49aa4effb7818d/grpcio-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3b789472e9ef75d179295d0c6a1f7f0aefd08189cd1c822b068b0523365a1dbe"}, - {url = "https://files.pythonhosted.org/packages/e1/3d/8c3f10bbf2dd1fb77d3426b40132b53dc94a39d5b5f0555f800827c3719e/grpcio-1.53.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3bee217bda6b2c81d9e2866f523217135a03a007a89043eee074e93d76706b0"}, - {url = "https://files.pythonhosted.org/packages/e9/f6/ce087e6204f977a6435504c6e3d2e0aae899986d20da8ec6dae2413b1f7e/grpcio-1.53.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cbf1e3aaec3edf734ef90182363a395d234cd4790544be914cedbe1b9fec99a"}, - {url = "https://files.pythonhosted.org/packages/ec/dc/707d8bd3d71e26ef8beb04519bfd1f8111eac80fec065432f2222022d34b/grpcio-1.53.2-cp310-cp310-win32.whl", hash = "sha256:6be86e8d5cf47415968588e5dfbfb92ee8757fb41139584192b67050d1a72c58"}, - {url = "https://files.pythonhosted.org/packages/ee/4d/88efe77ffa641aa1b0c8b31fa7862d2a8450d0d7e71b3e0f56baa65c18e6/grpcio-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:f7e66d8b31ef2bada7029275debbe12c97397ec7ac70a659837a7b8a6a9dc916"}, - {url = "https://files.pythonhosted.org/packages/f8/54/8221fe0d2bc1f06e9c83885beef9679aac01df10691d9f716c1bed552c75/grpcio-1.53.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504af9e86ab01c9c33d8a452fe846aa931d024945f2e897537ccb8f7d76778ee"}, - {url = "https://files.pythonhosted.org/packages/ff/b9/2307da723e99f35909c35b227f64dd273f6c9f22744d90ee516864c730db/grpcio-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3761f9a6817e32898eaa5aecd0b0ad69d0c68ab45ea7bf206e8dc4548f025f0"}, -] -"grpcio-tools 1.53.2" = [ - {url = "https://files.pythonhosted.org/packages/07/01/6fc661d9b755af606340ba3a86cd53045d0677b6b048deaf17dc155975d5/grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:0c8bb2ac4f17b53cc4bbd51da87ee111704003a618fa6903edd6013aa0beffe3"}, - {url = "https://files.pythonhosted.org/packages/17/8a/293d81ca22c9dd981a033085dd8492c27ad79c4c675a298112772e21b05e/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ba8cdc56b713e6b27b2f5777e449b4617b549af6ab548aaf265eeda12a4ac6f"}, - {url = "https://files.pythonhosted.org/packages/17/f0/137600746a7223a0e8067d2c8daa8d04bc5809fccb45761b0f9beb4b8d64/grpcio_tools-1.53.2-cp311-cp311-win_amd64.whl", hash = "sha256:c57cd3d0ef5d2ac8cc0ffc7b9226e85364adf50e91aaf3c34589d15e574a7215"}, - {url = "https://files.pythonhosted.org/packages/18/e5/0bbcb76446bc07973985482912fb29086050ae3e5d57170cefa889df42e3/grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e438248bdd092bfa74ddec74de86808b952fe65b23911b68d649160a26449d90"}, - {url = "https://files.pythonhosted.org/packages/1b/47/27389c5d71a206c8fe2a8bd63c62da76e144423d5323dd609182666fe347/grpcio_tools-1.53.2-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:46c64e9defe703cd6d713871e3e5b93052e33b4270d6649fb807d25eacba7dcf"}, - {url = "https://files.pythonhosted.org/packages/25/2d/3742983b742543f12c94dcf1f1e1ab5dfea617efb3b117734148ac68a8c7/grpcio_tools-1.53.2-cp39-cp39-win32.whl", hash = "sha256:32e6921291586e897dbcdf54c1dbfb95c3bb2446b28b76dcbd85a01807712e4e"}, - {url = "https://files.pythonhosted.org/packages/2d/2b/1e2bf54c90b30bf63da467e853a7035d8f8ddf1543ec88cf566b0b48b30c/grpcio_tools-1.53.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e41438402d6ac3a291f4c1ae3b3adb7bb989c820b7671e3bdc598a75e8d65"}, - {url = "https://files.pythonhosted.org/packages/2d/69/67bf2591b3228323310179dfb5e81fbc1d3d565203f7bddeb0b99c22069c/grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0a24c1f0b03069290095d7d0467ef6b9db4a2ac6df505ac066025990f490dbb5"}, - {url = "https://files.pythonhosted.org/packages/2f/f7/b4bf3082e0bd867681dc4d3b10bf0e584546c0fbb56ee7f97c65182b3cfd/grpcio_tools-1.53.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:161f6ca5786dbabe451e80f520b767f244ff0559a91d9148b82f0a4cefa1968f"}, - {url = "https://files.pythonhosted.org/packages/30/52/5ca963fd6477d8cf029889fc3529276a999ae25a5cac5caafe1e2160b399/grpcio_tools-1.53.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:95a2563ff4928a71815815d8ab50ebc7143eaf9f69062e557e3dd9b1ce029167"}, - {url = "https://files.pythonhosted.org/packages/34/cc/86e16c75e9aed1c7191e878bd2ac6e274349e4a7073fabe0c86539be26a8/grpcio_tools-1.53.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:8d047f35c04a78176ad61a2336bfc13bc7d773bcaf4bdbf34420faa93f52a30f"}, - {url = "https://files.pythonhosted.org/packages/38/78/c1ea8f2ccba62e80075315ab01b21496ee815107ac13967d312f729f4297/grpcio_tools-1.53.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e5c4dce09a1f1bce8b135bf1738311b7b44a3628afcb4d6ebd8b0423f33dd49"}, - {url = "https://files.pythonhosted.org/packages/3f/33/01294f84c413e05a5d13c5648b883ecd44f5edacf9f989733cf2207b35ac/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:621e6aa0ee0ca6d24cd0dc0a3ea4e8dd585ee9a7c665f0b5247a08032d89ac9f"}, - {url = "https://files.pythonhosted.org/packages/43/8f/ee91cf09f72bf86e4784e8f030425d789e6984a8f7882fdef77d53dda8d9/grpcio_tools-1.53.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:968c94cb210da93d02c3d41605fc3400cdbd8e30e5ef5910638570a6d9b1be1d"}, - {url = "https://files.pythonhosted.org/packages/46/72/e146c0b7997b2c0effe277c5ff401896d5e2edc2e02b53c76334f3b683e9/grpcio_tools-1.53.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:f386874e79293f09d1871efbf177ef5248d82eb110a754b0f7680f3d2a7318ab"}, - {url = "https://files.pythonhosted.org/packages/47/b2/f96d9a44724f0eb3a8de382ceb5afcc01f5789ed4aee6fa4ec0f5db6ab10/grpcio_tools-1.53.2-cp310-cp310-win_amd64.whl", hash = "sha256:86e381816730c6459c0a4be780704098865083dcc66d4ea6f0603a7f3abbc376"}, - {url = "https://files.pythonhosted.org/packages/4b/f5/5e10e0657b82cd46cdc3dbfae8d47fdc424e8185fc1444948798276ea06e/grpcio_tools-1.53.2-cp311-cp311-win32.whl", hash = "sha256:f1bb5564e7dec518b163761771372a010514c1845cc8e96b6e84af3cac4fd864"}, - {url = "https://files.pythonhosted.org/packages/50/bf/c8ed62293c2db8d9759f0d655cb8afb72f4254e03e732069395b9d7a42d3/grpcio_tools-1.53.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a554d24b0500e3cd84623998a8c6ce44ded62ffaaa5ef9c1252dbe6fdb614edf"}, - {url = "https://files.pythonhosted.org/packages/52/16/3368bb67940a3dad015af104221b40e37420f81e87ce060d62d4d4f0fb53/grpcio_tools-1.53.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c72771f031db3187266bd5802ce5ef687d1e4082faadf6aab65d29ba20648410"}, - {url = "https://files.pythonhosted.org/packages/54/68/4359ffc4d6383d850604fbb7051d849633a983c3bc136cad35b679e314bd/grpcio_tools-1.53.2-cp38-cp38-win32.whl", hash = "sha256:c4533e6c208f6adba2de6eb093c4e338d75b6fb82f4307806a9b861dc71af555"}, - {url = "https://files.pythonhosted.org/packages/5d/6f/683e13b02b05b19030a9a8442adb037948048bc6b22928068b9c01bc3292/grpcio_tools-1.53.2-cp39-cp39-win_amd64.whl", hash = "sha256:82cbdec632c5ddefaf55077100313edacb99c3c72a3f1b7d224c6bb240709d11"}, - {url = "https://files.pythonhosted.org/packages/64/5d/93926be2744561c335dabde00098227fcdcc55e1c10811569114a18781d4/grpcio_tools-1.53.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:56dba5debe2d805d30a336302d696a32c8a8d7bd9951cb9eddbbc514f95a3afc"}, - {url = "https://files.pythonhosted.org/packages/6b/ca/f631e1d4684117f022793cd6f48ff9fc1e2d59ad4bcd79e8aec6d5d153df/grpcio_tools-1.53.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:f7104bd88c418f9d2e09105da6b2abc92aa0274ccbcb2237e11c21d33d09164e"}, - {url = "https://files.pythonhosted.org/packages/70/78/10f3decc485435efad896d1851bf0b37c58764760124b85084163cd316a3/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f073ee3d1088d54fd1da5df2f39ae8767397a6e60baaabbf22525e5dc86b759c"}, - {url = "https://files.pythonhosted.org/packages/7a/65/30c3214b8deb79d90de99c082fd957da88b5773531dbe24a636c5ee3a6e1/grpcio_tools-1.53.2-cp310-cp310-win32.whl", hash = "sha256:85e933f52e85476d70fddc0112952cfe8537166a3b05b41bde5eb9ae71cd2328"}, - {url = "https://files.pythonhosted.org/packages/81/c4/f5ac950149925676fb3e3616dd8a5510e2adb95698949fe132dd047ded2d/grpcio_tools-1.53.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ecf297f8fecdce591716794a1ec5212b03d8302452d6ea0a4f88479592e09bfa"}, - {url = "https://files.pythonhosted.org/packages/8f/55/cc40a32d8130ed2a6df648be5ebecf26ed2360b0955e2b8e3026013d1684/grpcio_tools-1.53.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f855784689e3162a9e1811299c7745f84a856d8085b8e34ae6db27318a28d42e"}, - {url = "https://files.pythonhosted.org/packages/94/4e/96dbe76e108968af8b367fb5b4c22efebd99211587ca7e6511cad32ca88a/grpcio_tools-1.53.2-cp38-cp38-win_amd64.whl", hash = "sha256:cb7fffed68628efa3a3df3f7a7fdebb3fd7162f287b9ab372f17c68da63ab368"}, - {url = "https://files.pythonhosted.org/packages/96/bf/92bd25b19ef9ba171536dcb5ce1b411af7c481d4b02d083049f06342891c/grpcio_tools-1.53.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccee441cbe40b2f40a8e1c1967fe71647b02914993e606dc1fd9ac216d8916a4"}, - {url = "https://files.pythonhosted.org/packages/97/93/43bbe6d371b34199ac878e14a732c2ead809c9dbfa7b84dfe4beac75667d/grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d27bbcb89e7dee2d5e03caffa48f9ecdbc1a0384e4d2bbd5691ab9902bf63c10"}, - {url = "https://files.pythonhosted.org/packages/9b/e5/5ed9acd22b9ea5aa7c29fca91d8e5e65e12f2633114a9da88c5eefc62a2a/grpcio_tools-1.53.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:049b16c36c3b0e9e52aa35dec6655000c97f5a26215322804d4149c5690997e4"}, - {url = "https://files.pythonhosted.org/packages/a2/d1/e85a0777d43aed5171be62b1f40ec9bf71e842ea41b94a84a87c404160cb/grpcio_tools-1.53.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:a71e2a881eb8e821b6f5eeab2ee450b56597000ec34bfcd0c35b666ad7e64eb9"}, - {url = "https://files.pythonhosted.org/packages/af/ea/29681ceb699e7d85e1a20b6617abd1c5f3593ec7269d9a95f3d77318a74a/grpcio_tools-1.53.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:aa53908aec5d2be30cfa50304aee60918d888918707731e444dbea672121731d"}, - {url = "https://files.pythonhosted.org/packages/be/99/c008310b54848e1220b1c919a6a741347795873d304ba73cbc5cf1da5edf/grpcio_tools-1.53.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556f6997fe369a6cfd230335c46cb89d5ac2be65c093b25b8a0e9bfee76cb705"}, - {url = "https://files.pythonhosted.org/packages/ce/04/13e2348348705665b0b54df4cf9f2309d7433e33469fb93e1e10aa8f4ec6/grpcio_tools-1.53.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1bebff9958c7efec5306a720dc37c1e7cb775cca136000448137e8a7a93162d3"}, - {url = "https://files.pythonhosted.org/packages/cf/64/1ae9d7d436b5cc8754a07659e0b58545e4ca8a884ab0f2535a04ad288d0d/grpcio_tools-1.53.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5980a7a9dcf8a49f4031dc18f9890a84ef85dc6b3b25b9d58f44d4eedb6d46b8"}, - {url = "https://files.pythonhosted.org/packages/d7/42/167e3c614df8ee5235441ab63883f964951c159624805baaf9d6fb2e260f/grpcio_tools-1.53.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7bc87ede62465510e621e4a84d6670c3e78d40b4285f4abf24a3cfc305153374"}, - {url = "https://files.pythonhosted.org/packages/d7/61/989f7aaa518cb9b4a892db6f58e4842702f3d942224a908485f8820fbfd5/grpcio_tools-1.53.2-cp37-cp37m-win_amd64.whl", hash = "sha256:20de66650c11c7c03956aed1e40cdb890be2a41a275ac0a3eb69111cc331ff6e"}, - {url = "https://files.pythonhosted.org/packages/da/30/fcb1b78cee6770fc3324e7094f2fe83fb2a4b2165b5513b8cdd52d14b025/grpcio_tools-1.53.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330ec5a90c56d8c90b7668b8e85228fd64d85fb7909525f559ba4471a3c84b8d"}, - {url = "https://files.pythonhosted.org/packages/e3/e7/ff4158a582c018960c606f5eea7f9866c004e7fd54ebe7852960c145d141/grpcio_tools-1.53.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2386165f2af6808d626d00b77d5642f32fd1c9e62e4918651e2cfdbc44493a68"}, - {url = "https://files.pythonhosted.org/packages/e8/4c/3bebfb60b13e451bf4878f99b0dd950415dc048b2ad8956fee1a52d3e9f6/grpcio_tools-1.53.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:9769bdb7be6749055418728625b314812a70086cd42ca96a09dc70ec7d2cbac1"}, - {url = "https://files.pythonhosted.org/packages/ea/e8/6b3e6230b85abe738a1e2eb4399dcf3cbb939aa62e5e74c476fa4d96f433/grpcio_tools-1.53.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:34d0227356b4dc2533b800f941a714100a35f93a97ddf44b25a4dcb3b7c8559b"}, - {url = "https://files.pythonhosted.org/packages/ee/26/18c09bd2a4ba37d602fed3c6369009e8099bf1172ed3f6e0f6bb45eda2b2/grpcio_tools-1.53.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:fa58925e12c82e86a9206533cc19d92df888f5878e07e08c56dca31c894d88a4"}, - {url = "https://files.pythonhosted.org/packages/f8/86/b45101e24e5cce9259d73ce2994dc33886a64e71735976e4707f9e1ef6c7/grpcio_tools-1.53.2-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:c0055ba3408f48b6d930b51cf565a072c7bdb7cacee32ef07c8997ae82f33f0e"}, -] -"iniconfig 2.0.0" = [ - {url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, -] -"netifaces 0.11.0" = [ - {url = "https://files.pythonhosted.org/packages/0a/0f/6cd5502483369f1141dbb5335f8db145d1684b6f3ada4964cfa6b24a4b62/netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:08e3f102a59f9eaef70948340aeb6c89bd09734e0dca0f3b82720305729f63ea"}, - {url = "https://files.pythonhosted.org/packages/0f/5a/e41d480218114fa48615b1f9edd9b3a952fbdce244d4d995d876b5a0d674/netifaces-0.11.0-cp27-cp27m-win32.whl", hash = "sha256:7dbb71ea26d304e78ccccf6faccef71bb27ea35e259fb883cfd7fd7b4f17ecb1"}, - {url = "https://files.pythonhosted.org/packages/13/d3/805fbf89548882361e6900cbb7cc50ad7dec7fab486c5513be49729d9c4e/netifaces-0.11.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:96c0fe9696398253f93482c84814f0e7290eee0bfec11563bd07d80d701280c3"}, - {url = "https://files.pythonhosted.org/packages/15/4c/8610767d17c0cc495ad4469ec9a7c46a29714f77b783a6c79124eb291854/netifaces-0.11.0-cp37-cp37m-win32.whl", hash = "sha256:8f7da24eab0d4184715d96208b38d373fd15c37b0dafb74756c638bd619ba150"}, - {url = "https://files.pythonhosted.org/packages/1a/29/fedda8ef898f12af8edde0355775e1564acf358261c974f2929e9307597e/netifaces-0.11.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5f9ca13babe4d845e400921973f6165a4c2f9f3379c7abfc7478160e25d196a4"}, - {url = "https://files.pythonhosted.org/packages/1d/b4/0ba3c00f8bbbd3328562d9e7158235ffe21968b88a21adf5614b019e5037/netifaces-0.11.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:3ecb3f37c31d5d51d2a4d935cfa81c9bc956687c6f5237021b36d6fdc2815b2c"}, - {url = "https://files.pythonhosted.org/packages/40/53/42ff106997354547cdde323b8d4ceb7308feeff32e1ba5a6e44f91807e75/netifaces-0.11.0-cp36-cp36m-win32.whl", hash = "sha256:2650beee182fed66617e18474b943e72e52f10a24dc8cac1db36c41ee9c041b7"}, - {url = "https://files.pythonhosted.org/packages/47/49/bf6c18d33682ec5cca15ba37f86d0a04979cfa15a9e51c86673c1831d04c/netifaces-0.11.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28f4bf3a1361ab3ed93c5ef360c8b7d4a4ae060176a3529e72e5e4ffc4afd8b0"}, - {url = "https://files.pythonhosted.org/packages/66/a4/78085681dc50af1c310791b30bf901455893cd7cfe98194e334fbc8dd6d9/netifaces-0.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0f6133ac02521270d9f7c490f0c8c60638ff4aec8338efeff10a1b51506abe85"}, - {url = "https://files.pythonhosted.org/packages/6b/07/613110af7b7856cf0bea173a866304f5476aba06f5ccf74c66acc73e36f1/netifaces-0.11.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1"}, - {url = "https://files.pythonhosted.org/packages/6e/9d/22ac139745145a3780ef7fe70d13727015b6819462044f0148eff912b532/netifaces-0.11.0-cp35-cp35m-win32.whl", hash = "sha256:c9a3a47cd3aaeb71e93e681d9816c56406ed755b9442e981b07e3618fb71d2ac"}, - {url = "https://files.pythonhosted.org/packages/73/b1/a8285eb5c37592fd202037f5ccac64faf59f990b3d85a881286881ef2ba4/netifaces-0.11.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:815eafdf8b8f2e61370afc6add6194bd5a7252ae44c667e96c4c1ecf418811e4"}, - {url = "https://files.pythonhosted.org/packages/77/6c/eb2b7c9dbbf6cd0148fda0215742346dc4d45b79f680500832e8c6457936/netifaces-0.11.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c92ff9ac7c2282009fe0dcb67ee3cd17978cffbe0c8f4b471c00fe4325c9b4d4"}, - {url = "https://files.pythonhosted.org/packages/89/5c/f44769f4afa88a1e8888eb81771a00a54227d40858f81bdf9f5fc1ec110c/netifaces-0.11.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:50721858c935a76b83dd0dd1ab472cad0a3ef540a1408057624604002fcfb45b"}, - {url = "https://files.pythonhosted.org/packages/89/b2/b0201e550aee1fb84de0a951bfb74a91b67d49a77d8cb5334b7585e40a77/netifaces-0.11.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c03fb2d4ef4e393f2e6ffc6376410a22a3544f164b336b3a355226653e5efd89"}, - {url = "https://files.pythonhosted.org/packages/95/61/762ab93c47553a4501fbac46bbe0e27c9e80a4a9d0696917ca9c5ab2d5b9/netifaces-0.11.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c37a1ca83825bc6f54dddf5277e9c65dec2f1b4d0ba44b8fd42bc30c91aa6ea1"}, - {url = "https://files.pythonhosted.org/packages/9f/29/7accc0545b1e39c9ac31b0074c197a5d7cfa9aca21a7e3f6aae65c145fe5/netifaces-0.11.0-cp38-cp38-win32.whl", hash = "sha256:d07b01c51b0b6ceb0f09fc48ec58debd99d2c8430b09e56651addeaf5de48048"}, - {url = "https://files.pythonhosted.org/packages/a9/65/eea4d675d8bb5acc243d44f93a4b5757fcda223a6817ef2864c1491fe60f/netifaces-0.11.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2479bb4bb50968089a7c045f24d120f37026d7e802ec134c4490eae994c729b5"}, - {url = "https://files.pythonhosted.org/packages/b8/cf/10693eb6d91d24916e5b12a498a5f13d150a0169922a344ffd1b4c006648/netifaces-0.11.0-cp34-cp34m-win32.whl", hash = "sha256:73ff21559675150d31deea8f1f8d7e9a9a7e4688732a94d71327082f517fc6b4"}, - {url = "https://files.pythonhosted.org/packages/c0/8c/b8d1e0bb4139e8b9b8acea7157c4106eb020ea25f943b364c763a0edba0a/netifaces-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54ff6624eb95b8a07e79aa8817288659af174e954cca24cdb0daeeddfc03c4ff"}, - {url = "https://files.pythonhosted.org/packages/c8/05/b41bbe076da2316f4521decf22346b1f20cb81484dc49424a9e58e6f50ae/netifaces-0.11.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:48324183af7f1bc44f5f197f3dad54a809ad1ef0c78baee2c88f16a5de02c4c9"}, - {url = "https://files.pythonhosted.org/packages/cb/08/b02f45cde4d0a6250ced65fad02ca08b48d0938ee1d64b9880f82b27ccab/netifaces-0.11.0-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:84e4d2e6973eccc52778735befc01638498781ce0e39aa2044ccfd2385c03246"}, - {url = "https://files.pythonhosted.org/packages/d7/6c/d24d9973e385fde1440f6bb83b481ac8d1627902021c6b405f9da3951348/netifaces-0.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:469fc61034f3daf095e02f9f1bbac07927b826c76b745207287bc594884cfd05"}, - {url = "https://files.pythonhosted.org/packages/d8/6f/3cb4f56b5298905e55fbbb8eb468e2db13375f74504d162bbaa9488a306e/netifaces-0.11.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:18917fbbdcb2d4f897153c5ddbb56b31fa6dd7c3fa9608b7e3c3a663df8206b5"}, - {url = "https://files.pythonhosted.org/packages/dd/51/316a0e27e015dff0573da8a7629b025eb2c10ebbe3aaf6a152039f233972/netifaces-0.11.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5be83986100ed1fdfa78f11ccff9e4757297735ac17391b95e17e74335c2047d"}, - {url = "https://files.pythonhosted.org/packages/e9/50/0c9f1703cf67ab6605ac7c03ddf8d0a1fb6862e5ad2be349c42b40381f12/netifaces-0.11.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eb4813b77d5df99903af4757ce980a98c4d702bbcb81f32a0b305a1537bdf0b1"}, - {url = "https://files.pythonhosted.org/packages/ea/14/57dcb067e83a6615b60d3635cdaa05b4b7c7fa8b21a1ae5fcab5513bda20/netifaces-0.11.0-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:aab1dbfdc55086c789f0eb37affccf47b895b98d490738b81f3b2360100426be"}, - {url = "https://files.pythonhosted.org/packages/f1/52/2e526c90b5636bfab54eb81c52f5b27810d0228e80fa1afac3444dd0cd77/netifaces-0.11.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:841aa21110a20dc1621e3dd9f922c64ca64dd1eb213c47267a2c324d823f6c8f"}, - {url = "https://files.pythonhosted.org/packages/fc/9f/4774897afc9d2bea18d3cb62d9a9815d03b9897387ad6e9b788a2acdf425/netifaces-0.11.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cb925e1ca024d6f9b4f9b01d83215fd00fe69d095d0255ff3f64bffda74025c8"}, -] -"packaging 23.1" = [ - {url = "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, -] -"pluggy 1.4.0" = [ - {url = "https://files.pythonhosted.org/packages/a5/5b/0cc789b59e8cc1bf288b38111d002d8c5917123194d45b29dcdac64723cc/pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, -] -"prometheus-client 0.19.0" = [ - {url = "https://files.pythonhosted.org/packages/bb/9f/ad934418c48d01269fc2af02229ff64bcf793fd5d7f8f82dc5e7ea7ef149/prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, -] -"protobuf 4.22.3" = [ - {url = "https://files.pythonhosted.org/packages/25/ca/79af03ceec0f9439d8fb5c2c8d99454c5c4f8c7fe00c8e7dbb280a8177c8/protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"}, - {url = "https://files.pythonhosted.org/packages/2f/db/42950497852aa35940a33e29118d8a2117fb20072bee08728f0948b70d7a/protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"}, - {url = "https://files.pythonhosted.org/packages/3d/df/045aa99824f00c732410463512c52c2137f0a8cb968be573e63c9a679a84/protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"}, - {url = "https://files.pythonhosted.org/packages/5b/98/1856887e6b5d707f06bad7a0a19a6f166819cde6df472cd463b3c54b4bc3/protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"}, - {url = "https://files.pythonhosted.org/packages/5d/d5/ce54c05165aee15a3353bff5e18891699ffe5c580a827500412c14097584/protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"}, - {url = "https://files.pythonhosted.org/packages/64/1a/607462fe9bd9815571b92510074a74f2012cca6b564ecc65a9d65ecec6da/protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"}, - {url = "https://files.pythonhosted.org/packages/6d/f6/695ae28e310ea84fbde27cbca851e3dbdc51fcef0f79f622166932b7b7e4/protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"}, - {url = "https://files.pythonhosted.org/packages/82/48/09fad23447675247e42f4262191505dbb4c9a67b372f593cd1465968c522/protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"}, - {url = "https://files.pythonhosted.org/packages/8f/fd/04c33233cbc10b183f19ac1d57f04e849bf62f80837aa332b95dfd2dc44a/protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"}, - {url = "https://files.pythonhosted.org/packages/d3/4b/ba25359a15db99b12b59c1d68ccbd0c1d2d4c0c874d9b92f19b5f89d8293/protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"}, - {url = "https://files.pythonhosted.org/packages/f4/fd/d8d309382c71c5e83a1920ae9840410396e595e3b36229d96e3ba755687e/protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"}, - {url = "https://files.pythonhosted.org/packages/f8/70/6291e75633eeaa24fed46c9f66091bec184644e6159f392ac32eb92b1f65/protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"}, -] -"pytest 8.1.1" = [ - {url = "https://files.pythonhosted.org/packages/4d/7e/c79cecfdb6aa85c6c2e3cf63afc56d0f165f24f5c66c03c695c4d9b84756/pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, -] -"pyyaml 6.0.1" = [ - {url = "https://files.pythonhosted.org/packages/02/74/b2320ebe006b6a521cf929c78f12a220b9db319b38165023623ed195654b/PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {url = "https://files.pythonhosted.org/packages/03/5c/c4671451b2f1d76ebe352c0945d4cd13500adb5d05f5a51ee296d80152f7/PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {url = "https://files.pythonhosted.org/packages/03/f7/4f8b71f3ce8cfb2c06e814aeda5b26ecc62ecb5cf85f5c8898be34e6eb6a/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {url = "https://files.pythonhosted.org/packages/06/92/e0224aa6ebf9dc54a06a4609da37da40bb08d126f5535d81bff6b417b2ae/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {url = "https://files.pythonhosted.org/packages/07/91/45dfd0ef821a7f41d9d0136ea3608bb5b1653e42fd56a7970532cb5c003f/PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {url = "https://files.pythonhosted.org/packages/0d/46/62ae77677e532c0af6c81ddd6f3dbc16bdcc1208b077457354442d220bfb/PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {url = "https://files.pythonhosted.org/packages/0e/88/21b2f16cb2123c1e9375f2c93486e35fdc86e63f02e274f0e99c589ef153/PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {url = "https://files.pythonhosted.org/packages/1e/ae/964ccb88a938f20ece5754878f182cfbd846924930d02d29d06af8d4c69e/PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {url = "https://files.pythonhosted.org/packages/24/62/7fcc372442ec8ea331da18c24b13710e010c5073ab851ef36bf9dacb283f/PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {url = "https://files.pythonhosted.org/packages/24/97/9b59b43431f98d01806b288532da38099cc6f2fea0f3d712e21e269c0279/PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {url = "https://files.pythonhosted.org/packages/27/d5/fb4f7a3c96af89c214387af42c76117d2c2a0a40576e217632548a6e1aff/PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {url = "https://files.pythonhosted.org/packages/28/09/55f715ddbf95a054b764b547f617e22f1d5e45d83905660e9a088078fe67/PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {url = "https://files.pythonhosted.org/packages/29/0f/9782fa5b10152abf033aec56a601177ead85ee03b57781f2d9fced09eefc/PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {url = "https://files.pythonhosted.org/packages/29/61/bf33c6c85c55bc45a29eee3195848ff2d518d84735eb0e2d8cb42e0d285e/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {url = "https://files.pythonhosted.org/packages/2b/9f/fbade56564ad486809c27b322d0f7e6a89c01f6b4fe208402e90d4443a99/PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {url = "https://files.pythonhosted.org/packages/2e/97/3e0e089ee85e840f4b15bfa00e4e63d84a3691ababbfea92d6f820ea6f21/PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {url = "https://files.pythonhosted.org/packages/40/da/a175a35cf5583580e90ac3e2a3dbca90e43011593ae62ce63f79d7b28d92/PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {url = "https://files.pythonhosted.org/packages/41/9a/1c4c51f1a0d2b6fd805973701ab0ec84d5e622c5aaa573b0e1157f132809/PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {url = "https://files.pythonhosted.org/packages/4a/4b/c71ef18ef83c82f99e6da8332910692af78ea32bd1d1d76c9787dfa36aea/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {url = "https://files.pythonhosted.org/packages/4d/f1/08f06159739254c8947899c9fc901241614195db15ba8802ff142237664c/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {url = "https://files.pythonhosted.org/packages/4f/78/77b40157b6cb5f2d3d31a3d9b2efd1ba3505371f76730d267e8b32cf4b7f/PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {url = "https://files.pythonhosted.org/packages/57/c5/5d09b66b41d549914802f482a2118d925d876dc2a35b2d127694c1345c34/PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {url = "https://files.pythonhosted.org/packages/5b/07/10033a403b23405a8fc48975444463d3d10a5c2736b7eb2550b07b367429/PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {url = "https://files.pythonhosted.org/packages/5e/94/7d5ee059dfb92ca9e62f4057dcdec9ac08a9e42679644854dc01177f8145/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {url = "https://files.pythonhosted.org/packages/62/2a/df7727c52e151f9e7b852d7d1580c37bd9e39b2f29568f0f81b29ed0abc2/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {url = "https://files.pythonhosted.org/packages/73/9c/766e78d1efc0d1fca637a6b62cea1b4510a7fb93617eb805223294fef681/PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {url = "https://files.pythonhosted.org/packages/7b/5e/efd033ab7199a0b2044dab3b9f7a4f6670e6a52c089de572e928d2873b06/PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {url = "https://files.pythonhosted.org/packages/7d/39/472f2554a0f1e825bd7c5afc11c817cd7a2f3657460f7159f691fbb37c51/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {url = "https://files.pythonhosted.org/packages/7f/5d/2779ea035ba1e533c32ed4a249b4e0448f583ba10830b21a3cddafe11a4e/PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {url = "https://files.pythonhosted.org/packages/84/02/404de95ced348b73dd84f70e15a41843d817ff8c1744516bf78358f2ffd2/PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {url = "https://files.pythonhosted.org/packages/84/4d/82704d1ab9290b03da94e6425f5e87396b999fd7eb8e08f3a92c158402bf/PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {url = "https://files.pythonhosted.org/packages/96/06/4beb652c0fe16834032e54f0956443d4cc797fe645527acee59e7deaa0a2/PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {url = "https://files.pythonhosted.org/packages/ac/6c/967d91a8edf98d2b2b01d149bd9e51b8f9fb527c98d80ebb60c6b21d60c4/PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {url = "https://files.pythonhosted.org/packages/b3/34/65bb4b2d7908044963ebf614fe0fdb080773fc7030d7e39c8d3eddcd4257/PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {url = "https://files.pythonhosted.org/packages/b4/33/720548182ffa8344418126017aa1d4ab4aeec9a2275f04ce3f3573d8ace8/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {url = "https://files.pythonhosted.org/packages/b6/a0/b6700da5d49e9fed49dc3243d3771b598dad07abb37cc32e524607f96adc/PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {url = "https://files.pythonhosted.org/packages/ba/91/090818dfa62e85181f3ae23dd1e8b7ea7f09684864a900cab72d29c57346/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {url = "https://files.pythonhosted.org/packages/bc/06/1b305bf6aa704343be85444c9d011f626c763abb40c0edc1cad13bfd7f86/PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {url = "https://files.pythonhosted.org/packages/c1/39/47ed4d65beec9ce07267b014be85ed9c204fa373515355d3efa62d19d892/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {url = "https://files.pythonhosted.org/packages/c7/4c/4a2908632fc980da6d918b9de9c1d9d7d7e70b2672b1ad5166ed27841ef7/PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {url = "https://files.pythonhosted.org/packages/c7/d1/02baa09d39b1bb1ebaf0d850d106d1bdcb47c91958557f471153c49dc03b/PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {url = "https://files.pythonhosted.org/packages/c8/6b/6600ac24725c7388255b2f5add93f91e58a5d7efaf4af244fdbcc11a541b/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {url = "https://files.pythonhosted.org/packages/cc/5c/fcabd17918348c7db2eeeb0575705aaf3f7ab1657f6ce29b2e31737dd5d1/PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {url = "https://files.pythonhosted.org/packages/d6/6a/439d1a6f834b9a9db16332ce16c4a96dd0e3970b65fe08cbecd1711eeb77/PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {url = "https://files.pythonhosted.org/packages/d7/8f/db62b0df635b9008fe90aa68424e99cee05e68b398740c8a666a98455589/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {url = "https://files.pythonhosted.org/packages/e1/a1/27bfac14b90adaaccf8c8289f441e9f76d94795ec1e7a8f134d9f2cb3d0b/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {url = "https://files.pythonhosted.org/packages/e5/31/ba812efa640a264dbefd258986a5e4e786230cb1ee4a9f54eb28ca01e14a/PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {url = "https://files.pythonhosted.org/packages/ec/0d/26fb23e8863e0aeaac0c64e03fd27367ad2ae3f3cccf3798ee98ce160368/PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {url = "https://files.pythonhosted.org/packages/f1/26/55e4f21db1f72eaef092015d9017c11510e7e6301c62a6cfee91295d13c6/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {url = "https://files.pythonhosted.org/packages/fe/88/def2e57fe740544f2eefb1645f1d6e0094f56c00f4eade708140b6137ead/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, -] -"setuptools 67.6.1" = [ - {url = "https://files.pythonhosted.org/packages/0b/fc/8781442def77b0aa22f63f266d4dadd486ebc0c5371d6290caf4320da4b7/setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, -] -"tabulate 0.9.0" = [ - {url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, -] -"tomli 2.0.1" = [ - {url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, +files = [ + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] diff --git a/pyproject.toml b/pyproject.toml index 3cfc316a..7c3e4f1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "pdm.backend" [project] name = "ceph-nvmeof" -version = "1.3.3" +version = "1.4.1" description = "Service to provide Ceph storage over NVMe-oF protocol" readme = "README.md" requires-python = "~=3.9" @@ -28,7 +28,8 @@ dependencies = [ "tabulate>=0.9.0", "pyyaml>=6.0.1", "prometheus_client ~= 0.19.0", - "netifaces ~= 0.11.0" + "netifaces ~= 0.11.0", + "cryptography>=43.0.3" ] [tool.pdm.scripts] diff --git a/tests/ceph-nvmeof.no-huge.conf b/tests/ceph-nvmeof.no-huge.conf index 55665105..e4c8dce2 100644 --- a/tests/ceph-nvmeof.no-huge.conf +++ b/tests/ceph-nvmeof.no-huge.conf @@ -17,6 +17,8 @@ state_update_notify = True state_update_timeout_in_msec = 2000 state_update_interval_sec = 5 enable_spdk_discovery_controller = False +enable_key_encryption = True +encryption_key = /etc/ceph/encryption.key #omap_file_lock_duration = 20 #omap_file_lock_retries = 30 #omap_file_lock_retry_sleep_interval = 1.0 @@ -29,7 +31,7 @@ enable_spdk_discovery_controller = False #verify_nqns = True #allowed_consecutive_spdk_ping_failures = 1 #spdk_ping_interval_in_seconds = 2.0 -#max_hosts_per_namespace = 1 +#max_hosts_per_namespace = 8 #max_namespaces_with_netmask = 1000 #max_subsystems = 128 #max_namespaces = 1024 diff --git a/tests/ceph-nvmeof.tls.conf b/tests/ceph-nvmeof.tls.conf index 14be0cc3..77f8a976 100644 --- a/tests/ceph-nvmeof.tls.conf +++ b/tests/ceph-nvmeof.tls.conf @@ -16,6 +16,8 @@ enable_auth = True state_update_notify = True state_update_interval_sec = 5 enable_spdk_discovery_controller = False +enable_key_encryption = True +encryption_key = /etc/ceph/encryption.key #omap_file_lock_duration = 20 #omap_file_lock_retries = 30 #omap_file_lock_retry_sleep_interval = 1.0 @@ -28,7 +30,7 @@ enable_spdk_discovery_controller = False #verify_nqns = True #allowed_consecutive_spdk_ping_failures = 1 #spdk_ping_interval_in_seconds = 2.0 -#max_hosts_per_namespace = 1 +#max_hosts_per_namespace = 8 #max_namespaces_with_netmask = 1000 #max_subsystems = 128 #max_namespaces = 1024 diff --git a/tests/ha/demo_test.sh b/tests/ha/demo_test.sh index 6f9374b2..29fac53d 100755 --- a/tests/ha/demo_test.sh +++ b/tests/ha/demo_test.sh @@ -557,6 +557,12 @@ function demo_bdevperf_dhchap() echo "Connecting using no PSK key should fail" exit 1 fi + + make -s exec SVC=ceph OPTS=-T CMD="rados --pool rbd listomapvals nvmeof.state" | grep "DHHC" + if [[ $? -eq 0 ]]; then + echo "DHCHAP keys should be encrypted in OMAP" + exit 1 + fi set -e echo "ℹ️ bdevperf tcp connect ip: $NVMEOF_IP_ADDRESS port: ${port4} nqn: ${NQN}host4 using PSK key" @@ -707,6 +713,17 @@ function demo_bdevperf_dhchap() dhchap_key_list=`make -s exec SVC=nvmeof OPTS=-T CMD="/usr/local/bin/spdk_rpc -s /var/tmp/spdk.sock keyring_get_keys"` [[ `echo $dhchap_key_list | jq -r '.[0]'` == "null" ]] + echo "ℹ️ disable key encryption" + sed -i 's/enable_key_encryption = True/enable_key_encryption = False/' ceph-nvmeof.conf + container_id=$(docker ps -q -f name=nvmeof) + docker restart ${container_id} + sleep 20 + cephnvmf_func subsystem add --subsystem ${NQN}3 --dhchap-key "${DHCHAP_KEY10}" + cephnvmf_func host add --subsystem ${NQN}3 --host-nqn ${NQN}host7 --dhchap-key "${DHCHAP_KEY11}" + cephnvmf_func host add --subsystem ${NQN}3 --host-nqn ${NQN}host8 --dhchap-key "${DHCHAP_KEY5}" + cephnvmf_func host add --subsystem ${NQN}3 --host-nqn ${NQN}host9 --dhchap-key "${DHCHAP_KEY6}" + make -s exec SVC=ceph OPTS=-T CMD="rados --pool rbd listomapvals nvmeof.state" | grep "DHHC" + return 0 } diff --git a/tests/test_cli.py b/tests/test_cli.py index 8559b8d4..9b7017aa 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -32,6 +32,7 @@ subsystem5 = "nqn.2016-06.io.spdk:cnode5" subsystem6 = "nqn.2016-06.io.spdk:cnode6" subsystem7 = "nqn.2016-06.io.spdk:cnode7" +subsystem8 = "nqn.2016-06.io.spdk:cnode8" discovery_nqn = "nqn.2014-08.org.nvmexpress.discovery" serial = "Ceph00000000000001" uuid = "948878ee-c3b2-4d58-a29b-2cff713fc02d" @@ -70,6 +71,7 @@ def gateway(config): port = config.getint("gateway", "port") config.config["gateway"]["group"] = group_name config.config["gateway"]["max_namespaces_with_netmask"] = "3" + config.config["gateway"]["max_hosts_per_namespace"] = "1" config.config["gateway"]["max_subsystems"] = "3" config.config["gateway"]["max_namespaces"] = "12" config.config["gateway"]["max_namespaces_per_subsystem"] = "11" @@ -212,6 +214,9 @@ def test_create_subsystem(self, caplog, gateway): assert f'"nqn": "{subsystem}"' in caplog.text assert f'"max_namespaces": 2049' in caplog.text caplog.clear() + cli(["subsystem", "add", "--subsystem", subsystem, "--max-namespaces", "2049", "--no-group-append"]) + assert f"Failure creating subsystem {subsystem}: Subsystem already exists" in caplog.text + caplog.clear() cli(["subsystem", "add", "--subsystem", subsystem2, "--serial-number", serial, "--no-group-append"]) assert f"Adding subsystem {subsystem2}: Successful" in caplog.text caplog.clear() @@ -256,6 +261,9 @@ def test_create_subsystem(self, caplog, gateway): assert subs_list.status == 0 assert subs_list.subsystems[0].nqn == subsystem assert subs_list.subsystems[1].nqn == subsystem2 + caplog.clear() + cli(["subsystem", "add", "--subsystem", subsystem8, "--serial-number", serial, "--no-group-append"]) + assert f"Failure creating subsystem {subsystem8}: Serial number {serial} is already used by subsystem {subsystem2}" in caplog.text def test_create_subsystem_with_discovery_nqn(self, caplog, gateway): caplog.clear() diff --git a/tests/test_cli_change_keys.py b/tests/test_cli_change_keys.py index e053c1a5..7f65f386 100644 --- a/tests/test_cli_change_keys.py +++ b/tests/test_cli_change_keys.py @@ -23,7 +23,6 @@ key2 = "DHHC-1:01:eNNXGjidEHHStbUi2Gmpps0JcnofReFfy+NaulguGgt327hz:" key3 = "DHHC-1:01:KD+sfH3/o2bRQoV0ESjBUywQlMnSaYpZISUbVa0k0nsWpNST:" key4 = "DHHC-1:01:x7ecfGgIdOEl+J5cJ9JcZHOS2By2Me6eDJUnrsT9MVrCWRYV:" -hostpsk1 = "NVMeTLSkey-1:01:YzrPElk4OYy1uUERriPwiiyEJE/+J5ckYpLB+5NHMsR2iBuT:" config = "ceph-nvmeof.conf" @pytest.fixture(scope="module") @@ -92,14 +91,14 @@ def test_change_host_key(caplog, two_gateways): assert f"Changing key for host {hostnqn1} on subsystem {subsystem}: Successful" in caplog.text assert f"Host {hostnqn1} has a DH-HMAC-CHAP key but subsystem {subsystem} has no key, a unidirectional authentication will be used" in caplog.text time.sleep(15) - assert f"Received request to change inband authentication key for host {hostnqn1} on subsystem {subsystem}, dhchap: {key2}, context: