Can't restart service via node sdk

I’m trying to use the node sdk to restart a service on a device.
balena.models.device.restartService(uuid, imageId)

I’m getting the image id via the current_services array returned as part of
balena.models.device.getWithServiceDetails(uuid)
in the shape of:
{ "<service-name>": [{ ... "image_id": 999999, ... }] }
However when I run the restartService method above the response is:

ERROR : (node:90) UnhandledPromiseRejectionWarning: BalenaRequestError: Request error: Service not found, a container must exist for this endpoint to work

I can restart the service by using the supervisor api but only if I send the serviceName not imageId which results in the same error. Is there a different way to get the imageId or a way to get a different imageId that works?

Thanks for the help.

Hi there, I just did some experimenting on my own machine to reproduce the behaviour you are reporting - it seems as though the object that is returned by balena.models.device.getWithServiceDetails(uuid) returns an object that contains something like this:

{ image_install:
   [ { image: [Array],
       is_provided_by__release: [Array],
       id: 41176000,
       download_progress: null,
       status: 'Running',
       install_date: '2021-01-26T15:09:25.703Z',
       __metadata: [Object] },
     ],
}

If I used image_install[0].id then I got the same error as you. However the image_install[0].image field is an array that looks like this:

[ { is_a_build_of__service: [ [Object] ],
    id: 3204611,
    __metadata: { uri: 'uri thingy' } } ]

