Do not export balenaApi on api-binder

Instead, add `getBalenaApi` function to api-helper so other modules can
access a balena API instance.

Further reduces circular dependencies to 5

Change-type: patch
This commit is contained in:
Felipe Lalanne 2024-05-15 16:39:33 -04:00
parent ac2db38742
commit 59689b2789
4 changed files with 36 additions and 39 deletions

View File

@ -3,8 +3,7 @@ import { stripIndent } from 'common-tags';
import { isLeft } from 'fp-ts/lib/Either';
import * as t from 'io-ts';
import _ from 'lodash';
import { PinejsClientRequest } from 'pinejs-client-request';
import url from 'url';
import type { PinejsClientRequest } from 'pinejs-client-request';
import * as config from '../config';
import * as deviceConfig from '../device-config';
@ -17,7 +16,6 @@ import {
InternalInconsistencyError,
TargetStateError,
} from '../lib/errors';
import * as request from '../lib/request';
import log from '../lib/supervisor-console';
@ -511,31 +509,18 @@ async function reportInitialName(
}
}
export let balenaApi: PinejsClientRequest | null = null;
let balenaApi: PinejsClientRequest | null = null;
export const initialized = _.once(async () => {
await config.initialized();
await deviceState.initialized();
const { unmanaged, apiEndpoint, currentApiKey } = await config.getMany([
'unmanaged',
'apiEndpoint',
'currentApiKey',
]);
const unmanaged = await config.get('unmanaged');
if (unmanaged) {
log.debug('Unmanaged mode is set, skipping API client initialization');
return;
}
const baseUrl = url.resolve(apiEndpoint, '/v6/');
const passthrough = structuredClone(await request.getRequestOptions());
passthrough.headers = passthrough.headers != null ? passthrough.headers : {};
passthrough.headers.Authorization = `Bearer ${currentApiKey}`;
balenaApi = new PinejsClientRequest({
apiPrefix: baseUrl,
passthrough,
});
log.info(`API Binder bound to: ${baseUrl}`);
balenaApi = await apiHelper.getBalenaApi();
});

View File

@ -1,4 +1,4 @@
import type { PinejsClientRequest } from 'pinejs-client-request';
import { PinejsClientRequest } from 'pinejs-client-request';
import Bluebird from 'bluebird';
import * as config from '../config';
@ -14,6 +14,8 @@ import {
isHttpConflictError,
} from './errors';
import log from './supervisor-console';
import memoizee from 'memoizee';
import url from 'url';
export type KeyExchangeOpts = config.ConfigType<'provisioningOptions'>;
@ -23,6 +25,29 @@ export interface Device {
[key: string]: unknown;
}
export const getBalenaApi = memoizee(
async () => {
await config.initialized();
const { apiEndpoint, currentApiKey } = await config.getMany([
'apiEndpoint',
'currentApiKey',
]);
const baseUrl = url.resolve(apiEndpoint, '/v6/');
const passthrough = structuredClone(await request.getRequestOptions());
passthrough.headers =
passthrough.headers != null ? passthrough.headers : {};
passthrough.headers.Authorization = `Bearer ${currentApiKey}`;
log.info(`API Binder bound to: ${baseUrl}`);
return new PinejsClientRequest({
apiPrefix: baseUrl,
passthrough,
});
},
{ promise: true },
);
export const fetchDevice = async (
balenaApi: PinejsClientRequest,
uuid: string,

View File

@ -1,5 +1,4 @@
import * as path from 'path';
import * as apiBinder from '../api-binder';
import * as config from '../config';
import * as db from '../db';
import * as volumeManager from '../compose/volume-manager';
@ -20,6 +19,7 @@ import type {
DatabaseApp,
DatabaseService,
} from '../device-state/target-state-cache';
import { getBalenaApi } from '../lib/api-helper';
import type { TargetApp, TargetApps, TargetState } from '../types';
@ -54,13 +54,7 @@ async function createVolumeFromLegacyData(
* Gets proper database ids from the cloud for the app and app services
*/
export async function normaliseLegacyDatabase() {
await apiBinder.initialized();
if (apiBinder.balenaApi == null) {
throw new InternalInconsistencyError(
'API binder is not initialized correctly',
);
}
const balenaApi = await getBalenaApi();
// When legacy apps are present, we kill their containers and migrate their /data to a named volume
log.info('Migrating ids for legacy app...');
@ -97,7 +91,7 @@ export async function normaliseLegacyDatabase() {
}
log.debug(`Getting release ${app.commit} for app ${app.appId} from API`);
const releases = await apiBinder.balenaApi.get({
const releases = await balenaApi.get({
resource: 'release',
options: {
$filter: {
@ -266,15 +260,7 @@ export async function fromV2TargetState(
* @param appId
*/
const getUUIDFromAPI = async (appId: number) => {
await apiBinder.initialized();
if (apiBinder.balenaApi == null) {
throw new InternalInconsistencyError(
'API binder is not initialized correctly',
);
}
const { balenaApi } = apiBinder;
const balenaApi = await getBalenaApi();
const appDetails = await balenaApi.get({
resource: 'application',

View File

@ -58,8 +58,9 @@ export class Supervisor {
await deviceState.initialized();
const unmanaged = await config.get('unmanaged');
logger.logSystemMessage('Supervisor starting', {}, 'Supervisor start');
if (conf.legacyAppsPresent && apiBinder.balenaApi != null) {
if (conf.legacyAppsPresent && !unmanaged) {
log.info('Legacy app detected, running migration');
await normaliseLegacyDatabase();
}