@ada after some help from the SDK team, basically, there are two types of env vars, device env vars (which map to those on the UI that you see service name beeing “all services”). These you can get with:
const deviceEnvVars = await sdk.models.device.envVar.getAllByDevice(deviceUUID);
And these do not have service name associated (as they will apply to all services). There is also (as you pointed) device service env var, which apply specifically for a single device on a single service. You can further expand
into the service install resource to get the service name, as follows:
const deviceServiceVars = await sdk.models.device.serviceVar.getAllByDevice(deviceUUID, {
$expand: {
service_install: {
$expand: {
installs__service: {
$select: ['id', 'service_name']
}
}
}
}
})
You will have an object similar to:
[
{
"service_install": [
{
"installs__service": [
{
"id": 2998312,
"service_name": "balena-hello-world"
}
],
"created_at": "2024-10-15T15:52:49.737Z",
"device": {
"__id": 12864513
},
"id": 44442160
}
],
"created_at": "2024-10-22T10:03:38.802Z",
"value": "123",
"id": 51510637,
"name": "test"
}
]
So you can get the serviceName with serviceVar[index]["service_install"][0]["installs__service"][0]["service_name"]
.
I would also recommend to add some nullability checks in case service_install is null (as these might be created asynchronously) with a retry.
Here is a script that might serve you:
const fromDeviceUuid = '';
const toDeviceUuid = '';
const envVars = await sdk.models.device.envVar.getAllByDevice(fromDeviceUuid);
const serviceVars = await sdk.models.device.serviceVar.getAllByDevice(deviceUUID, {
$expand: {
service_install: {
$expand: {
installs__service: {
$select: ['id', 'service_name']
}
}
}
}
});
for (const ev of envVars) {
await sdk.models.device.envVar.set(toDeviceUuid, ev.name, ev.value);
}
for (const sv of serviceVars) {
const serviceName = sv?.service_install?.[0].installs__service[0].service_name;
if (serviceName == null) {
// TODO. wait a bit and retry from the start (do another `sdk.models.device.serviceVar.getAllByDevice`)
}
await sdk.models.device.serviceVar.set(toDeviceUuid, serviceName, sv.name, sv.value);
}
More over, several of those calls can be paralelised using Promise.all
(Promise.all() - JavaScript | MDN) in case they want to implement it.
Let us know if this works for you!