From aeff5997d02289619f3a2f1e3041144d559feb43 Mon Sep 17 00:00:00 2001 From: Scott Lowe Date: Wed, 30 Dec 2020 16:36:46 +0100 Subject: [PATCH] Refactor out command internal scandevices Change-type: patch Signed-off-by: Scott Lowe --- doc/cli.markdown | 6 +-- lib/commands/internal/scandevices.ts | 55 ------------------------ lib/commands/join.ts | 4 +- lib/commands/leave.ts | 7 ++-- lib/utils/promote.ts | 63 ++++++++++------------------ 5 files changed, 29 insertions(+), 106 deletions(-) delete mode 100644 lib/commands/internal/scandevices.ts diff --git a/doc/cli.markdown b/doc/cli.markdown index b5d18a8a..01d8c598 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -3191,8 +3191,8 @@ To move a device between applications on the same server, use the If you don't specify a device hostname or IP, this command will automatically scan the local network for balenaOS devices and prompt you to select one -from an interactive picker. This requires root privileges. Likewise, if -the application flag is not provided then a picker will be shown. +from an interactive picker. This may require administrator/root privileges. +Likewise, if the application flag is not provided then a picker will be shown. Applications may be specified by app name, slug, or numeric ID. App slugs are the recommended option, as they are unique and unambiguous. Slugs @@ -3243,7 +3243,7 @@ so the device can subsequently re-join the server if needed. If you don't specify a device hostname or IP, this command will automatically scan the local network for balenaOS devices and prompt you to select one -from an interactive picker. This usually requires root privileges. +from an interactive picker. This may require administrator/root privileges. Examples: diff --git a/lib/commands/internal/scandevices.ts b/lib/commands/internal/scandevices.ts deleted file mode 100644 index f32f5778..00000000 --- a/lib/commands/internal/scandevices.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @license - * Copyright 2016-2020 Balena Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import Command from '../../command'; -import { stripIndent } from '../../utils/lazy'; - -// 'Internal' commands are called during the execution of other commands. -// `scandevices` is called during by `join`,`leave'. -// TODO: These should be refactored to modules/functions, and removed -// See previous `internal sudo` refactor: -// - https://github.com/balena-io/balena-cli/pull/1455/files -// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308357 -// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308526 - -export default class ScandevicesCmd extends Command { - public static description = stripIndent` - Scan for local balena-enabled devices and show a picker to choose one. - - Don't use this command directly! - `; - - public static usage = 'internal scandevices'; - - public static root = true; - public static hidden = true; - - public async run() { - const { forms } = await import('balena-sync'); - try { - const hostnameOrIp = await forms.selectLocalBalenaOsDevice(); - return console.error(`==> Selected device: ${hostnameOrIp}`); - } catch (e) { - if (e.message.toLowerCase().includes('could not find any')) { - const { ExpectedError } = await import('../../errors'); - throw new ExpectedError(e); - } else { - throw e; - } - } - } -} diff --git a/lib/commands/join.ts b/lib/commands/join.ts index 01f395a6..8d84b692 100644 --- a/lib/commands/join.ts +++ b/lib/commands/join.ts @@ -48,8 +48,8 @@ export default class JoinCmd extends Command { If you don't specify a device hostname or IP, this command will automatically scan the local network for balenaOS devices and prompt you to select one - from an interactive picker. This requires root privileges. Likewise, if - the application flag is not provided then a picker will be shown. + from an interactive picker. This may require administrator/root privileges. + Likewise, if the application flag is not provided then a picker will be shown. ${applicationIdInfo.split('\n').join('\n\t\t')} `; diff --git a/lib/commands/leave.ts b/lib/commands/leave.ts index 4aa47240..119ea676 100644 --- a/lib/commands/leave.ts +++ b/lib/commands/leave.ts @@ -18,7 +18,7 @@ import { flags } from '@oclif/command'; import Command from '../command'; import * as cf from '../utils/common-flags'; -import { getBalenaSdk, stripIndent } from '../utils/lazy'; +import { stripIndent } from '../utils/lazy'; import { parseAsLocalHostnameOrIp } from '../utils/validation'; interface FlagsDef { @@ -42,7 +42,7 @@ export default class LeaveCmd extends Command { If you don't specify a device hostname or IP, this command will automatically scan the local network for balenaOS devices and prompt you to select one - from an interactive picker. This usually requires root privileges. + from an interactive picker. This may require administrator/root privileges. `; public static examples = [ @@ -72,8 +72,7 @@ export default class LeaveCmd extends Command { const { args: params } = this.parse(LeaveCmd); const promote = await import('../utils/promote'); - const sdk = getBalenaSdk(); const logger = await Command.getLogger(); - return promote.leave(logger, sdk, params.deviceIpOrHostname); + return promote.leave(logger, params.deviceIpOrHostname); } } diff --git a/lib/utils/promote.ts b/lib/utils/promote.ts index bbe3146a..1f8ff662 100644 --- a/lib/utils/promote.ts +++ b/lib/utils/promote.ts @@ -31,12 +31,12 @@ export async function join( appUpdatePollInterval?: number, ): Promise { logger.logDebug('Determining device...'); - const deviceIp = await getOrSelectLocalDevice(deviceHostnameOrIp); - await assertDeviceIsCompatible(deviceIp); - logger.logDebug(`Using device: ${deviceIp}`); + deviceHostnameOrIp = deviceHostnameOrIp || (await selectLocalDevice()); + await assertDeviceIsCompatible(deviceHostnameOrIp); + logger.logDebug(`Using device: ${deviceHostnameOrIp}`); logger.logDebug('Determining device type...'); - const deviceType = await getDeviceType(deviceIp); + const deviceType = await getDeviceType(deviceHostnameOrIp); logger.logDebug(`Device type: ${deviceType}`); logger.logDebug('Determining application...'); @@ -50,7 +50,7 @@ export async function join( } logger.logDebug('Determining device OS version...'); - const deviceOsVersion = await getOsVersion(deviceIp); + const deviceOsVersion = await getOsVersion(deviceHostnameOrIp); logger.logDebug(`Device OS version: ${deviceOsVersion}`); logger.logDebug('Generating application config...'); @@ -61,8 +61,7 @@ export async function join( logger.logDebug(`Using config: ${JSON.stringify(config, null, 2)}`); logger.logDebug('Configuring...'); - await configure(deviceIp, config); - logger.logDebug('All done.'); + await configure(deviceHostnameOrIp, config); const platformUrl = await sdk.settings.get('balenaUrl'); logger.logSuccess(`Device successfully joined ${platformUrl}!`); @@ -70,17 +69,15 @@ export async function join( export async function leave( logger: Logger, - _sdk: BalenaSdk.BalenaSDK, deviceHostnameOrIp?: string, ): Promise { logger.logDebug('Determining device...'); - const deviceIp = await getOrSelectLocalDevice(deviceHostnameOrIp); - await assertDeviceIsCompatible(deviceIp); - logger.logDebug(`Using device: ${deviceIp}`); + deviceHostnameOrIp = deviceHostnameOrIp || (await selectLocalDevice()); + await assertDeviceIsCompatible(deviceHostnameOrIp); + logger.logDebug(`Using device: ${deviceHostnameOrIp}`); logger.logDebug('Deconfiguring...'); - await deconfigure(deviceIp); - logger.logDebug('All done.'); + await deconfigure(deviceHostnameOrIp); logger.logSuccess('Device successfully left the platform.'); } @@ -155,39 +152,21 @@ async function getOsVersion(deviceIp: string): Promise { return match[1]; } -async function getOrSelectLocalDevice(deviceIp?: string): Promise { - if (deviceIp) { - return deviceIp; - } - - const through = await import('through2'); - - let ip: string | null = null; - const stream = through(function (data, _enc, cb) { - const match = /^==> Selected device: (.*)$/m.exec(data.toString()); - if (match) { - ip = match[1]; - cb(); +async function selectLocalDevice(): Promise { + const { forms } = await import('balena-sync'); + let hostnameOrIp; + try { + hostnameOrIp = await forms.selectLocalBalenaOsDevice(); + console.error(`==> Selected device: ${hostnameOrIp}`); + } catch (e) { + if (e.message.toLowerCase().includes('could not find any')) { + throw new ExpectedError(e); } else { - cb(null, data); + throw e; } - }); - - stream.pipe(process.stderr); - - const { sudo } = await import('../utils/helpers'); - const command = ['internal', 'scandevices']; - await sudo(command, { - stderr: stream, - msg: - 'Scanning for local devices. If asked, please type your computer password.', - }); - - if (!ip) { - throw new ExpectedError('No device selected'); } - return ip; + return hostnameOrIp; } async function selectAppFromList(