If I used this id (so that’s image_install[0].image[0].id as the imageId then I was able to use balena.models.device.restartService successfully.

Hopefully that made sense - let me know if it didn’t!

Hi! Thanks for digging into that.

Unfortunately the id you found deep within the image_install object is the same image_id value I get from the current_services array from the getWithServiceDetails(uuid) function call.

At least now I know I was using the right image_id. Where are you getting your device uuid? I’m just copying it from the balena cloud dashboard. Could that be the wrong value possibly?

Hi, @adelbello!

Sorry to hear you’re having trouble with the Balena SDK. I have replicated your steps (or approximately) as well, with the code:

    const uuid = "YOUR_UUID"
    const sdk = fromSharedOptions();

    const device = await sdk.models.device.getWithServiceDetails(uuid)
    const id = device.current_services.upnp[0].image_id
    await sdk.models.device.restartService(uuid, id)

I used this on an open source balena project on balenaHub called balenaSound.

If you want to try this too and have an extra device laying around, you can try too, if you want to try something that is known to work. Maybe you’ll see something you missed and get it working that way.

For the next diagnostic, I’d like you to tunnel into your balena device, however you want to do it (cloud dashboard or balena ssh) and run the following commands:

curl --header "Content-Type:application/json" "$BALENA_SUPERVISOR_ADDRESS/v2/applications/$BALENA_APP_ID/restart-service?apikey=$BALENA_SUPERVISOR_API_KEY" -d '{"serviceName": "my-service"}'

and

curl --header "Content-Type:application/json" "$BALENA_SUPERVISOR_ADDRESS/v2/applications/$BALENA_APP_ID/restart-service?apikey=$BALENA_SUPERVISOR_API_KEY" -d '{"imageId": 1234}'

Obviously substituting “1234” and “my-service” with your real service name/image id.

and let us know the results.

The purpose of this is to determine if there’s something in the pipeline between the SDK and the device that is preventing the service from restarting or if it’s the supervisor itself that is bugged.

Thank you for you patience and assistance in making Balena a better product. I hope to hear from you soon.

Zane

Sorry, I should have said balena ssh into a container. So, you would use balena ssh [uuid] [service name] and run the command

Also, sorry, forgot to mention, you’ll need to enable those variables in order to send that command. From the docs:

To enable these Supervisor environment variables, the io.balena.features.supervisor-api label must be applied for each service that requires them. See here for further details.

Thank you for the help so far. Still no luck here. I’ve tried to add the labels to the compose file to enable the supervisor environment variables but they don’t seem to be available. Would you mind looking over my compose file to see if I’m doing it correctly?

version: "2"
services:
  electron:
    labels:
      io.balena.features.supervisor-api: "1"
    build:
      context: ./app
  pi-services:
    labels:
      io.balena.features.supervisor-api: "1"
    build: ./PiServices

when I ssh into the into the service after deploying with:
balena ssh <device uuid> <service name>
and try to echo a variable with:
echo $BALENA_SUPERVISOR_ADDRESS
I get nothing returned.

Ok, in a way that kind of answers my question, because that means that the service is not restarting when you try to push to it.

I think the easiest thing would be to grant support access to the device so we can interact with the supervisor to see what’s going wrong.

Would you mind going to your device dashboard, actions, “Grant Support Access”, and then share the device url here?

Sure, thanks for the help.
I’ve enabled support access. The device doesn’t have a public facing url but its dashboard url is:
https://dashboard.balena-cloud.com/devices/80c335fe0600452f174b88b05eafd5e9/summary

Hi

I was able to run curl --header "Content-Type:application/json" "$BALENA_SUPERVISOR_ADDRESS/v2/applications/$BALENA_APP_ID/restar t-service?apikey=$BALENA_SUPERVISOR_API_KEY" -d '{"serviceName": "pi-services"}' from your electron container just fine.

How are you trying to run this? Can you mention detailed steps?

Hi @anujdeshpande. As a matter of fact I am also able to restart the service by sending a supervisor api request and specifying a service name. My issue is with the node sdk with an image id, i.e.
sdk.models.device.restartService(uuid, imageId)

And it’s also probably significant that while I can restart a service using the api by specifying a service name, I am unable to restart a service using the api by specifying an imageId. In fact the error outputs of both methods - api using imageId and sdk using imageId - are the same:
... Service not found, a container must exist for this endpoint to work

Hey @adelbello, could you please post the entire error log or more context here so that we’ll be able to assist you better?
Thanks,
Georgia

Hi @georgiats sure, although there’s not much more to it:

2021-02-02 8:51:12 PM [Console] ERROR : (node:115) UnhandledPromiseRejectionWarning: BalenaRequestError: Request error: Service not found, a container must exist for this endpoint to work
  at Object.<anonymous> (/app/node_modules/balena-request/build/request.js:190:27)
  at Generator.next (<anonymous>)
  at fulfilled (/app/node_modules/balena-request/node_modules/tslib/tslib.js:114:62)
  at process._tickCallback (internal/process/next_tick.js:68:7)
2021-02-02 8:51:12 PM [Console] ERROR : (node:115) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
2021-02-02 8:51:12 PM [Console] ERROR : (node:115) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

This is a result of running:
sdk.models.device.restartService('80c335fe0600452f174b88b05eafd5e9', 3216996)

Hi there, are you able to grant support access again please, we’ll do some quick troubleshooting from our end…

Sure! Granted for one week.

https://dashboard.balena-cloud.com/devices/80c335fe0600452f174b88b05eafd5e9/summary

OK, I’ve tested below in browser dev tools console against your device and found it to be working correctly (restarted both electron and pi-services services):

uuid = '80c335fe0600452f174b88b05eafd5e9'
const device = await sdk.models.device.getWithServiceDetails(uuid)

const electron_running_image_id = device.current_services.electron[0].image_id
await sdk.models.device.restartService(uuid, electron_running_image_id)

const pi_services_running_image_id = device.current_services["pi-services"][0].image_id
await sdk.models.device.restartService(uuid, pi_services_running_image_id)

Can you please check the image_id you are supplying by inspecting the device dictionary returned by the getWithServiceDetails method to get the current (running) image ids.

Yes the image ids I’m using, that are returned by the getWithServiceDetails() method are 3220189 for electron and 3220190 for pi-services. Are those the same image ids you have?

As luck would have it support agents were disallowed from attempting to restart containers a mere 7 hours ago.

So, there’s no way for me to manually try to restart your containers. I believe this is to prevent an accidentally restart of a container that messes up the application of a customer, but makes diagnosing things like this rather difficult.

But to answer your question, yes those are the same image ids my Anton and I both got.

Can you try opening Chrome Developer Tools (or your browser equivalent) while on the balena cloud dashboard and past the exact command:

;(async () => {
uuid = '80c335fe0600452f174b88b05eafd5e9'
const device = await sdk.models.device.getWithServiceDetails(uuid)

const electron_running_image_id = device.current_services.electron[0].image_id
await sdk.models.device.restartService(uuid, electron_running_image_id)

const pi_services_running_image_id = device.current_services["pi-services"][0].image_id
await sdk.models.device.restartService(uuid, pi_services_running_image_id)
})()

This should be a failsafe way to restart the container.

And if that works, try adjusting your code to the code provided in your own project and see if that works?

If that doesn’t work, let us know, and we’ll go from there.

This code works.

I’m really at a loss right now because I was testing it with, as far as I can tell, accurate hard-coded values.

This proves the sdk is working though and there is something faulty with my code. Thank you to everyone on this thread in helping me to debug this. I really appreciate the time you took.

It’s all good, thanks for reaching out. Be sure to ping us again if you need more help regarding the same.