diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index bff65974..fe2ee97e 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -31,7 +31,7 @@ The Balena object can be configured with a dict of type Settings
```python
balena = Balena({
"balena_host": "balena-cloud.com",
- "api_version": "v6",
+ "api_version": "v7",
"device_actions_endpoint_version": "v1",
"data_directory": "/home/example/.balena",
"image_cache_time": str(1 * 1000 * 60 * 60 * 24 * 7), # 1 week
@@ -91,7 +91,6 @@ hesitate to open an issue in GitHub](https://github.com/balena-io/balena-sdk-pyt
- [get_all_by_organization(org_handle_or_id, options)](#application.get_all_by_organization) ⇒ [List[TypeApplication]
](#typeapplication)
- [get_all_directly_accessible(options)](#application.get_all_directly_accessible) ⇒ [List[TypeApplication]
](#typeapplication)
- [get_by_name(app_name, options, context)](#application.get_by_name) ⇒ [TypeApplication
](#typeapplication)
- - [get_by_owner(app_name, owner, options)](#application.get_by_owner) ⇒ [TypeApplication
](#typeapplication)
- [get_dashboard_url(app_id)](#application.get_dashboard_url) ⇒ str
- [get_directly_accessible(slug_or_uuid_or_id, options)](#application.get_directly_accessible) ⇒ [TypeApplication
](#typeapplication)
- [get_id(slug_or_uuid_or_id)](#application.get_id) ⇒ int
@@ -281,6 +280,7 @@ hesitate to open an issue in GitHub](https://github.com/balena-io/balena-sdk-pyt
- [get_config(slug_or_uuid_or_id, options)](#deviceos.get_config) ⇒ None
- [get_download_size(device_type, version)](#deviceos.get_download_size) ⇒ float
- [get_max_satisfying_version(device_type, version_or_range, os_type)](#deviceos.get_max_satisfying_version) ⇒ Optional[str]
+ - [get_supervisor_releases_for_cpu_architecture(cpu_architecture_slug_or_id, options)](#deviceos.get_supervisor_releases_for_cpu_architecture) ⇒ [List[ReleaseType]
](#releasetype)
- [get_supported_os_update_versions(device_type, current_version)](#deviceos.get_supported_os_update_versions) ⇒ None
- [is_architecture_compatible_with(os_architecture, application_architecture)](#deviceos.is_architecture_compatible_with) ⇒ None
- [is_supported_os_update(device_type, current_version, target_version)](#deviceos.is_supported_os_update) ⇒ bool
@@ -502,24 +502,6 @@ Get all applications directly accessible by the user
>>> balena.models.application.get("myapp")
```
-
-### Function: get_by_owner(app_name, owner, options) ⇒ [TypeApplication
](#typeapplication)
-
-Get a single application using the appname and the handle of the owning organization.
-
-#### Args:
- app_name (str): application name.
- owner (str): The handle of the owning organization.
- options (AnyObject): extra pine options to use.
-
-#### Returns:
- TypeApplication: application info.
-
-#### Examples:
-```python
->>> balena.models.application.get_by_owner('foo', 'my_org')
-```
-
### Function: get_dashboard_url(app_id) ⇒ str
@@ -1943,11 +1925,9 @@ Note a device.
### Function: set_supervisor_release(uuid_or_id, supervisor_version_or_id) ⇒ None
Set a specific device to run a particular supervisor release.
-
#### Args:
uuid_or_id (Union[str, int]): device uuid (string) or id (int)
supervisor_version_or_id (Union[str, int]): the version of a released supervisor (string) or id (number)
-
#### Examples:
```python
>>> balena.models.device.set_supervisor_release('f55dcdd9ad', 'v13.0.0')
@@ -3135,6 +3115,26 @@ Get OS download size estimate. Currently only the raw (uncompressed) size is rep
#### Returns:
float: OS image download size, in bytes.
+
+### Function: get_supervisor_releases_for_cpu_architecture(cpu_architecture_slug_or_id, options) ⇒ [List[ReleaseType]
](#releasetype)
+
+Returns the Releases of the supervisor for the CPU Architecture
+
+#### Args:
+ cpu_architecture_slug_or_id (Union[str, int]): The slug (string) or id (number) for the CPU Architecture.
+ options (AnyObject): extra pine options to use.
+
+#### Returns:
+ ReleaseType: release info.
+
+
+Example:
+ results = balena.models.os.get_supervisor_releases_for_cpu_architecture('aarch64');
+ results = balena.models.os.get_supervisor_releases_for_cpu_architecture(
+ 'aarch64',
+ { $filter: { raw_version: '12.11.0' } },
+ );
+
### Function: get_supported_os_update_versions(device_type, current_version) ⇒ None
@@ -4175,7 +4175,7 @@ The name must be a string; the optional doc argument can have any type.
"start_timestamp": str,
"end_timestamp": str,
"push_timestamp": str,
- "image_size": int,
+ "image_size": str,
"dockerfile": str,
"error_message": str,
"is_a_build_of__service": Union[List[ServiceType], PineDeferred],
@@ -4367,7 +4367,9 @@ The name must be a string; the optional doc argument can have any type.
"release_image": Optional[List[ReleaseImageType]],
"should_be_running_on__application": Optional[List[TypeApplication]],
"is_running_on__device": Optional[List[TypeDevice]],
- "should_be_running_on__device": Optional[List[TypeDevice]],
+ "is_pinned_to__device": Optional[List[TypeDevice]],
+ "should_operate__device": Optional[List[TypeDevice]],
+ "should_manage__device": Optional[List[TypeDevice]],
"release_tag": Optional[List[BaseTagType]]
}
```
@@ -4427,7 +4429,9 @@ The name must be a string; the optional doc argument can have any type.
"release_image": Optional[List[ReleaseImageType]],
"should_be_running_on__application": Optional[List[TypeApplication]],
"is_running_on__device": Optional[List[TypeDevice]],
- "should_be_running_on__device": Optional[List[TypeDevice]],
+ "is_pinned_to__device": Optional[List[TypeDevice]],
+ "should_operate__device": Optional[List[TypeDevice]],
+ "should_manage__device": Optional[List[TypeDevice]],
"release_tag": Optional[List[BaseTagType]],
"images": List[ImageBasicInfoType],
"user": BasicUserInfoType
@@ -4479,22 +4483,6 @@ The name must be a string; the optional doc argument can have any type.
```
-### SupervisorReleaseType
-
-
-```python
-{
- "created_at": str,
- "id": int,
- "supervisor_version": str,
- "image_name": str,
- "is_public": bool,
- "note": Optional[str],
- "is_for__device_type": Union[List[DeviceTypeType], PineDeferred]
-}
-```
-
-
### TeamApplicationAccessType
@@ -4544,7 +4532,7 @@ The name must be a string; the optional doc argument can have any type.
"id": int,
"created_at": str,
"app_name": str,
- "actor": Union[List[ActorType], int],
+ "actor": Union[List[ActorType], PineDeferred],
"slug": str,
"uuid": str,
"is_accessible_by_support_until__date": str,
@@ -4586,7 +4574,7 @@ The name must be a string; the optional doc argument can have any type.
"id": int,
"created_at": str,
"app_name": str,
- "actor": Union[List[ActorType], int],
+ "actor": Union[List[ActorType], PineDeferred],
"slug": str,
"uuid": str,
"is_accessible_by_support_until__date": str,
@@ -4641,7 +4629,7 @@ The name must be a string; the optional doc argument can have any type.
```python
{
"id": int,
- "actor": Union[List[ActorType], int],
+ "actor": Union[List[ActorType], PineDeferred],
"created_at": str,
"modified_at": str,
"custom_latitude": str,
@@ -4669,12 +4657,9 @@ The name must be a string; the optional doc argument can have any type.
"os_version": str,
"provisioning_progress": int,
"provisioning_state": str,
- "state": TypeDeviceState,
"status": str,
- "status_sort_index": int,
"supervisor_version": str,
"uuid": str,
- "vpn_address": str,
"api_heartbeat_state": Literal["online", "offline", "timeout", "unknown"],
"memory_usage": int,
"memory_total": int,
@@ -4685,15 +4670,16 @@ The name must be a string; the optional doc argument can have any type.
"cpu_temp": int,
"cpu_id": str,
"is_undervolted": bool,
- "overall_status": Any,
+ "overall_status": Literal["configuring", "inactive", "post-provisioning", "updating", "operational", "disconnected", "reduced-functionality"],
"overall_progress": int,
"is_of__device_type": Union[List[DeviceTypeType], PineDeferred],
"belongs_to__application": Union[List[TypeApplication], PineDeferred],
"belongs_to__user": Union[List[UserType], PineDeferred, None],
"is_running__release": Union[List[ReleaseType], PineDeferred, None],
- "should_be_running__release": Union[List[ReleaseType], PineDeferred, None],
+ "is_pinned_on__release": Union[List[ReleaseType], PineDeferred, None],
"is_managed_by__service_instance": Union[List[ServiceInstanceType], PineDeferred, None],
- "should_be_managed_by__supervisor_release": Union[List[SupervisorReleaseType], PineDeferred, None],
+ "should_be_operated_by__release": Union[List[ReleaseType], PineDeferred, None],
+ "should_be_managed_by__release": Union[List[ReleaseType], PineDeferred, None],
"device_config_variable": Optional[List[EnvironmentVariableBase]],
"device_environment_variable": Optional[List[EnvironmentVariableBase]],
"device_tag": Optional[List[BaseTagType]],
@@ -4703,24 +4689,13 @@ The name must be a string; the optional doc argument can have any type.
```
-### TypeDeviceState
-
-
-```python
-{
- "key": str,
- "name": str
-}
-```
-
-
### TypeDeviceWithServices
```python
{
"id": int,
- "actor": Union[List[ActorType], int],
+ "actor": Union[List[ActorType], PineDeferred],
"created_at": str,
"modified_at": str,
"custom_latitude": str,
@@ -4748,12 +4723,9 @@ The name must be a string; the optional doc argument can have any type.
"os_version": str,
"provisioning_progress": int,
"provisioning_state": str,
- "state": TypeDeviceState,
"status": str,
- "status_sort_index": int,
"supervisor_version": str,
"uuid": str,
- "vpn_address": str,
"api_heartbeat_state": Literal["online", "offline", "timeout", "unknown"],
"memory_usage": int,
"memory_total": int,
@@ -4764,15 +4736,16 @@ The name must be a string; the optional doc argument can have any type.
"cpu_temp": int,
"cpu_id": str,
"is_undervolted": bool,
- "overall_status": Any,
+ "overall_status": Literal["configuring", "inactive", "post-provisioning", "updating", "operational", "disconnected", "reduced-functionality"],
"overall_progress": int,
"is_of__device_type": Union[List[DeviceTypeType], PineDeferred],
"belongs_to__application": Union[List[TypeApplication], PineDeferred],
"belongs_to__user": Union[List[UserType], PineDeferred, None],
"is_running__release": Union[List[ReleaseType], PineDeferred, None],
- "should_be_running__release": Union[List[ReleaseType], PineDeferred, None],
+ "is_pinned_on__release": Union[List[ReleaseType], PineDeferred, None],
"is_managed_by__service_instance": Union[List[ServiceInstanceType], PineDeferred, None],
- "should_be_managed_by__supervisor_release": Union[List[SupervisorReleaseType], PineDeferred, None],
+ "should_be_operated_by__release": Union[List[ReleaseType], PineDeferred, None],
+ "should_be_managed_by__release": Union[List[ReleaseType], PineDeferred, None],
"device_config_variable": Optional[List[EnvironmentVariableBase]],
"device_environment_variable": Optional[List[EnvironmentVariableBase]],
"device_tag": Optional[List[BaseTagType]],
@@ -4809,7 +4782,7 @@ The name must be a string; the optional doc argument can have any type.
```python
{
"id": int,
- "actor": Union[List[ActorType], int],
+ "actor": Union[List[ActorType], PineDeferred],
"created_at": str,
"username": str,
"organization_membership": Optional[List[OrganizationMembershipType]],
diff --git a/balena/__init__.py b/balena/__init__.py
index 9b4e1fd4..8eac56e8 100644
--- a/balena/__init__.py
+++ b/balena/__init__.py
@@ -30,7 +30,7 @@
```python
balena = Balena({
"balena_host": "balena-cloud.com",
- "api_version": "v6",
+ "api_version": "v7",
"device_actions_endpoint_version": "v1",
"data_directory": "/home/example/.balena",
"image_cache_time": str(1 * 1000 * 60 * 60 * 24 * 7), # 1 week
diff --git a/balena/models/api_key.py b/balena/models/api_key.py
index f352006b..2f9b684a 100644
--- a/balena/models/api_key.py
+++ b/balena/models/api_key.py
@@ -134,8 +134,8 @@ def get_provisioning_api_keys_by_application(
>>> balena.models.api_key.get_provisioning_api_keys_by_application("myorg/myapp")
"""
- app = self.__application.get(slug_or_uuid_or_id, {"$select": "actor"})
- return self.get_all(merge({"$filter": {"is_of__actor": app.get("actor")}}, options))
+ actor_id = self.__application.get(slug_or_uuid_or_id, {"$select": "actor"})["actor"]["__id"]
+ return self.get_all(merge({"$filter": {"is_of__actor": actor_id}}, options))
def get_device_api_keys_by_device(self, uuid_or_id: Union[str, int], options: AnyObject = {}) -> List[APIKeyType]:
"""
@@ -150,8 +150,8 @@ def get_device_api_keys_by_device(self, uuid_or_id: Union[str, int], options: An
>>> balena.models.api_key.get_device_api_keys_by_device(1111386)
"""
- dev = self.__device.get(uuid_or_id, {"$select": "actor"})
- return self.get_all(merge({"$filter": {"is_of__actor": dev["actor"]}}, options))
+ actor_id = self.__device.get(uuid_or_id, {"$select": "actor"})["actor"]["__id"]
+ return self.get_all(merge({"$filter": {"is_of__actor": actor_id}}, options))
def get_all_named_user_api_keys(self, options: AnyObject = {}) -> List[APIKeyType]:
"""
diff --git a/balena/models/application.py b/balena/models/application.py
index 53c92935..729bdf23 100644
--- a/balena/models/application.py
+++ b/balena/models/application.py
@@ -2,7 +2,6 @@
from math import isinf
from typing import List, Literal, Optional, Union, cast
from urllib.parse import urljoin
-from deprecated import deprecated
from .. import exceptions
from ..balena_auth import request
@@ -403,37 +402,6 @@ def get_all_by_organization(
}
)
- @deprecated("get_by_owner will be removed in a future release, use get_all_by_organization instead")
- def get_by_owner(self, app_name: str, owner: str, options: AnyObject = {}) -> TypeApplication:
- """
- Get a single application using the appname and the handle of the owning organization.
-
- Args:
- app_name (str): application name.
- owner (str): The handle of the owning organization.
- options (AnyObject): extra pine options to use.
-
- Returns:
- TypeApplication: application info.
-
- Examples:
- >>> balena.models.application.get_by_owner('foo', 'my_org')
- """
-
- slug = f"{owner.lower()}/{app_name.lower()}"
- app = self.__pine.get(
- {
- "resource": "application",
- "id": {"slug": slug},
- "options": options,
- }
- )
-
- if app is None:
- raise exceptions.ApplicationNotFound(slug)
-
- return app
-
def has(self, slug_or_uuid_or_id: Union[str, int]) -> bool:
"""
Check if an application exists.
diff --git a/balena/models/device.py b/balena/models/device.py
index 5aa1c122..c304a0d2 100644
--- a/balena/models/device.py
+++ b/balena/models/device.py
@@ -83,19 +83,6 @@ class SupervisorStateType(TypedDict):
download_progress: str
-class DeviceStatus:
- """
- Balena device statuses.
- """
-
- IDLE = "Idle"
- CONFIGURING = "Configuring"
- UPDATING = "Updating"
- OFFLINE = "Offline"
- POST_PROVISIONING = "Post Provisioning"
- INACTIVE = "Inactive"
-
-
class Device:
"""
This class implements device model for balena python SDK.
@@ -1620,7 +1607,7 @@ def is_tracking_application_release(self, uuid_or_id: Union[str, int]) -> bool:
bool: is tracking the current application release.
"""
- return not bool(self.get(uuid_or_id, {"$select": "should_be_running__release"})["should_be_running__release"])
+ return not bool(self.get(uuid_or_id, {"$select": "is_pinned_on__release"})["is_pinned_on__release"])
# TODO: enable device batching
def pin_to_release(
@@ -1667,7 +1654,7 @@ def pin_to_release(
{
"resource": "device",
"id": device["id"],
- "body": {"should_be_running__release": release["id"]},
+ "body": {"is_pinned_on__release": release["id"]},
}
)
@@ -1679,7 +1666,7 @@ def track_application_release(self, uuid_or_id_or_ids: Union[str, int, List[int]
uuid_or_id_or_ids (Union[str, int, List[int]]): device uuid (str) or id (int) or ids (List[int])
"""
- self.__set(uuid_or_id_or_ids, {"should_be_running__release": None})
+ self.__set(uuid_or_id_or_ids, {"is_pinned_on__release": None})
# TODO: enable device batching
def set_supervisor_release(
@@ -1689,11 +1676,9 @@ def set_supervisor_release(
) -> None:
"""
Set a specific device to run a particular supervisor release.
-
Args:
uuid_or_id (Union[str, int]): device uuid (string) or id (int)
supervisor_version_or_id (Union[str, int]): the version of a released supervisor (string) or id (number)
-
Examples:
>>> balena.models.device.set_supervisor_release('f55dcdd9ad', 'v13.0.0')
"""
@@ -1701,46 +1686,29 @@ def set_supervisor_release(
uuid_or_id,
{
"$select": ["id", "supervisor_version", "os_version"],
- "$expand": {"is_of__device_type": {"$select": "slug"}},
+ "$expand": {"is_of__device_type": {"$select": "is_of__cpu_architecture"}},
},
)
- device_type_slug = device["is_of__device_type"][0]["slug"]
+ cpu_arch_id = device["is_of__device_type"][0]["is_of__cpu_architecture"]["__id"]
release_options = {
"$top": 1,
"$select": "id",
- "$filter": {
- "is_for__device_type": {
- "$any": {
- "$alias": "dt",
- "$expr": {
- "dt": {
- "slug": device_type_slug,
- },
- },
- },
- },
- },
+ "$filter": {"id" if is_id(supervisor_version_or_id) else "raw_version": supervisor_version_or_id},
}
- if is_id(supervisor_version_or_id):
- release_options["$filter"]["id"] = supervisor_version_or_id
- else:
- release_options["$filter"]["supervisor_version"] = supervisor_version_or_id
-
try:
- release = self.__pine.get({"resource": "supervisor_release", "options": release_options})[0]
+ release = self.__device_os.get_supervisor_releases_for_cpu_architecture(cpu_arch_id, release_options)[0]
except IndexError:
raise Exception(f"Supervisor release not found {supervisor_version_or_id}")
ensure_version_compatibility(device["supervisor_version"], MIN_SUPERVISOR_MC_API, "supervisor")
ensure_version_compatibility(device["os_version"], MIN_OS_MC, "host OS")
-
self.__pine.patch(
{
"resource": "device",
"id": device["id"],
- "body": {"should_be_managed_by__supervisor_release": release["id"]},
+ "body": {"should_be_managed_by__release": release["id"]},
}
)
diff --git a/balena/models/os.py b/balena/models/os.py
index 872e8376..20aefd5f 100644
--- a/balena/models/os.py
+++ b/balena/models/os.py
@@ -10,7 +10,8 @@
from ..hup import get_hup_action_type
from ..pine import PineClient
from ..types import AnyObject
-from ..utils import compare, merge, normalize_balena_semver
+from ..types.models import ReleaseType
+from ..utils import compare, merge, normalize_balena_semver, is_id
from ..settings import Settings
from .application import Application
from .device_type import DeviceType
@@ -493,6 +494,89 @@ def is_architecture_compatible_with(self, os_architecture: str, application_arch
return True
+ def get_supervisor_releases_for_cpu_architecture(
+ self, cpu_architecture_slug_or_id: Union[str, int], options: AnyObject = {}
+ ) -> List[ReleaseType]:
+ """
+ Returns the Releases of the supervisor for the CPU Architecture
+
+ Args:
+ cpu_architecture_slug_or_id (Union[str, int]): The slug (string) or id (number) for the CPU Architecture.
+ options (AnyObject): extra pine options to use.
+
+ Returns:
+ ReleaseType: release info.
+
+
+ Example:
+ results = balena.models.os.get_supervisor_releases_for_cpu_architecture('aarch64');
+ results = balena.models.os.get_supervisor_releases_for_cpu_architecture(
+ 'aarch64',
+ { $filter: { raw_version: '12.11.0' } },
+ );
+ """
+ return self.__pine.get(
+ {
+ "resource": "release",
+ "options": merge(
+ {
+ "$select": ["id", "raw_version", "known_issue_list"],
+ "$filter": {
+ "status": "success",
+ "is_final": True,
+ "is_invalidated": False,
+ "semver_major": {"$gt": 0},
+ "belongs_to__application": {
+ "$any": {
+ "$alias": "a",
+ "$expr": {
+ "$and": [
+ {"a": {"slug": {"$startswith": "balena_os/"}}},
+ {"a": {"slug": {"$endswith": "-supervisor"}}},
+ ],
+ "a": {
+ "is_public": True,
+ "is_host": False,
+ "is_for__device_type": {
+ "$any": {
+ "$alias": "dt",
+ "$expr": {
+ "dt": {
+ "is_of__cpu_architecture": (
+ cpu_architecture_slug_or_id
+ if is_id(cpu_architecture_slug_or_id)
+ else {
+ "$any": {
+ "$alias": "c",
+ "$expr": {
+ "c": {
+ "slug": cpu_architecture_slug_or_id,
+ },
+ },
+ },
+ }
+ ),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "$orderby": [
+ {"semver_major": "desc"},
+ {"semver_minor": "desc"},
+ {"semver_patch": "desc"},
+ {"revision": "desc"},
+ ],
+ },
+ options,
+ ),
+ }
+ )
+
def __tags_to_dict(self, tags: List[Any]) -> Dict[str, str]:
tag_map = {}
diff --git a/balena/settings.py b/balena/settings.py
index ae2d8981..5259d7cc 100644
--- a/balena/settings.py
+++ b/balena/settings.py
@@ -49,7 +49,7 @@ def remove(self, key: str) -> bool:
DEFAULT_SETTINGS = {
# These are default config values
"balena_host": "balena-cloud.com",
- "api_version": "v6",
+ "api_version": "v7",
"device_actions_endpoint_version": "v1",
# cache time : 1 week in milliseconds
"image_cache_time": str(1 * 1000 * 60 * 60 * 24 * 7),
diff --git a/balena/types/models.py b/balena/types/models.py
index e128436f..d7488062 100644
--- a/balena/types/models.py
+++ b/balena/types/models.py
@@ -9,7 +9,7 @@ class PineDeferred(TypedDict):
NavigationResource = Union[List[__T], PineDeferred]
ReverseNavigationResource = Union[List[__T], None]
-ConceptTypeNavigationResource = Union[List[__T], int]
+ConceptTypeNavigationResource = NavigationResource[__T]
OptionalNavigationResource = Union[List[__T], PineDeferred, None]
@@ -242,11 +242,6 @@ class DeviceTypeType(TypedDict):
device_type_alias: ReverseNavigationResource["DeviceTypeAliasType"]
-class TypeDeviceState(TypedDict):
- key: str
- name: str
-
-
class ServiceInstanceType(TypedDict):
id: int
created_at: str
@@ -255,17 +250,6 @@ class ServiceInstanceType(TypedDict):
last_heartbeat: str
-class SupervisorReleaseType(TypedDict):
- created_at: str
- id: int
- supervisor_version: str
- image_name: str
- is_public: bool
- note: Optional[str]
-
- is_for__device_type: NavigationResource[DeviceTypeType]
-
-
class ImageInstallType(TypedDict):
id: int
download_progress: Optional[float]
@@ -308,12 +292,9 @@ class TypeDevice(TypedDict):
os_version: str
provisioning_progress: int
provisioning_state: str
- state: TypeDeviceState
status: str
- status_sort_index: int
supervisor_version: str
uuid: str
- vpn_address: str
api_heartbeat_state: Literal["online", "offline", "timeout", "unknown"]
memory_usage: int
memory_total: int
@@ -325,7 +306,16 @@ class TypeDevice(TypedDict):
cpu_id: str
is_undervolted: bool
# This is a computed term
- overall_status: Any
+ overall_status: Literal[
+ "configuring",
+ "inactive",
+ "post-provisioning",
+ "updating",
+ "operational",
+ "disconnected",
+ "reduced-functionality",
+ ]
+
# This is a computed term
overall_progress: int
@@ -333,9 +323,10 @@ class TypeDevice(TypedDict):
belongs_to__application: NavigationResource[TypeApplication]
belongs_to__user: OptionalNavigationResource[UserType]
is_running__release: OptionalNavigationResource["ReleaseType"]
- should_be_running__release: OptionalNavigationResource["ReleaseType"]
+ is_pinned_on__release: OptionalNavigationResource["ReleaseType"]
is_managed_by__service_instance: OptionalNavigationResource[ServiceInstanceType]
- should_be_managed_by__supervisor_release: OptionalNavigationResource[SupervisorReleaseType]
+ should_be_operated_by__release: OptionalNavigationResource["ReleaseType"]
+ should_be_managed_by__release: OptionalNavigationResource["ReleaseType"]
device_config_variable: ReverseNavigationResource["EnvironmentVariableBase"]
device_environment_variable: ReverseNavigationResource["EnvironmentVariableBase"]
device_tag: ReverseNavigationResource["BaseTagType"]
@@ -442,7 +433,7 @@ class ImageType(TypedDict):
start_timestamp: str
end_timestamp: str
push_timestamp: str
- image_size: int
+ image_size: str
dockerfile: str
error_message: str
is_a_build_of__service: NavigationResource["ServiceType"]
@@ -508,7 +499,9 @@ class ReleaseType(TypedDict):
release_image: ReverseNavigationResource[ReleaseImageType]
should_be_running_on__application: ReverseNavigationResource[TypeApplication]
is_running_on__device: ReverseNavigationResource[TypeDevice]
- should_be_running_on__device: ReverseNavigationResource[TypeDevice]
+ is_pinned_to__device: ReverseNavigationResource[TypeDevice]
+ should_operate__device: ReverseNavigationResource[TypeDevice]
+ should_manage__device: ReverseNavigationResource[TypeDevice]
release_tag: ReverseNavigationResource[BaseTagType]
diff --git a/balena/utils.py b/balena/utils.py
index dd0dd833..a5355996 100644
--- a/balena/utils.py
+++ b/balena/utils.py
@@ -172,8 +172,7 @@ def get_current_service_details_pine_expand(
def get_single_install_summary(raw_data: Any) -> Any:
# TODO: Please compare me to node-sdk version
"""
- Builds summary data for an image install or gateway download
-
+ Builds summary data for an image install
"""
image = raw_data["image"][0]
@@ -207,11 +206,7 @@ def generate_current_service_details(raw_device: TypeDevice) -> TypeDeviceWithSe
grouped_services[obj.pop("service_name", None)].append(obj)
raw_device["current_services"] = dict(grouped_services) # type: ignore
- raw_device["current_gateway_downloads"] = [ # type: ignore
- get_single_install_summary(i) for i in raw_device.get("gateway_download", [])
- ]
raw_device.pop("image_install", None) # type: ignore
- raw_device.pop("gateway_download", None) # type: ignore
return raw_device # type: ignore
diff --git a/tests/functional/models/test_application.py b/tests/functional/models/test_application.py
index cb9c65ac..23861c5b 100644
--- a/tests/functional/models/test_application.py
+++ b/tests/functional/models/test_application.py
@@ -72,21 +72,6 @@ def test_06_get_all_by_organization(self):
self.balena.models.application.get_all_by_organization(self.org_id)[0]["app_name"], "FooBar"
)
- def test_06_get_by_owner(self):
- with self.assertRaises(self.helper.balena_exceptions.ApplicationNotFound):
- self.balena.models.application.get_by_owner("AppNotExist", self.helper.credentials["user_id"])
-
- self.assertEqual(
- self.balena.models.application.get_by_owner("FooBar", self.helper.default_organization["handle"])[
- "app_name"
- ],
- "FooBar",
- )
-
- with self.assertRaises(Exception) as cm:
- self.balena.models.application.get_by_owner("FooBar", "random_username")
- self.assertIn("Application not found: random_username/foobar", cm.exception.message) # type: ignore
-
def test_07_has(self):
self.assertFalse(self.balena.models.application.has("AppNotExist"))
self.assertTrue(self.balena.models.application.has(self.app_slug))
diff --git a/tests/functional/models/test_device_os.py b/tests/functional/models/test_device_os.py
index 30a53808..bd415041 100644
--- a/tests/functional/models/test_device_os.py
+++ b/tests/functional/models/test_device_os.py
@@ -38,6 +38,48 @@ def test_02_get_hup_action_type(self):
for ver in testVersion:
get_hup_action_type("", ver, ver)
+ def test_03_get_supervisor_releases_for_cpu_architecture(self):
+ # return an empty array if no image was found
+ svRelease = self.balena.models.os.get_supervisor_releases_for_cpu_architecture("notACpuArch")
+ self.assertEqual(svRelease, [])
+
+ # by default include the id, semver and known_issue_list
+ dt = self.balena.models.device_type.get(
+ "raspberrypi4-64", {"$select": "slug", "$expand": {"is_of__cpu_architecture": {"$select": "slug"}}}
+ )
+
+ svReleases = self.balena.models.os.get_supervisor_releases_for_cpu_architecture(
+ dt["is_of__cpu_architecture"][0]["slug"]
+ )
+
+ self.assertGreater(len(svReleases), 0)
+ svRelease = svReleases[0]
+ self.assertListEqual(sorted(svRelease.keys()), sorted(["id", "raw_version", "known_issue_list"]))
+
+ # return the right string when asking for raspberrypi4-64 and v12.11.0
+ dt = self.balena.models.device_type.get(
+ "raspberrypi4-64", {"$select": "slug", "$expand": {"is_of__cpu_architecture": {"$select": "slug"}}}
+ )
+ svReleases = self.balena.models.os.get_supervisor_releases_for_cpu_architecture(
+ dt["is_of__cpu_architecture"][0]["slug"],
+ {
+ "$select": "id",
+ "$expand": {
+ "release_image": {
+ "$select": "id",
+ "$expand": {"image": {"$select": "is_stored_at__image_location"}},
+ },
+ },
+ "$filter": {"raw_version": "12.11.0"},
+ },
+ )
+
+ self.assertEqual(len(svReleases), 1)
+ svRelease = svReleases[0]
+ imageLocation = svRelease["release_image"][0]["image"][0]["is_stored_at__image_location"]
+ self.assertRegex(imageLocation, r"registry2\.[a-z0-9_\-.]+\.[a-z]+\/v2\/[0-9a-f]+")
+ self.assertEqual(imageLocation, "registry2.balena-cloud.com/v2/4ca706e1c624daff7e519b3009746b2c")
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/functional/test_auth.py b/tests/functional/test_auth.py
index 445583d2..e5abbc96 100644
--- a/tests/functional/test_auth.py
+++ b/tests/functional/test_auth.py
@@ -159,9 +159,9 @@ def test_17_should_login_with_device_key(self):
self.assertEqual(whoami["actorType"], "device")
self.assertEqual(whoami["actorTypeId"], self.app_info["device"]["id"])
self.assertEqual(whoami["uuid"], device_uuid)
- self.assertEqual(whoami["id"], self.app_info["device"]["actor"])
+ self.assertEqual(whoami["id"], self.app_info["device"]["actor"]["__id"])
- self.assertEqual(self.balena.auth.get_actor_id(), self.app_info["device"]["actor"])
+ self.assertEqual(self.balena.auth.get_actor_id(), self.app_info["device"]["actor"]["__id"])
errMsg = "The authentication credentials in use are not of a user"
with self.assertRaises(Exception) as cm:
@@ -190,10 +190,10 @@ def test_18_should_login_with_app_key(self):
self.assertEqual(whoami["actorType"], "application")
self.assertEqual(whoami["actorTypeId"], app_id)
- self.assertEqual(whoami["id"], self.app_info["app"]["actor"])
+ self.assertEqual(whoami["id"], self.app_info["app"]["actor"]["__id"])
self.assertEqual(whoami["slug"], self.app_info["app"]["slug"])
- self.assertEqual(self.balena.auth.get_actor_id(), self.app_info["app"]["actor"])
+ self.assertEqual(self.balena.auth.get_actor_id(), self.app_info["app"]["actor"]["__id"])
errMsg = "The authentication credentials in use are not of a user"
with self.assertRaises(Exception) as cm: