mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-19 05:37:51 +00:00
Merge pull request #2626 from balena-io/less-requests
Stop fetching unnecessary fields
This commit is contained in:
commit
46ab335407
@ -147,6 +147,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
public async getApplication(balena: BalenaSDK, fleet: string) {
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
return await getApplication(balena, fleet, {
|
||||
$select: 'slug',
|
||||
$expand: {
|
||||
is_for__device_type: { $select: 'slug' },
|
||||
},
|
||||
|
@ -131,6 +131,7 @@ export default class DeviceInitCmd extends Command {
|
||||
await (await import('../../utils/patterns')).selectApplication()
|
||||
).slug,
|
||||
{
|
||||
$select: ['id', 'slug'],
|
||||
$expand: {
|
||||
is_for__device_type: {
|
||||
$select: 'slug',
|
||||
|
@ -30,13 +30,6 @@ import { ExpectedError } from '../../errors';
|
||||
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo } from '../../utils/messages';
|
||||
|
||||
type ExtendedDevice = PineTypedResult<
|
||||
Device,
|
||||
typeof import('../../utils/helpers').expandForAppNameAndCpuArch
|
||||
> & {
|
||||
application_name?: string;
|
||||
};
|
||||
|
||||
interface FlagsDef {
|
||||
fleet?: string;
|
||||
help: void;
|
||||
@ -82,6 +75,33 @@ export default class DeviceMoveCmd extends Command {
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
private async getDevices(balena: BalenaSDK, deviceUuids: string[]) {
|
||||
const deviceOptions = {
|
||||
$select: 'belongs_to__application',
|
||||
$expand: {
|
||||
is_of__device_type: {
|
||||
$select: 'is_of__cpu_architecture',
|
||||
$expand: {
|
||||
is_of__cpu_architecture: {
|
||||
$select: 'slug',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies PineOptions<Device>;
|
||||
|
||||
// TODO: Refacor once `device.get()` accepts an array of uuids`
|
||||
const devices = await Promise.all(
|
||||
deviceUuids.map(
|
||||
(uuid) =>
|
||||
balena.models.device.get(uuid, deviceOptions) as Promise<
|
||||
PineTypedResult<Device, typeof deviceOptions>
|
||||
>,
|
||||
),
|
||||
);
|
||||
return devices;
|
||||
}
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||
DeviceMoveCmd,
|
||||
@ -89,36 +109,17 @@ export default class DeviceMoveCmd extends Command {
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const { expandForAppNameAndCpuArch } = await import('../../utils/helpers');
|
||||
|
||||
// Split uuids string into array of uuids
|
||||
const deviceUuids = params.uuid.split(',');
|
||||
|
||||
// Get devices
|
||||
const devices = await Promise.all(
|
||||
deviceUuids.map(
|
||||
(uuid) =>
|
||||
balena.models.device.get(
|
||||
uuid,
|
||||
expandForAppNameAndCpuArch,
|
||||
) as Promise<ExtendedDevice>,
|
||||
),
|
||||
);
|
||||
|
||||
// Map application name for each device
|
||||
for (const device of devices) {
|
||||
const belongsToApplication = device.belongs_to__application;
|
||||
device.application_name = belongsToApplication?.[0]
|
||||
? belongsToApplication[0].app_name
|
||||
: 'N/a';
|
||||
}
|
||||
const devices = await this.getDevices(balena, deviceUuids);
|
||||
|
||||
// Disambiguate application
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
|
||||
// Get destination application
|
||||
const application = options.fleet
|
||||
? await getApplication(balena, options.fleet)
|
||||
? await getApplication(balena, options.fleet, { $select: ['id', 'slug'] })
|
||||
: await this.interactivelySelectApplication(balena, devices);
|
||||
|
||||
// Move each device
|
||||
@ -135,7 +136,7 @@ export default class DeviceMoveCmd extends Command {
|
||||
|
||||
async interactivelySelectApplication(
|
||||
balena: BalenaSDK,
|
||||
devices: ExtendedDevice[],
|
||||
devices: Awaited<ReturnType<typeof this.getDevices>>,
|
||||
) {
|
||||
const { getExpandedProp } = await import('../../utils/pine');
|
||||
// deduplicate the slugs
|
||||
@ -181,7 +182,9 @@ export default class DeviceMoveCmd extends Command {
|
||||
const application = await patterns.selectApplication(
|
||||
(app) =>
|
||||
compatibleDeviceTypeSlugs.has(app.is_for__device_type[0].slug) &&
|
||||
devices.some((device) => device.application_name !== app.app_name),
|
||||
devices.some(
|
||||
(device) => device.belongs_to__application.__id !== app.id,
|
||||
),
|
||||
true,
|
||||
);
|
||||
return application;
|
||||
|
@ -78,7 +78,9 @@ export default class DeviceRegisterCmd extends Command {
|
||||
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
const application = await getApplication(balena, params.fleet);
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$select: ['id', 'slug'],
|
||||
});
|
||||
const uuid = options.uuid ?? balena.models.device.generateUniqueKey();
|
||||
|
||||
console.info(`Registering to ${application.slug}: ${uuid}`);
|
||||
|
@ -92,7 +92,9 @@ export default class DevicesCmd extends Command {
|
||||
|
||||
if (options.fleet != null) {
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
const application = await getApplication(balena, options.fleet);
|
||||
const application = await getApplication(balena, options.fleet, {
|
||||
$select: 'id',
|
||||
});
|
||||
devices = (await balena.models.device.getAllByApplication(
|
||||
application.id,
|
||||
devicesOptions,
|
||||
|
@ -130,7 +130,9 @@ export default class FleetCreateCmd extends Command {
|
||||
|
||||
async getOrganization() {
|
||||
const { getOwnOrganizations } = await import('../../utils/sdk');
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk());
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk(), {
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
|
||||
if (organizations.length === 0) {
|
||||
// User is not a member of any organizations (should not happen).
|
||||
|
@ -65,7 +65,9 @@ export default class FleetPurgeCmd extends Command {
|
||||
|
||||
// balena.models.application.purge only accepts a numeric id
|
||||
// so we must first fetch the app to get it's id,
|
||||
const application = await getApplication(balena, params.fleet);
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$select: 'id',
|
||||
});
|
||||
|
||||
try {
|
||||
await balena.models.application.purge(application.id);
|
||||
|
@ -77,9 +77,10 @@ export default class FleetRenameCmd extends Command {
|
||||
// Disambiguate target application (if params.params is a number, it could either be an ID or a numerical name)
|
||||
const { getApplication } = await import('../../utils/sdk');
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$select: ['id', 'app_name', 'slug'],
|
||||
$expand: {
|
||||
application_type: {
|
||||
$select: ['slug'],
|
||||
$select: 'slug',
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -132,9 +133,9 @@ export default class FleetRenameCmd extends Command {
|
||||
}
|
||||
|
||||
// Get application again, to be sure of results
|
||||
const renamedApplication = await balena.models.application.get(
|
||||
application.id,
|
||||
);
|
||||
const renamedApplication = await getApplication(balena, application.id, {
|
||||
$select: ['app_name', 'slug'],
|
||||
});
|
||||
|
||||
// Output result
|
||||
console.log(`Fleet renamed`);
|
||||
|
@ -63,7 +63,9 @@ export default class FleetRestartCmd extends Command {
|
||||
const balena = getBalenaSdk();
|
||||
|
||||
// Disambiguate application
|
||||
const application = await getApplication(balena, params.fleet);
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$select: 'slug',
|
||||
});
|
||||
|
||||
await balena.models.application.restart(application.slug);
|
||||
}
|
||||
|
@ -76,7 +76,9 @@ export default class FleetRmCmd extends Command {
|
||||
);
|
||||
|
||||
// Disambiguate application (if is a number, it could either be an ID or a numerical name)
|
||||
const application = await getApplication(balena, params.fleet);
|
||||
const application = await getApplication(balena, params.fleet, {
|
||||
$select: 'slug',
|
||||
});
|
||||
|
||||
// Remove
|
||||
await balena.models.application.remove(application.slug);
|
||||
|
@ -46,7 +46,9 @@ export default class OrgsCmd extends Command {
|
||||
const { getOwnOrganizations } = await import('../utils/sdk');
|
||||
|
||||
// Get organizations
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk());
|
||||
const organizations = await getOwnOrganizations(getBalenaSdk(), {
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
|
||||
// Display
|
||||
console.log(
|
||||
|
@ -328,7 +328,7 @@ export default class PushCmd extends Command {
|
||||
]);
|
||||
|
||||
const application = await getApplication(sdk, appNameOrSlug, {
|
||||
$select: ['app_name', 'slug'],
|
||||
$select: 'slug',
|
||||
});
|
||||
|
||||
const opts = {
|
||||
|
@ -437,20 +437,6 @@ export const expandForAppName = {
|
||||
},
|
||||
} satisfies BalenaSdk.PineOptions<BalenaSdk.Device>;
|
||||
|
||||
export const expandForAppNameAndCpuArch = {
|
||||
$expand: {
|
||||
...expandForAppName.$expand,
|
||||
is_of__device_type: {
|
||||
$select: 'slug',
|
||||
$expand: {
|
||||
is_of__cpu_architecture: {
|
||||
$select: 'slug',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies BalenaSdk.PineOptions<BalenaSdk.Device>;
|
||||
|
||||
/**
|
||||
* Use the `readline` library on Windows to install SIGINT handlers.
|
||||
* This appears to be necessary on MSYS / Git for Windows, and also useful
|
||||
|
@ -14,7 +14,14 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import type { BalenaSDK, Device, Organization } from 'balena-sdk';
|
||||
import type {
|
||||
Application,
|
||||
BalenaSDK,
|
||||
Device,
|
||||
Organization,
|
||||
PineOptions,
|
||||
PineTypedResult,
|
||||
} from 'balena-sdk';
|
||||
import _ = require('lodash');
|
||||
|
||||
import { instanceOf, NotLoggedInError, ExpectedError } from '../errors';
|
||||
@ -157,18 +164,28 @@ export async function confirm(
|
||||
}
|
||||
}
|
||||
|
||||
const selectApplicationPineOptions = {
|
||||
$select: ['id', 'slug', 'app_name'],
|
||||
$expand: {
|
||||
is_for__device_type: {
|
||||
$select: 'slug',
|
||||
},
|
||||
},
|
||||
} satisfies PineOptions<Application>;
|
||||
|
||||
type SelectApplicationResult = PineTypedResult<
|
||||
Application,
|
||||
typeof selectApplicationPineOptions
|
||||
>;
|
||||
|
||||
export async function selectApplication(
|
||||
filter?: (app: ApplicationWithDeviceType) => boolean,
|
||||
filter?: (app: SelectApplicationResult) => boolean,
|
||||
errorOnEmptySelection = false,
|
||||
) {
|
||||
const balena = getBalenaSdk();
|
||||
const apps = (await balena.models.application.getAllDirectlyAccessible({
|
||||
$expand: {
|
||||
is_for__device_type: {
|
||||
$select: 'slug',
|
||||
},
|
||||
},
|
||||
})) as ApplicationWithDeviceType[];
|
||||
const apps = (await balena.models.application.getAllDirectlyAccessible(
|
||||
selectApplicationPineOptions,
|
||||
)) as SelectApplicationResult[];
|
||||
|
||||
if (!apps.length) {
|
||||
throw new ExpectedError('No fleets found');
|
||||
@ -193,7 +210,9 @@ export async function selectOrganization(
|
||||
organizations?: Array<Pick<Organization, 'handle' | 'name'>>,
|
||||
) {
|
||||
// Use either provided orgs (if e.g. already loaded) or load from cloud
|
||||
organizations ??= await getBalenaSdk().models.organization.getAll();
|
||||
organizations ??= await getBalenaSdk().models.organization.getAll({
|
||||
$select: ['name', 'handle'],
|
||||
});
|
||||
return getCliForm().ask({
|
||||
message: 'Select an organization',
|
||||
type: 'list',
|
||||
@ -296,7 +315,9 @@ export async function getOnlineTargetDeviceUuid(
|
||||
try {
|
||||
logger.logDebug(`Fetching fleet ${fleetOrDevice}`);
|
||||
const { getApplication } = await import('./sdk');
|
||||
return await getApplication(sdk, fleetOrDevice);
|
||||
return await getApplication(sdk, fleetOrDevice, {
|
||||
$select: ['id', 'slug'],
|
||||
});
|
||||
} catch (err) {
|
||||
const { BalenaApplicationNotFound } = await import('balena-errors');
|
||||
if (instanceOf(err, BalenaApplicationNotFound)) {
|
||||
|
@ -76,31 +76,44 @@ export async function getFleetSlug(
|
||||
if (!looksLikeFleetSlug(nameOrSlug)) {
|
||||
// Not a slug: must be an app name.
|
||||
// TODO: revisit this logic when we add support for fleet UUIDs.
|
||||
return (await getApplication(sdk, nameOrSlug)).slug;
|
||||
return (await getApplication(sdk, nameOrSlug, { $select: 'slug' })).slug;
|
||||
}
|
||||
return nameOrSlug.toLowerCase();
|
||||
}
|
||||
|
||||
export async function getOwnOrganizations(
|
||||
sdk: BalenaSDK,
|
||||
): Promise<Organization[]>;
|
||||
export async function getOwnOrganizations<TP extends PineOptions<Organization>>(
|
||||
sdk: BalenaSDK,
|
||||
options: TP,
|
||||
): Promise<Array<PineTypedResult<Organization, TP>>>;
|
||||
/**
|
||||
* Wraps the sdk organization.getAll method,
|
||||
* restricting to those orgs user is a member of
|
||||
*/
|
||||
export async function getOwnOrganizations(
|
||||
sdk: BalenaSDK,
|
||||
options?: PineOptions<Organization>,
|
||||
): Promise<Organization[]> {
|
||||
return await sdk.models.organization.getAll({
|
||||
$filter: {
|
||||
organization_membership: {
|
||||
$any: {
|
||||
$alias: 'orm',
|
||||
$expr: {
|
||||
orm: {
|
||||
user: await sdk.auth.getUserId(),
|
||||
return await sdk.models.organization.getAll(
|
||||
sdk.utils.mergePineOptions(
|
||||
{
|
||||
$filter: {
|
||||
organization_membership: {
|
||||
$any: {
|
||||
$alias: 'orm',
|
||||
$expr: {
|
||||
orm: {
|
||||
user: await sdk.auth.getUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
$orderby: 'name asc',
|
||||
},
|
||||
},
|
||||
$orderby: 'name asc',
|
||||
});
|
||||
options,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user