Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openBalena settings returning balenaCloud #1029

Open
bartversluijs opened this issue Jan 5, 2021 · 8 comments
Open

openBalena settings returning balenaCloud #1029

bartversluijs opened this issue Jan 5, 2021 · 8 comments

Comments

@bartversluijs
Copy link

Expected Behavior

I'm using the Balena SDK to communicate with my openBalena server.
I create an SDK instance like this:

import { getSdk } from 'balena-sdk';
const balenaInstance = getSdk({ apiUrl: 'api.<open-balena-domain>' });

I expect the following to happen:

balenaInstance.settings.get('apiUrl'); // Output: https://api.<open-balena-domain>
balenaInstance.settings.get('vpnUrl'); // Output: vpn.<open-balena-domain>

Actual Behavior

The following happens:

balenaInstance.settings.get('apiUrl'); // Output: https://api.balena-cloud.com
balenaInstance.settings.get('vpnUrl'); // Output: vpn.balena-cloud.com

Steps to Reproduce the Problem

import { getSdk } from 'balena-sdk';
const balenaInstance = getSdk({ apiUrl: 'api.<open-balena-domain>' });
console.log(await balenaInstance.settings.get('apiUrl'));
console.log(await balenaInstance.settings.get('vpnUrl'));

Specifications

  • SDK version: 15.21.1
  • Browser:
  • Node version: 14.3.0
  • Npm version: 6.14.5
  • OS: MacOS Big Sur (11.1)

References

@thgreasi
Copy link
Member

thgreasi commented Jan 5, 2021

Hi,
Thanks for bringing this up.
It seems that in its current form the settings namespace is a bit confusing and I see your point that the current results are not expected. Let me try to clarify how things are working today.

Currently the settings namespace is primarily used for the needs of the CLI.
Under the hood it uses balena-settings-client which parses your local ~/.balenarc.yml file and populates all the settings using the values in your local ~/.balenarc.yml, environment variables, or sane defaults based based on the apiUrl in your ~/.balenarc.yml (or api.balena-cloud.com when not found).

This way whenever a CLI command is issued, the CLI can find all urls that it needs in order to operate without extra web requests.
The SDK currently only uses the data directory that the settings namespace provides for storing & retrieving the user token when using auth,login() and auth.loginWithToken().

Unfortunately at this point the only way to retrieve the initially provided api url is by using the balenaInstance.pine.API_URL.

Let us know whether that unblocks you for now.
Thanks again for reporting this.

Kind regards,
Thodoris

@bartversluijs
Copy link
Author

Hi Thodoris,

I see, it's a bit confusing indeed. However, if there's a way to get the Balena instance from the initiated SDK, it's fine for me. I need to get it via the SDK instance, because our application can contain devices from our openBalena server as well as a balenaCloud server. And we've a function that returns the right Balena SDK based on some details of the device.

I tried using balenaInstance.pine.API_URL, but my IDE throws an error that API_URL does not exist on balenaInstance.pine, or is this just not typed?

Thanks in advance!

@thgreasi
Copy link
Member

@bartversluijs I'm sorry for the late reply. Indeed balenaInstance.pine.API_URL is not currently typed.
It is actually somethings that I can't say that we will be maintaining in next versions.
Until we properly support augmenting the values returned by the settings namespace methods with the ones provided during the initialization of the SDK, I would suggest you to refactor your code so that instead of just the SDK instance, it returns an object that also includes the server whose API_URL was used during instantiation. Something like:

declare function getSdkInfoForDevice (device: BalenaSdk.Device): { sdk: BalenaSdk.BalenaSDK, api_url: string };

@bartversluijs
Copy link
Author

Hi @thgreasi,

Thanks for thinking with me. I've created my own typing of the Balena SDK which extends the current Balena SDK and included the hostname. This way, I can use the hostname just from the SDK instance.

import { BalenaSDK as originalBalenaSDK } from 'balena-sdk';

export interface BalenaSDK extends originalBalenaSDK {
  hostname: string;
}

I can also add hostname to the Balena SDK typing without creating my own interface, but this does the job just fine.


I'll let you (and your team) decide if this issue can be closed or not, because the settings namespace can cause weird behaviour for others. If this is intended to work this way and will not be changed, this issue can be closed!

@thgreasi
Copy link
Member

thgreasi commented Feb 18, 2021

Hi @bartversluijs can you give a code example on how you use that new property?
As far as I can tell, there is no sdk.hostname at the moment.
Do you populate it manually after the instantiation?`

@bartversluijs
Copy link
Author

Hi @thgreasi,
Correct, there's no sdk.hostname in the Balena SDK at the moment. So I had to populate it. I initiate the SDK via a custom method, which populates the sdk.hostname. This is because the SDK doesn't have a way of returning the hostname of the instance it's connected to at the moment.

@thgreasi
Copy link
Member

thgreasi commented Feb 23, 2021

Thanks for the extra details @bartversluijs .

And we've a function that returns the right Balena SDK based on some details of the device.

I guess that this function goes over all balena sdk instances and checks the hostname property, right?
If so, I would actually suggest you to use an object or a Map as a dictionary for finding the correct balena sdk instance, instead of iterating over an array. That would look something like:

const balenaSdkMap: Record<string, BalenaSDK> = {};

function getBalenaSdkForHostname(hostname: string) {
	const sdk = balenaSdkMap[hostname];
	if (!sdk) {
		sdk = getSdk({ apiUrl: hostname });
		balenaSdkMap[hostname] = sdk;
	}
	return sdk;
}

@bartversluijs
Copy link
Author

Thanks for the suggestion @thgreasi.
Indeed, I'm looping over an array (with array.find), but the input is a device (registered on our server & Balena) and based on the app name and version, it determines the Balena SDK. So it has more than 1 variable to find the right Balena SDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants