-
Notifications
You must be signed in to change notification settings - Fork 0
Instructions for Tenants
To ease the development of new tenants, a reference tenant has been provided in the repository in the folder src/FINALES2/tenants. Since the tenant communication with the server is done entirely through HTTP protocols, a tenant does not need to be implemented in Python as the reference tenant. Here a description of the core server interactions for a tenant are described
The registration of users is handled through the FINALES server admin, who will add users to a database with information received by email.
For registration send an email with the following information:
To: the admin
Subject: FINALES new user registration
Necessary information in email:
New user to be registered to FINALES with the following specifications:
username: "ExampleUsername"
password: "ExamplePassword"
Usergroup: NOT YET IMPLEMENTED
If the tenant has not made sure their capability is present in FINALES, first follow "How to add new schemas for my quantity and method" at https://github.com/BIG-MAP/FINALES2_schemas.
Once the respective capability is registered, create the JSON description of your tenant. To facilitate this process, it is recommended to base your tenant implementation on the Tenant class defined in the reference Tenant. The JSON description of the tenant can then be created by calling the tenant_object_to_json
method of the tenant object. The resulting JSON file will be saved as <tenant name>.json
in the folder, in from which the method was invoked.
The JSON file contains the definition of the tenant in the following format:
{
"name": "<tenant name>",
"limitations": [
{
"quantity": "<quantity served by the tenant",
"method": "<method provided by the tenant>",
"limitations": {
<a dictionary stating limitations for each parameter in the input schema of quantity-method pair>
}
}
],
"contact_person": "["<name/alias of contact person>"]"
}
The limitations dictionary is of the form {"<parameter name>": <limitations}
. Limitations are typically lists of objects of the same type as the parameter value. Floats and integers are treated separately as they allow to specify ranges of accepted values using a minimum and maximum value additional to specifying a list of acceptable values. This means:
parameter type | limitations type |
---|---|
str | list(str) |
dict | list(dict) |
list | list(list) |
int | list(int) or list({"min": ", "max": "}) or a mixed list of the two types of values |
float | list(float) or list({"min": ", "max": "}) or a mixed list of the two types of values |
The JSON file obtained for the tenant is subsequently sent via email to the FINALES administrator, who registers the tenant in the FINALES using this file by following the instructions given in the admin section of this Wiki under How-to register/alter_state of a tenant.
The FINALES administrator can register users in the server according to the instructions given in How-to add a new user.
Once a user is registered, the username and password can be used to authenticate by calling the endpoint /user_management/authenticate
and passing the username and password. The response of the endpoint contains a token and a token type, which need to be saved in an authentication header in the following format:
{
"accept": "application/json",
"Authorization": (
"<capitalized token type>"
"<access token>"
}
This authentication header is subsequently included in the headers
key when calling endpoints requiring authentication. Note that all endpoints in the FINALES except the authentication endpoint itself require user authentication and some of them require additional entries in the dictionary passed to the headers
key of their call. A frequently needed additional key-value pair is "Content-Type": "application/x-www-form-urlencoded"
.
Call the endpoint GET/capabilities/ which retrieves all capabilities currently in the MAP. You can filter for currently_available, which will allow you to also retrieve the capabilities that are registered but not active anymore. The endpoint returns a list of dictionaries with the capabilities with the information
[
# There will be a list of objects, each with a different (quantity, method) pair,
# for describing the different capabilities of the server
{
"quantity": str,
# this is the name of the quantity
"method": str,
# this is the name of the method used to obtain the quantity
"json_schema_specifications": dict,
# this is a json schema that describes what the dictionary of parameters
# for the method should look like
"json_schema_result_output": dict,
# this is a json schema that describes what the output dictionary in the
# posted results should look like
}
]
The endpoint GET/limitations/ exposes the limitations of all the tenants that are currently registered to specific capabilities in the MAP. This endpoint can showcase examples of how to define limitations. It is however especially relevant for optimisation tenants, who need the limitations of the capabilities to know what the limitations of the search space available in the MAP.
Through the post endpoint POST/request/ one can request a simulation/experiment with defined parameters for a quantity. Using the json structure
{
"quantity": "string",
"methods": [
"method1",
"method2"
],
"parameters": {
"method1": {},
"method2": {}
},
"tenant_uuid": "string"
}
Here methods is a list since several methods can be prompted to report the quantity. Since different methods need different input parameters, the parameters is a dict of dicts with method names as keys. Once a tenant post a request the server returns the uuid of the request. This can be used to track the specific request using GET/requests/{object_id}, to see if the status of the request has gone from pending --> (reserved, resolved). The original poster of the request can retract the request using the POST/{object_id}/update_status endpoint.
Assuming the tenant is registered to capabilities and ready to perform simulations/experiments in the MAP. To see if any pending request are currently available call GET/pending_requests/, where you can filter for both quantities and methods. Note that the tenant must check themselves whether or not the requests are within the defined limitations for the tenant.
If you have a request you wish to perform simulation/experiment for call the endpoint POST/{object_id}/update_status (with object_id being the uuid of the request). Here you can change the status for the request from 'pending' --> 'reserved'. This way the other tenants will not start to work on the same request.
When the request have been performed the data can be posted using POST/results. Here we pass the request_uuid in the HTTP call, like so
{
"data": {},
"quantity": "string",
"method": [
method1
],
"parameters": {
"method1": {}
},
"tenant_uuid": "string",
"request_uuid": "string"
}
The data field is checked to obey the structure of the capability the tenant is providing. The paramters stated here are the actual parameters used for the simulation/experiment which may differ from the original request. Once a result is posted, the original request is automatically changed to the state 'resolved'. Once posted the tenant will receive a uuid for the result.
For retrieving the posted results one can call GET/results/{object_id}, with the object_id being the result_uuid. It is also possible to retrieve all results through GET/results_requested/ where you can filter for quantity and method, which will return a list of all results.
If you have previous results relevant to the MAP you want to post without an initial request use POST/results/post_unsolicited_result/. Here you post the result without an intial request_uuid. The results will be posted and a request stating the same parameters will automatically be created and assigned with the status 'unsolicited'.