Connecting edges to a federation
It is always the edge that initiates connection with the server. To do this connection information such as address, port, host and cryptographic information is needed. This can be retrieved as a blob, a Base64 encoded string, in the client interface. The blob is then used to issue a connection request in the edge.
Connect using SA Studio
SA Studio comes with a default federation, containing a nameserver and a client, that can be reached on the web. In this section we describe how you connect to the SA Studio federation.
The steps for connecting to an SA Studio federation is to first generate a connection blob, and then to use that blob when connecting an edge to the federation.
Creating a connection blob
A connection blob can be created using the SA Studio GUI. Open SA Studio, navigate to the Devices symbol tab, and select Connect edge.
Under "Generate connection data for client named", write a name for the edge and press Ok. This will generate a connection blob in different formats intended for copying to the edge. This guide will use the raw configuration blob and paste it in different commands.
Make a note of the name used for generating the blob, as this will be required for connecting.
This showed how to create a connection blob in the SA Studio UI. How to manually generate connection blobs is described in the section Connecting edges to a nameserver.
When using the SA Studio Sandbox environment as a server, the connection information is reset at regular intervals. This is because the sandbox is not intended as a production environment. When the information is reset, a new connection has to be initiated by the edges, using a new blob.
Connecting the edge
Now we can use the connection blob to connect the edge to the SA Studio federation. We can either do this from within a running instance of SA Engine on the edge, or from a terminal on the edge. The following two sections shows examples of both approaches. More detailed information on how to connect edges to nameservers can be found in the section Connecting edges to a nameserver.
From within SA Engine
Launch SA Engine on your edge unit. The commands connect_using_config_blob
or reconnect_using_config_blob
can be used to connect to the nameserver using the generated blob.
The arguments are described in the doc string:
doc("connect_using_config_blob");
For example, to connect an instance as an edge and name it my-edge in the federation, with reconnection enabled:
reconnect_using_config_blob(<blob>,"my-edge",true);
When the connection is successful, the output will look something like this:
[Edge MY-EDGE running intially in INTERACTIVE mode]
[Connection (0/7) - No connection found]
[Connection (1/7) - Connecting as: my-edge@13.53.132.202:35021 with TLS]
[Connection (2/7) - Registered as "my-edge@13.53.132.202:35021"]
[Connection (3/7) - Connected to SERVER with: #[socket "13.53.132.202" 35021 SERVER 808 SECURE WS]]
[Connection (4/7) - Uplink opened: #[socket "13.53.132.202" 35021 SERVER 816 SECURE WS]]
[Connection (5/7) - Registered as edge]
[Connection (6/7) - Uplink socket registered with edge manager]
[Connection (7/7) - Established OK]
[Payload-connection - Established OK]
[Edge MY-EDGE waiting for query from SERVER...]
It is now possible to execute queries and deploy models to the edge from the SA Studio client.
From a terminal
When starting sa.engine
from a terminal, the -o
flag can be used to append osql code. SA Engine will then execute the supplied code directly after launching. This can be used to launch an SA Engine edge and connect it to a federation in one command.
sa.engine -o 'reconnect_using_config_blob(<blob>, <edge-name>, true);'
This construct is useful for setting up an edge to reconnect when it is rebooted. More information more about how to reconnect after reboot can be found in Run an edge as a service.
Connection stability
If the connection to the server is lost, for example if there is a network issue or server reboot, the edge will keep trying to reconnect at regular intervals until the server is available and connection can be re-established.
If the edge instance of SA Engine is closed, for example if the device is rebooted, the connection must be initiated again. Once an edge with a certain name has been connected, connecting it again will require using the reconnect_using_config_blob
command. As it is allowed to use reconnect for the first connection as well, this command is recommended for any setup where the connection is intended to last over time.
There can only be one instance connected with each name. To connect several edges to a federation, they must all have unique names.
If two or more edge instances connect with the same name, they will compete for the connection. This can be observed as lots of reconnection attempts in both instances.
Disconnecting an edge
To remove an edge running in INTERACTIVE mode (the default mode, see Edge modes for more information) from a federation you have to terminate the edge instance.
edge_cq("my-edge", "quit;");
If an edge is disconnected from the network, it will still be visible in the federation. The edge will be removed from the federation the first time a peer tries to access the edge.
Local federation
If the edge device is connected to a computer on the same local network, it is possible to set up a local federation in the computer and connect the edge to it. This can be useful to start developing on an edge before a server federation is ready, or before the edge has access to internet.
Quick start
Here we briefly cover the overall steps for setting up a local federation. For more detailed information we refer to the sections Starting a nameserver and Connecting edges to a nameserver.
On the computer, start SA Engine, either in a terminal window or in a client like VS Code. Run the following OSQL code.
start_nameserver("my_nameserver"); // start the nameserver
reregister("me"); // register this peer in the nameserver
other_peers(); // verify by listing all other peers, this
// will include the nameserver
my_local_ip(); // check the local ip to use in the edge
Now, on the edge device, run SA Engine from a terminal with the -e
flag.
sa.engine -e my-edge-name@<local-ip>
This will launch SA Engine as an edge and show the same connection information as when connecting with a blob.
To verify the connection in the computer, use listening_edges()
.
listening_edges();
This will list all edges that are registered in the federation (and only edges, no other peers).
Starting a nameserver
In this section we will describe in depth the different ways of starting a nameserver.
Start from a client
A nameserver can be started in SA Engine with the function start_nameserver(<description>)
, where description is a string describing the nameserver. The nameserver is started on the device the SA Engine client is running on. The following OSQL query starts a nameserver called "my-server" on the local machine.
start_server("my-server");
When a nameserver is started in this way, the client that started the nameserver will automatically connect to the nameserver. But the client is connected "anonymously" without a name. To register the client on the nameserver we need to use the reregister("peer-name")
query. The following OSQL query registers the client on the nameserver under the name "my-client".
reregister("my-client");
The nameserver listens to incoming connections on the default port 35021, or the port specified by the environment variable NAMESERVERPORT
. This port needs to be open in the firewall on the device if we want to connect edges to it over the network.
A nameserver can be configured to listen to other ports than the default port. To start a nameserver that listens to a custom port, simply use the string format "name:port-number"
. The following OSQL query starts a nameserver called "my-server" that listens to incoming connections on port 443.
start_server("my-server:443");
When starting a nameserver with a custom port number from within a client, the client does not automatically connect to the nameserver. Clients are configured to use the default port number for communicating with nameservers, so to connect the client we have to reregister the client with reregister("peer-name@server:port")
. The following OSQL query registers the client as "my-client" on a nameserver on the local host that listens to port 443.
reregister("my-client@localhost:443");
Starting a nameserver that listens to a custom port can be useful when connecting edges over a network that doesn't allow communication on the default port 35021.
Start from a terminal
A nameserver can be started directly in the terminal without starting a client. Simply start SA Engine with the flag -n server-name[:port]
. If no port number is provided, the nameserver will listen on the default port 35021 or the port specified by the environment variable NAMESERVERPORT
. The following command starts SA Engine as a nameserver with the name "my-server" that listens to port 443.
sa.engine -n my-server:443
This will run a nameserver without a client.
Convert a client to a nameserver
A client can also be converted into a nameserver. This is done by first configuring the client as a nameserver with the function nameserver(<description>)
. Then the nameserver is started with the function listen()
.
The following OSQL queries converts a client to a nameserver named "my-server" that listens to port 443.
nameserver("my-server:443");
listen();
This will lock the client since it is converted to a nameserver and is busy listening to incoming requests.
Nameserver description string
The nameserver description string has a variety of formats. The following table lists all formats of the nameserver description string.
Format | Description |
---|---|
'' | A nameserver with the default name NAMESERVER that listens on the default port 35021 or the port specified by the environment variable NAMESERVERPORT .. |
'name' | A nameserver with name NAME . The nameserver will still have the name NAMESERVER as alias. |
'name:port' | A nameserver with name NAME that listens to a custom port. |
':port' | A nameserver with the default name NAMESERVER that listens to a custom port. |
Connecting edges to a nameserver
In the previous sections we have briefly mentioned some ways to connect an edge to a federation. Here we go more in depth and give a more exhaustive description of the different ways to connect edges to servers.
From a terminal
SA Engine can be started as an edge by providing the -e
flag.
sa.engine -e edge-name[@server[:port]]
If only the edge name is provided, the edge will try to connect to a nameserver on the local machine on port 35021. If no nameserver is running, or if no nameserver is listening to the port, an error message will be displayed and the edge will try to reconnect every few seconds.
The following command starts SA Engine as an edge with the name "my-edge" and connects it to a nameserver on the local machine.
sa.engine -e my-edge
If the nameserver is running on a separate computer, we have to specify the IP or hostname of the computer hosting the nameserver.
For example, the following command starts SA Engine as an edge that connects to a nameserver listening to port 443 on a remote computer with IP 10.0.0.1.
sa.engine -e my-edge@10.0.0.1:443
If the port number is left out, the edge tries to connect to the nameserver on the default port 35021.
SA Engine can also be started as an edge from a terminal with the -o
flag and an OSQL query that connects to a nameserver. One way of doing this is by using the OSQL function reconnect_using_config_blob()
. This can be useful when setting up SA Engine edges to run as a service.
sa.engine -o 'reconnect_using_config_blob(<blob>, <edge-name>, true);'
How to connect to a nameserver with a "config blob" is covered in the Using a configuration blob section.
Using edge_listener
If we know the IP or hostname of the nameserver, we can use the OSQL function edge_listener()
to connect to the nameserver.
For example, the following OSQL query connects the SA Engine instance as an edge to a nameserver running on IP 10.0.0.1 and listening to port 443.
edge_listener("my-edge@10.0.0.1:443");
The format of the string is the same as the format for sa.engine -e
described earlier.
edge_listener("edge-name[@server[:port]]");
In fact, sa.engine -e <desc>
can be considered an alias for sa.engine -o 'edge_listener("<desc>")'
.
Using a configuration blob
The standard way of connecting an edge to a remote nameserver is to use what's called a configuration blob (or connection blob, or config blob).
A config blob is a Base64 encoded string that contains connection information, such as address, port, host and cryptographic information. The blob can be generated on a server and then used to issue a connection request from the edge. It is always the edge that initiates connection with the server.
A connection blob is generated by running get_connect_config_blob("<peer-name>")
on the server. The following OSQL query generates a connection blob for a peer named "my-edge".
get_connect_config_blob("<peer-name>");
Then, on the edge, the connection is requested by using one of the functions connect_using_config_blob()
or reconnect_using_config_blob()
. As described in the section Connection stability, it is recommended to always use reconnect_using_config_blob()
.
The following OSQL query connects SA Engine as an edge to the server (federation) that generated the connection blob.
reconnect_using_config_blob(<blob>, "my-edge", true);
Note that the edge name "my-edge" must be the same name that was used when generating the connection blob. The last parameter in the list is set to true
to register the peer as an edge instance. If this parameter is set to false
, the SA Engine instance will only be registered as a client in the federation and not an edge.
As previously mentioned, the connect config blob generated with get_connect_config_blob()
is a Base64 encoded string containing connection information. However, it is also possible to generate the connection information in plain text by running the get_connect_config("<peer-name>")
function on a server. For example, the following OSQL query generates a connect configuration for an edge named "my-edge".
get_connect_config("my-edge");
The typical output record looks something like this:
{
"subnet_addrs": [['13.53.186.70',35021],
['127.0.0.1',null,'255.0.0.0'],
['172.10.4.79',null,'255.255.254.0']],
"peer_hostname": ['13.53.186.70',35022],
"federation_address": 'http://13.53.186.70:35021',
"peer_name": 'my-edge',
"federation_common_name": '6D61676E75732E67656464614073747265616D616E616C797A652E636F6D',
"certificate_authority": '-----BEGIN CERTIFICATE-----
...
...
----END CERTIFICATE-----',
"token": '...'
}
You can use this connection config unencoded to connect to a nameserver with the function connect_using_config()
, but it is highly recommended to use the Base64 encoded blob to prevent the configuration from being sent in plain text.
The address information in "subnet_addrs" shows the IP addresses for all interfaces on the computer. This information is also available with the get_all_addrs()
function. This can be useful when determining the server IP, e.g., when connecting an edge using the sa.engine -e <name>@<server-ip>
format.
Running get_all_addrs()
in SA Studio should produce something similar to the following.
['13.53.186.70',35021]
['127.0.0.1',null,'255.0.0.0']
['172.10.4.79',null,'255.255.254.0']
Managing configuration blobs
SA Engine provides a convenient way of storing and reusing configuration blobs.
To store a configuration blob, use the federation:save()
command. This will create a named reference to the blob. The reference is stored permanently in a folder named federations
. This ensures that the reference remains available even after restarting SA Engine. The federations
folder is placed in the SA_HOME
folder, which is also where user models are stored.
federation:save(Charstring name,Charstring blob)
To use a stored configuration blob to connect, use federation:connect()
.
federation:connect(Charstring name,Charstring peername,Boolean reregister,Boolean as_edge)
name
is the name given to the federation reference.
peername
is the name the connecting instance will have in the federation, it should be the same as used when creating the blob. The name in the blob will be used.
reregister
should be true if reconnection is to be allowed, which is normally the case.
as_edge
should be true when connecting an edge and false when connecting a client.
Clients can also be connected using the graphical interface in VS Code.
To see what federations has been previously stored, use federation:list()
. This will return a list with the names of all stored federation references.
To remove a federation, navigate to the SA_HOME/federations
folder and remove the file.
Simulate edges
The intended use case for SA Engine is to have one edge instance running on each edge device. However, it is possible to launch several edge instances of SA Engine on the same computer and connect them to a federation. This can be used for the purpose of testing the server setup or to work on federated learning algorithms.
To start a new SA edge instance from inside SA Engine, use eg. start_edge("my-edge-name")
, or start several with eg. start_edges(["edge1", "edge2"])
To start a new SA edge instance from the command line, use eg. sa.engine -e "my-edge-name"
.