# This file contains the Connector class for announcing combiner to the FEDn network via the discovery service (REST-API).
# The Connector class is used by the Combiner class in fedn/network/combiner/server.py.
# Once announced, the combiner will be able to receive controller requests from the controllerStub via gRPC.
# The discovery service will also add the combiner to the statestore.
#
#
import enum
import requests
from fedn.common.log_config import logger
[docs]
class Status(enum.Enum):
""" Enum for representing the status of a combiner announcement."""
Unassigned = 0
Assigned = 1
TryAgain = 2
UnAuthorized = 3
UnMatchedConfig = 4
[docs]
class ConnectorCombiner:
""" Connector for annnouncing combiner to the FEDn network.
:param host: host of discovery service
:type host: str
:param port: port of discovery service
:type port: int
:param myhost: host of combiner
:type myhost: str
:param fqdn: fully qualified domain name of combiner
:type fqdn: str
:param myport: port of combiner
:type myport: int
:param token: token for authentication
:type token: str
:param name: name of combiner
:type name: str
:param secure: True if https is used, False if http
:type secure: bool
:param verify: True if certificate is verified, False if not
:type verify: bool
"""
def __init__(self, host, port, myhost, fqdn, myport, token, name, secure=False, verify=False):
""" Initialize the ConnectorCombiner.
:param host: The host of the discovery service.
:type host: str
:param port: The port of the discovery service.
:type port: int
:param myhost: The host of the combiner.
:type myhost: str
:param fqdn: The fully qualified domain name of the combiner.
:type fqdn: str
:param myport: The port of the combiner.
:type myport: int
:param token: The token for the discovery service.
:type token: str
:param name: The name of the combiner.
:type name: str
:param secure: Use https for the connection to the discovery service.
:type secure: bool
:param verify: Verify the connection to the discovery service.
:type verify: bool
"""
self.host = host
self.fqdn = fqdn
self.port = port
self.myhost = myhost
self.myport = myport
self.token = token
self.name = name
self.secure = secure
self.verify = verify
# for https we assume a an ingress handles permanent redirect (308)
self.prefix = "http://"
if port:
self.connect_string = "{}{}:{}".format(
self.prefix, self.host, self.port)
else:
self.connect_string = "{}{}".format(
self.prefix, self.host)
logger.info("Setting connection string to {}".format(self.connect_string))
[docs]
def announce(self):
"""
Announce combiner to FEDn network via discovery service (REST-API).
:return: Tuple with announcement Status, FEDn network configuration if sucessful, else None.
:rtype: :class:`fedn.network.combiner.connect.Status`, str
"""
payload = {
"combiner_id": self.name,
"address": self.myhost,
"fqdn": self.fqdn,
"port": self.myport,
"secure_grpc": self.secure
}
try:
retval = requests.post(self.connect_string + '/add_combiner', json=payload,
verify=self.verify,
headers={'Authorization': 'Token {}'.format(self.token)})
except Exception:
return Status.Unassigned, {}
if retval.status_code == 400:
# Get error messange from response
reason = retval.json()['message']
return Status.UnMatchedConfig, reason
if retval.status_code == 401:
reason = "Unauthorized connection to reducer, make sure the correct token is set"
return Status.UnAuthorized, reason
if retval.status_code >= 200 and retval.status_code < 204:
if retval.json()['status'] == 'retry':
reason = retval.json()['message']
return Status.TryAgain, reason
return Status.Assigned, retval.json()
return Status.Unassigned, None