User guide
The flame_hub
module contains three different clients that are meant to be imported by a user:
With these clients it is possible to access the endpoints of the Hub auth
, core
and storage
APIs
respectively. The signature of the clients is always the same since they inherit from the BaseClient
class.
When initializing a client, there are some things to keep in mind.
You should provide an instance of either
PasswordAuth
orRobotAuth
to theauth
argument as these are the two main authentication schemes supported by the FLAME Hub.You can provide a custom
base_url
if you’re hosting your own instance of the FLAME Hub, otherwise the client will use the default publicly available Hub instance https://privateaim.dev to connect to.You should’nt set
client
explicitly unless you know what you’re doing. When providing any of the previous two arguments, a suitable client instance will be generated automatically.
Authentication functionalities are implemented in the flame_hub.auth
module. For further information, check out the
documentation about the authentication flows.
Handling resources
Among other things, each client implements six methods for each of its resources. Below you can find a description and
the naming pattern for each of the methods. RESOURCE_NAME
and RESOURCE_NAME_PLURAL
have to be replaced by either
the singular or plural form of a specific resource name following the
naming conventions of Python.
- get_RESOURCE_NAME(self, id: str | uuid.UUID | ResourceT, **params: Unpack[GetKwargs]) ResourceT | None
Takes an
id
and returns the corresponding resource orNone
if there is no resource with thatid
.id
can either be astr
, anUUID
or a resource of the exact type you are searching for. The last option is basically irrelevant unless the resource was updated in the meanwhile and you want to get the updated resource.
- get_RESOURCE_NAME_PLURAL(self, **params: Unpack[GetKwargs]) list[ResourceT]
Returns a list of the first
DEFAULT_PAGE_PARAMS["limit"]
resources. SeeDEFAULT_PAGE_PARAMS
for the default setting.
- find_RESOURCE_NAME_PLURAL(self, **params: Unpack[FindAllKwargs]) list[ResourceT]
Filters, sorts and pages resources and returns matching resources as a list. See
FindAllKwargs
for all possible keyword arguments and Finding resources for examples on how to find resources.
- create_RESOURCE_NAME(self, **params) ResourceT
Creates a new resource and returns it.
params
are keyword arguments that can be send to the Hub when creating a new resource of a specific type. To see what parameters can be specified on creation, have a look at the concrete create method or at the corresponding create model.
- update_RESOURCE_NAME(self, id: str | uuid.UUID | ResourceT, **params) ResourceT
Updates the resource that matches a given
id
.id
can either be astr
, anUUID
or a resource of the same type.params
are keyword arguments that can be send to the Hub when updating an already existing resource of a specific type. To see what parameters can be specified on update, have a look at the concrete update method or at the corresponding update model. Raises aHubAPIError
if there is no resource with thisid
.
- delete_RESOURCE_NAME(self, id: str | uuid.UUID | ResourceT)
Deletes the resource that matches a given
id
.id
can either be astr
, anUUID
or a resource of the same type. Raises aHubAPIError
if there is no resource with thisid
.
Hint
See ResourceT
for further information on the base resource type.
Note
Every resource model has an id
attribute. If you commit a resource instance as an id
to either a get,
update or delete method, the client will automatically use the id
attribute of the given resource.
Warning
Creation, deletion or update methods are not implemented for all resources since there is no endpoint on the Hub in some cases. Please check the API of the clients to see which methods exist.
Overview of implemented resources
AuthClient
realms
users
robots
permissions
roles
role permissions
user permissions
user roles
robot permissions
robot roles
CoreClient
registries
registry projects
nodes
master image groups
master images
master image event logs
projects
project nodes
analyses
analysis logs
analysis nodes
analysis node logs
analysis buckets
analysis bucket files
StorageClient
buckets
bucket files
Finding resources
In almost all scenarios, you will want to use find_RESOURCE_NAME_PLURAL()
over
get_RESOURCE_NAME_PLURAL()
methods because they offer to find multiple resources that match
certain criteria. To start off with an example, we create a core client and authorize it.
import flame_hub
auth = flame_hub.auth.PasswordAuth(
username="admin", password="start123", base_url="http://localhost:3000/auth/"
)
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)
The page
parameter enables control over the amount of returned results. You can define the limit and offset which
affects pagination. They default to limit=50
and offset=0
.
nodes_first_25 = core_client.find_nodes(page={"limit": 25})
nodes_next_10 = core_client.find_nodes(page={"limit": 10, "offset": 10})
assert nodes_first_25[10:20] == nodes_next_10
Note
core_client.find_nodes(page=DEFAULT_PAGE_PARAMS)
is functionally equivalent to
core_client.get_nodes()
. See DEFAULT_PAGE_PARAMS
for the default
setting.
The filter
parameter allows you to filter by any fields. You can perform exact matching, but also any other
operation supported by the FLAME Hub, including like and not queries and numeric greater than and less than
comparisons.
print(core_client.find_nodes(filter={"name": "my-node-42"}).pop().model_dump_json(indent=2))
{
"name": "my-node-42",
"id": "2f8fc7df-d5ff-484c-bfed-76b8f3c43afd",
...
}
You can also use the FilterOperator
enum class which contains all possible operators.
from flame_hub.types import FilterOperator
nodes_with_4_in_name = core_client.find_nodes(filter={"name": "~my-node-4"})
nodes_with_4_in_name_but_different = core_client.find_nodes(
filter={"name": (FilterOperator.like, "my-node-4")}
)
assert nodes_with_4_in_name == nodes_with_4_in_name_but_different
The sort
parameter allows you to define a field to sort by in either ascending or descending order. If order
is
left unset, the client will sort in ascending order by default.
nodes = core_client.find_nodes(sort={"by": "created_at"})
sedon = core_client.find_nodes(sort={"by": "created_at", "order": "descending"})
assert nodes == sedon[::-1]
See FindAllKwargs
for the API documentation of all possible parameters.
Optional fields
Some fields are not provided by default, such as the secret tied to a robot. You can explicitly request these fields with the fields keyword argument.
import flame_hub
auth = flame_hub.auth.PasswordAuth(
username="admin", password="start123", base_url="http://localhost:3000/auth/"
)
auth_client = flame_hub.AuthClient(base_url="http://localhost:3000/auth/", auth=auth)
system_robot = auth_client.find_robots(filter={"name": "system"}).pop()
assert system_robot.secret is None
You have to request secret
explicitly in order to get it.
system_robot = auth_client.find_robots(filter={"name": "system"}, fields="secret").pop()
print(system_robot.secret)
$2y$10$KUOKEwbbnaUDo41e7XBKGek4hggD6z6R95I69Cv3mTeBcx0hifBAC
If you are ever unsure which fields can be requested this way on a specific resource, use get_field_names()
function.
from flame_hub import get_field_names
from flame_hub.models import Robot
assert get_field_names(Robot) == ("secret",)
Meta information
Furthermore, it is possible to retrieve meta information for find and get methods via the meta
keyword argument.
When set to True
, methods return a model containing all received meta data as a second value.
import flame_hub
auth = flame_hub.auth.PasswordAuth(
username="admin", password="start123", base_url="http://localhost:3000/auth/"
)
auth_client = flame_hub.AuthClient(base_url="http://localhost:3000/auth/", auth=auth)
_, meta = auth_client.get_permissions(meta=True)
print(meta.model_dump_json(indent=2))
{
"total": 106,
"limit": 50,
"offset": 0
}
Nested resources
Some resources refer to other resources. For example, users are tied to a realm which is usually not sent back automatically. This applies to any other nested resource.
All clients will automatically fetch all nested resources if they are available. This means that you can usually save yourself extra API calls. Be aware that the client is not capable of fetching nested resources on any level deeper than the resource you are requesting.
import flame_hub
auth = flame_hub.auth.PasswordAuth(
username="admin", password="start123", base_url="http://localhost:3000/auth/"
)
auth_client = flame_hub.AuthClient(base_url="http://localhost:3000/auth/", auth=auth)
admin_user = auth_client.find_users(filter={"name": "admin"}).pop()
print(admin_user.id)
print(admin_user.realm.model_dump_json(indent=2))
794f2375-f043-4789-bd0c-e5534e8deeaa
{
"name": "master",
"display_name": null,
"description": null,
"id": "794f2375-f043-4789-bd0c-e5534e8deeaa",
"built_in": true,
"created_at": "2025-05-12T09:44:08.284000Z",
"updated_at": "2025-05-12T09:44:08.284000Z"
}
Since the realm ID is present, we can use the realm
property too. And just to be extremely sure, we verify that the
admin’s realm is the master realm.
master_realm = auth_client.find_realms(filter={"name": "master"}).pop()
assert admin_user.realm == master_realm
Handling exceptions
The flame_hub
module exports HubAPIError
which is a general error that is raised whenever the FLAME Hub
responds with an unexpected status code. All clients will try and put as much information into the raised error as
possible, including status code and additional information in the response body.
import flame_hub
from uuid import uuid4
auth = flame_hub.auth.PasswordAuth(
username="admin", password="start123", base_url="http://localhost:3000/auth/"
)
core_client = flame_hub.CoreClient(base_url="http://localhost:3000/core/", auth=auth)
try:
core_client.create_node(name="my-new-node", realm_id=str(uuid4()))
except flame_hub.HubAPIError as e:
print(e)
print(e.error_response.model_dump_json(indent=2))
received status code 400 (undefined): Can't find realm entity by realm_id
{
"status_code": 400,
"code": "undefined",
"message": "Can't find realm entity by realm_id"
}
In this example a HubAPIError
is raised because there is no realm with an ID that matches the dynamically
created ID. If the response body contains an error, it can be accessed with the error_response
property. Some errors
may also add additional fields which can also be accessed like this.
Models
The flame_hub.models
module contains all model definitions for resources emitted by the FLAME Hub. Use them at you
own discretion. They may change at any time.
Model classes whose names start with Update extend the special base class UpdateModel
which needs to
distinguish between properties being None
and being explicitly unset. UNSET
exists for this purpose, which is a sentinel value that should be used to mark a property as unset.
from flame_hub.models import UpdateNode, UNSET
update_node = UpdateNode(hidden=False, external_name=None, type=UNSET)
print(update_node.model_dump_json(indent=2, exclude_none=False, exclude_unset=True))
{
"hidden": false,
"external_name": null
}
Check out all implemented models here.
Types
The flame_hub.types
module contains type annotations that you might find useful when writing your own code. Check
out all implemented types here.