mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-01-18 18:56:25 +00:00
Merge pull request #1871 from balena-io/convert-devices
Convert device commands to oclif
This commit is contained in:
commit
795057338f
@ -51,6 +51,15 @@ const capitanoDoc = {
|
|||||||
title: 'Device',
|
title: 'Device',
|
||||||
files: [
|
files: [
|
||||||
'build/actions/device.js',
|
'build/actions/device.js',
|
||||||
|
'build/actions-oclif/device/identify.js',
|
||||||
|
'build/actions-oclif/device/index.js',
|
||||||
|
'build/actions-oclif/device/move.js',
|
||||||
|
'build/actions-oclif/device/reboot.js',
|
||||||
|
'build/actions-oclif/device/register.js',
|
||||||
|
'build/actions-oclif/device/rename.js',
|
||||||
|
'build/actions-oclif/device/rm.js',
|
||||||
|
'build/actions-oclif/device/shutdown.js',
|
||||||
|
'build/actions-oclif/devices/index.js',
|
||||||
'build/actions-oclif/devices/supported.js',
|
'build/actions-oclif/devices/supported.js',
|
||||||
'build/actions-oclif/device/public-url.js',
|
'build/actions-oclif/device/public-url.js',
|
||||||
],
|
],
|
||||||
|
335
doc/cli.markdown
335
doc/cli.markdown
@ -167,17 +167,17 @@ Users are encouraged to regularly update the balena CLI to the latest version.
|
|||||||
|
|
||||||
- Device
|
- Device
|
||||||
|
|
||||||
- [devices](#devices)
|
|
||||||
- [device <uuid>](#device-uuid)
|
|
||||||
- [device register <application>](#device-register-application)
|
|
||||||
- [device rm <uuid>](#device-rm-uuid)
|
|
||||||
- [device identify <uuid>](#device-identify-uuid)
|
|
||||||
- [device reboot <uuid>](#device-reboot-uuid)
|
|
||||||
- [device shutdown <uuid>](#device-shutdown-uuid)
|
|
||||||
- [device rename <uuid> [newName]](#device-rename-uuid-newname)
|
|
||||||
- [device move <uuid>](#device-move-uuid)
|
|
||||||
- [device init](#device-init)
|
- [device init](#device-init)
|
||||||
- [device os-update <uuid>](#device-os-update-uuid)
|
- [device os-update <uuid>](#device-os-update-uuid)
|
||||||
|
- [device identify <uuid>](#device-identify-uuid)
|
||||||
|
- [device <uuid>](#device-uuid)
|
||||||
|
- [device move <uuid>](#device-move-uuid)
|
||||||
|
- [device reboot <uuid>](#device-reboot-uuid)
|
||||||
|
- [device register <application>](#device-register-application)
|
||||||
|
- [device rename <uuid> [newname]](#device-rename-uuid-newname)
|
||||||
|
- [device rm <uuid>](#device-rm-uuid)
|
||||||
|
- [device shutdown <uuid>](#device-shutdown-uuid)
|
||||||
|
- [devices](#devices)
|
||||||
- [devices supported](#devices-supported)
|
- [devices supported](#devices-supported)
|
||||||
- [device public-url <uuid>](#device-public-url-uuid)
|
- [device public-url <uuid>](#device-public-url-uuid)
|
||||||
|
|
||||||
@ -454,132 +454,6 @@ Examples:
|
|||||||
|
|
||||||
# Device
|
# Device
|
||||||
|
|
||||||
## devices
|
|
||||||
|
|
||||||
Use this command to list all devices that belong to you.
|
|
||||||
|
|
||||||
You can filter the devices by application by using the `--application` option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena devices
|
|
||||||
$ balena devices --application MyApp
|
|
||||||
$ balena devices --app MyApp
|
|
||||||
$ balena devices -a MyApp
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --application, -a, --app <application>
|
|
||||||
|
|
||||||
application name
|
|
||||||
|
|
||||||
## device <uuid>
|
|
||||||
|
|
||||||
Use this command to show information about a single device.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device 7cf02a6
|
|
||||||
|
|
||||||
## device register <application>
|
|
||||||
|
|
||||||
Use this command to register a device to an application.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device register MyApp
|
|
||||||
$ balena device register MyApp --uuid <uuid>
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --uuid, -u <uuid>
|
|
||||||
|
|
||||||
custom uuid
|
|
||||||
|
|
||||||
## device rm <uuid>
|
|
||||||
|
|
||||||
Use this command to remove a device from balena.
|
|
||||||
|
|
||||||
Notice this command asks for confirmation interactively.
|
|
||||||
You can avoid this by passing the `--yes` boolean option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device rm 7cf02a6
|
|
||||||
$ balena device rm 7cf02a6 --yes
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --yes, -y
|
|
||||||
|
|
||||||
confirm non interactively
|
|
||||||
|
|
||||||
## device identify <uuid>
|
|
||||||
|
|
||||||
Use this command to identify a device.
|
|
||||||
|
|
||||||
In the Raspberry Pi, the ACT led is blinked several times.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device identify 23c73a1
|
|
||||||
|
|
||||||
## device reboot <uuid>
|
|
||||||
|
|
||||||
Use this command to remotely reboot a device
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device reboot 23c73a1
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --force, -f
|
|
||||||
|
|
||||||
force action if the update lock is set
|
|
||||||
|
|
||||||
## device shutdown <uuid>
|
|
||||||
|
|
||||||
Use this command to remotely shutdown a device
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device shutdown 23c73a1
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --force, -f
|
|
||||||
|
|
||||||
force action if the update lock is set
|
|
||||||
|
|
||||||
## device rename <uuid> [newName]
|
|
||||||
|
|
||||||
Use this command to rename a device.
|
|
||||||
|
|
||||||
If you omit the name, you'll get asked for it interactively.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device rename 7cf02a6
|
|
||||||
$ balena device rename 7cf02a6 MyPi
|
|
||||||
|
|
||||||
## device move <uuid>
|
|
||||||
|
|
||||||
Use this command to move a device to another application you own.
|
|
||||||
|
|
||||||
If you omit the application, you'll get asked for it interactively.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device move 7cf02a6
|
|
||||||
$ balena device move 7cf02a6 --application MyNewApp
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
#### --application, -a, --app <application>
|
|
||||||
|
|
||||||
application name
|
|
||||||
|
|
||||||
## device init
|
## device init
|
||||||
|
|
||||||
Use this command to download the OS image of a certain application and write it to an SD Card.
|
Use this command to download the OS image of a certain application and write it to an SD Card.
|
||||||
@ -646,6 +520,197 @@ a balenaOS version
|
|||||||
|
|
||||||
confirm non interactively
|
confirm non interactively
|
||||||
|
|
||||||
|
## device identify <uuid>
|
||||||
|
|
||||||
|
Identify a device by making the ACT LED blink (Raspberry Pi).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device identify 23c73a1
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to identify
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
## device <uuid>
|
||||||
|
|
||||||
|
Show information about a single device.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device 7cf02a6
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the device uuid
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
## device move <uuid>
|
||||||
|
|
||||||
|
Move a device to another application.
|
||||||
|
|
||||||
|
Note, if the application option is omitted it will be prompted
|
||||||
|
for interactively.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device move 7cf02a6
|
||||||
|
$ balena device move 7cf02a6 --application MyNewApp
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to move
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -a, --application APPLICATION
|
||||||
|
|
||||||
|
application name
|
||||||
|
|
||||||
|
#### --app APP
|
||||||
|
|
||||||
|
same as '--application'
|
||||||
|
|
||||||
|
## device reboot <uuid>
|
||||||
|
|
||||||
|
Remotely reboot a device.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device reboot 23c73a1
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to reboot
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -f, --force
|
||||||
|
|
||||||
|
force action if the update lock is set
|
||||||
|
|
||||||
|
## device register <application>
|
||||||
|
|
||||||
|
Register a device to an application.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device register MyApp
|
||||||
|
$ balena device register MyApp --uuid <uuid>
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### APPLICATION
|
||||||
|
|
||||||
|
the name or id of application to register device with
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -u, --uuid UUID
|
||||||
|
|
||||||
|
custom uuid
|
||||||
|
|
||||||
|
## device rename <uuid> [newName]
|
||||||
|
|
||||||
|
Rename a device.
|
||||||
|
|
||||||
|
Note, if the name is omitted, it will be prompted for interactively.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device rename 7cf02a6
|
||||||
|
$ balena device rename 7cf02a6 MyPi
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to rename
|
||||||
|
|
||||||
|
#### NEWNAME
|
||||||
|
|
||||||
|
the new name for the device
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
## device rm <uuid>
|
||||||
|
|
||||||
|
Remove a device from balena.
|
||||||
|
|
||||||
|
Note this command asks for confirmation interactively.
|
||||||
|
You can avoid this by passing the `--yes` option.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device rm 7cf02a6
|
||||||
|
$ balena device rm 7cf02a6 --yes
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to remove
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -y, --yes
|
||||||
|
|
||||||
|
answer "yes" to all questions (non interactive use)
|
||||||
|
|
||||||
|
## device shutdown <uuid>
|
||||||
|
|
||||||
|
Remotely shutdown a device.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena device shutdown 23c73a1
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
|
#### UUID
|
||||||
|
|
||||||
|
the uuid of the device to shutdown
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -f, --force
|
||||||
|
|
||||||
|
force action if the update lock is set
|
||||||
|
|
||||||
|
## devices
|
||||||
|
|
||||||
|
list all devices that belong to you.
|
||||||
|
|
||||||
|
You can filter the devices by application by using the `--application` option.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
$ balena devices
|
||||||
|
$ balena devices --application MyApp
|
||||||
|
$ balena devices --app MyApp
|
||||||
|
$ balena devices -a MyApp
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
#### -a, --application APPLICATION
|
||||||
|
|
||||||
|
application name
|
||||||
|
|
||||||
|
#### --app APP
|
||||||
|
|
||||||
|
same as '--application'
|
||||||
|
|
||||||
## devices supported
|
## devices supported
|
||||||
|
|
||||||
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
List the supported device types (like 'raspberrypi3' or 'intel-nuc').
|
||||||
|
75
lib/actions-oclif/device/identify.ts
Normal file
75
lib/actions-oclif/device/identify.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
import { ExpectedError } from '../../errors';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceIdentifyCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Identify a device.
|
||||||
|
|
||||||
|
Identify a device by making the ACT LED blink (Raspberry Pi).
|
||||||
|
`;
|
||||||
|
public static examples = ['$ balena device identify 23c73a1'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to identify',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device identify <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceIdentifyCmd);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await balena.models.device.identify(params.uuid);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message === 'Request error: No online device(s) found') {
|
||||||
|
throw new ExpectedError(`Device ${params.uuid} is not online`);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
lib/actions-oclif/device/index.ts
Normal file
110
lib/actions-oclif/device/index.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { expandForAppName } from '../../utils/helpers';
|
||||||
|
import { getBalenaSdk, getVisuals } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
import { Application, Device } from 'balena-sdk';
|
||||||
|
|
||||||
|
interface ExtendedDevice extends Device {
|
||||||
|
dashboard_url?: string;
|
||||||
|
application_name?: string;
|
||||||
|
commit?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Show info about a single device.
|
||||||
|
|
||||||
|
Show information about a single device.
|
||||||
|
`;
|
||||||
|
public static examples = ['$ balena device 7cf02a6'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the device uuid',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
public static primary = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceCmd);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
const device: ExtendedDevice = await balena.models.device.get(
|
||||||
|
params.uuid,
|
||||||
|
expandForAppName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const deviceStatus = await balena.models.device.getStatus(device.uuid);
|
||||||
|
device.status = deviceStatus;
|
||||||
|
|
||||||
|
device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid);
|
||||||
|
|
||||||
|
const belongsToApplication = device.belongs_to__application as Application[];
|
||||||
|
device.application_name = belongsToApplication?.[0]
|
||||||
|
? belongsToApplication[0].app_name
|
||||||
|
: 'N/a';
|
||||||
|
|
||||||
|
device.commit = device.is_on__commit;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
getVisuals().table.vertical(device, [
|
||||||
|
`$${device.device_name}$`,
|
||||||
|
'id',
|
||||||
|
'device_type',
|
||||||
|
'status',
|
||||||
|
'is_online',
|
||||||
|
'ip_address',
|
||||||
|
'application_name',
|
||||||
|
'last_seen',
|
||||||
|
'uuid',
|
||||||
|
'commit',
|
||||||
|
'supervisor_version',
|
||||||
|
'is_web_accessible',
|
||||||
|
'note',
|
||||||
|
'os_version',
|
||||||
|
'dashboard_url',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
131
lib/actions-oclif/device/move.ts
Normal file
131
lib/actions-oclif/device/move.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { Application, Device } from 'balena-sdk';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { expandForAppName } from '../../utils/helpers';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
interface ExtendedDevice extends Device {
|
||||||
|
application_name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
application?: string;
|
||||||
|
app?: string;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceMoveCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Move a device to another application.
|
||||||
|
|
||||||
|
Move a device to another application.
|
||||||
|
|
||||||
|
Note, if the application option is omitted it will be prompted
|
||||||
|
for interactively.
|
||||||
|
`;
|
||||||
|
public static examples = [
|
||||||
|
'$ balena device move 7cf02a6',
|
||||||
|
'$ balena device move 7cf02a6 --application MyNewApp',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to move',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device move <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
application: cf.application,
|
||||||
|
app: cf.app,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
DeviceMoveCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
const patterns = await import('../../utils/patterns');
|
||||||
|
|
||||||
|
// Consolidate application options
|
||||||
|
options.application = options.application || options.app;
|
||||||
|
delete options.app;
|
||||||
|
|
||||||
|
const device: ExtendedDevice = await balena.models.device.get(
|
||||||
|
params.uuid,
|
||||||
|
expandForAppName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const belongsToApplication = device.belongs_to__application as Application[];
|
||||||
|
device.application_name = belongsToApplication?.[0]
|
||||||
|
? belongsToApplication[0].app_name
|
||||||
|
: 'N/a';
|
||||||
|
|
||||||
|
// Get destination application
|
||||||
|
let application;
|
||||||
|
if (options.application) {
|
||||||
|
application = options.application;
|
||||||
|
} else {
|
||||||
|
const [deviceDeviceType, deviceTypes] = await Promise.all([
|
||||||
|
balena.models.device.getManifestBySlug(device.device_type),
|
||||||
|
balena.models.config.getDeviceTypes(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const compatibleDeviceTypes = deviceTypes.filter(
|
||||||
|
(dt) =>
|
||||||
|
balena.models.os.isArchitectureCompatibleWith(
|
||||||
|
deviceDeviceType.arch,
|
||||||
|
dt.arch,
|
||||||
|
) &&
|
||||||
|
!!dt.isDependent === !!deviceDeviceType.isDependent &&
|
||||||
|
dt.state !== 'DISCONTINUED',
|
||||||
|
);
|
||||||
|
|
||||||
|
application = await patterns.selectApplication((app: Application) =>
|
||||||
|
_.every([
|
||||||
|
_.some(compatibleDeviceTypes, (dt) => dt.slug === app.device_type),
|
||||||
|
// @ts-ignore using the extended device object prop
|
||||||
|
device.application_name !== app.app_name,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await balena.models.device.move(params.uuid, tryAsInteger(application));
|
||||||
|
|
||||||
|
console.info(`${params.uuid} was moved to ${application}`);
|
||||||
|
}
|
||||||
|
}
|
73
lib/actions-oclif/device/reboot.ts
Normal file
73
lib/actions-oclif/device/reboot.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
force: boolean;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceRebootCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Restart a device.
|
||||||
|
|
||||||
|
Remotely reboot a device.
|
||||||
|
`;
|
||||||
|
public static examples = ['$ balena device reboot 23c73a1'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to reboot',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device reboot <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
force: cf.force,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
DeviceRebootCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
// The SDK current throws "BalenaDeviceNotFound: Device not found: xxxxx"
|
||||||
|
// when the device is not online, which may be confusing.
|
||||||
|
// https://github.com/balena-io/balena-cli/issues/1872
|
||||||
|
await balena.models.device.reboot(params.uuid, options);
|
||||||
|
}
|
||||||
|
}
|
83
lib/actions-oclif/device/register.ts
Normal file
83
lib/actions-oclif/device/register.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
uuid?: string;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
application: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceRegisterCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Register a device.
|
||||||
|
|
||||||
|
Register a device to an application.
|
||||||
|
`;
|
||||||
|
public static examples = [
|
||||||
|
'$ balena device register MyApp',
|
||||||
|
'$ balena device register MyApp --uuid <uuid>',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'application',
|
||||||
|
description: 'the name or id of application to register device with',
|
||||||
|
parse: (app) => tryAsInteger(app),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device register <application>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
uuid: flags.string({
|
||||||
|
description: 'custom uuid',
|
||||||
|
char: 'u',
|
||||||
|
}),
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
DeviceRegisterCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
const application = await balena.models.application.get(params.application);
|
||||||
|
const uuid = options.uuid ?? balena.models.device.generateUniqueKey();
|
||||||
|
|
||||||
|
console.info(`Registering to ${application.app_name}: ${uuid}`);
|
||||||
|
|
||||||
|
const result = await balena.models.device.register(application.id, uuid);
|
||||||
|
|
||||||
|
return result && result.uuid;
|
||||||
|
}
|
||||||
|
}
|
85
lib/actions-oclif/device/rename.ts
Normal file
85
lib/actions-oclif/device/rename.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
newName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceRenameCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Rename a device.
|
||||||
|
|
||||||
|
Rename a device.
|
||||||
|
|
||||||
|
Note, if the name is omitted, it will be prompted for interactively.
|
||||||
|
`;
|
||||||
|
public static examples = [
|
||||||
|
'$ balena device rename 7cf02a6',
|
||||||
|
'$ balena device rename 7cf02a6 MyPi',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to rename',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'newName',
|
||||||
|
description: 'the new name for the device',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device rename <uuid> [newName]';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params } = this.parse<FlagsDef, ArgsDef>(DeviceRenameCmd);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
const form = await import('resin-cli-form');
|
||||||
|
|
||||||
|
const newName =
|
||||||
|
params.newName ||
|
||||||
|
(await form.ask({
|
||||||
|
message: 'How do you want to name this device?',
|
||||||
|
type: 'input',
|
||||||
|
})) ||
|
||||||
|
'';
|
||||||
|
|
||||||
|
await balena.models.device.rename(params.uuid, newName);
|
||||||
|
}
|
||||||
|
}
|
84
lib/actions-oclif/device/rm.ts
Normal file
84
lib/actions-oclif/device/rm.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
yes: boolean;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceRmCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Remove a device.
|
||||||
|
|
||||||
|
Remove a device from balena.
|
||||||
|
|
||||||
|
Note this command asks for confirmation interactively.
|
||||||
|
You can avoid this by passing the \`--yes\` option.
|
||||||
|
`;
|
||||||
|
public static examples = [
|
||||||
|
'$ balena device rm 7cf02a6',
|
||||||
|
'$ balena device rm 7cf02a6 --yes',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to remove',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device rm <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
yes: cf.yes,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
DeviceRmCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
const patterns = await import('../../utils/patterns');
|
||||||
|
|
||||||
|
// Confirm
|
||||||
|
await patterns.confirm(
|
||||||
|
options.yes,
|
||||||
|
'Are you sure you want to delete the device?',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
await balena.models.device.remove(params.uuid);
|
||||||
|
}
|
||||||
|
}
|
79
lib/actions-oclif/device/shutdown.ts
Normal file
79
lib/actions-oclif/device/shutdown.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { IArg } from '@oclif/parser/lib/args';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { getBalenaSdk } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
import { ExpectedError } from '../../errors';
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
force: boolean;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArgsDef {
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DeviceShutdownCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
Shutdown a device.
|
||||||
|
|
||||||
|
Remotely shutdown a device.
|
||||||
|
`;
|
||||||
|
public static examples = ['$ balena device shutdown 23c73a1'];
|
||||||
|
|
||||||
|
public static args: Array<IArg<any>> = [
|
||||||
|
{
|
||||||
|
name: 'uuid',
|
||||||
|
description: 'the uuid of the device to shutdown',
|
||||||
|
parse: (dev) => tryAsInteger(dev),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'device shutdown <uuid>';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
force: cf.force,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
|
||||||
|
DeviceShutdownCmd,
|
||||||
|
);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await balena.models.device.shutdown(params.uuid, options);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message === 'Request error: No online device(s) found') {
|
||||||
|
throw new ExpectedError(`Device ${params.uuid} is not online`);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
lib/actions-oclif/devices/index.ts
Normal file
113
lib/actions-oclif/devices/index.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* @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 { flags } from '@oclif/command';
|
||||||
|
import { stripIndent } from 'common-tags';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import Command from '../../command';
|
||||||
|
import * as cf from '../../utils/common-flags';
|
||||||
|
import { expandForAppName } from '../../utils/helpers';
|
||||||
|
import { getBalenaSdk, getVisuals } from '../../utils/lazy';
|
||||||
|
import { tryAsInteger } from '../../utils/validation';
|
||||||
|
import { Device, Application } from 'balena-sdk';
|
||||||
|
|
||||||
|
interface ExtendedDevice extends Device {
|
||||||
|
dashboard_url?: string;
|
||||||
|
application_name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FlagsDef {
|
||||||
|
application?: string;
|
||||||
|
app?: string;
|
||||||
|
help: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DevicesCmd extends Command {
|
||||||
|
public static description = stripIndent`
|
||||||
|
List all devices.
|
||||||
|
|
||||||
|
list all devices that belong to you.
|
||||||
|
|
||||||
|
You can filter the devices by application by using the \`--application\` option.
|
||||||
|
`;
|
||||||
|
public static examples = [
|
||||||
|
'$ balena devices',
|
||||||
|
'$ balena devices --application MyApp',
|
||||||
|
'$ balena devices --app MyApp',
|
||||||
|
'$ balena devices -a MyApp',
|
||||||
|
];
|
||||||
|
|
||||||
|
public static usage = 'devices';
|
||||||
|
|
||||||
|
public static flags: flags.Input<FlagsDef> = {
|
||||||
|
application: cf.application,
|
||||||
|
app: cf.app,
|
||||||
|
help: cf.help,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static primary = true;
|
||||||
|
|
||||||
|
public static authenticated = true;
|
||||||
|
|
||||||
|
public async run() {
|
||||||
|
const { flags: options } = this.parse<FlagsDef, {}>(DevicesCmd);
|
||||||
|
|
||||||
|
const balena = getBalenaSdk();
|
||||||
|
|
||||||
|
// Consolidate application options
|
||||||
|
options.application = options.application || options.app;
|
||||||
|
delete options.app;
|
||||||
|
|
||||||
|
let devices: ExtendedDevice[];
|
||||||
|
|
||||||
|
if (options.application != null) {
|
||||||
|
devices = await balena.models.device.getAllByApplication(
|
||||||
|
tryAsInteger(options.application),
|
||||||
|
expandForAppName,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
devices = await balena.models.device.getAll(expandForAppName);
|
||||||
|
}
|
||||||
|
|
||||||
|
devices = _.map(devices, function (device) {
|
||||||
|
device.dashboard_url = balena.models.device.getDashboardUrl(device.uuid);
|
||||||
|
|
||||||
|
const belongsToApplication = device.belongs_to__application as Application[];
|
||||||
|
device.application_name = belongsToApplication?.[0]
|
||||||
|
? belongsToApplication[0].app_name
|
||||||
|
: 'N/a';
|
||||||
|
|
||||||
|
device.uuid = device.uuid.slice(0, 7);
|
||||||
|
return device;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
getVisuals().table.horizontal(devices, [
|
||||||
|
'id',
|
||||||
|
'uuid',
|
||||||
|
'device_name',
|
||||||
|
'device_type',
|
||||||
|
'application_name',
|
||||||
|
'status',
|
||||||
|
'is_online',
|
||||||
|
'supervisor_version',
|
||||||
|
'os_version',
|
||||||
|
'dashboard_url',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -17,351 +17,7 @@ limitations under the License.
|
|||||||
import * as commandOptions from './command-options';
|
import * as commandOptions from './command-options';
|
||||||
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { normalizeUuidProp } from '../utils/normalization';
|
import { getBalenaSdk } from '../utils/lazy';
|
||||||
import { getBalenaSdk, getVisuals } from '../utils/lazy';
|
|
||||||
|
|
||||||
/** @type {import('balena-sdk').PineOptionsFor<import('balena-sdk').Device>} */
|
|
||||||
const expandForAppName = {
|
|
||||||
$expand: { belongs_to__application: { $select: 'app_name' } },
|
|
||||||
};
|
|
||||||
|
|
||||||
export const list = {
|
|
||||||
signature: 'devices',
|
|
||||||
description: 'list all devices',
|
|
||||||
help: `\
|
|
||||||
Use this command to list all devices that belong to you.
|
|
||||||
|
|
||||||
You can filter the devices by application by using the \`--application\` option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena devices
|
|
||||||
$ balena devices --application MyApp
|
|
||||||
$ balena devices --app MyApp
|
|
||||||
$ balena devices -a MyApp\
|
|
||||||
`,
|
|
||||||
options: [commandOptions.optionalApplication],
|
|
||||||
permission: 'user',
|
|
||||||
primary: true,
|
|
||||||
action(_params, options) {
|
|
||||||
const Promise = require('bluebird');
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
|
|
||||||
return Promise.try(function () {
|
|
||||||
if (options.application != null) {
|
|
||||||
return balena.models.device.getAllByApplication(
|
|
||||||
options.application,
|
|
||||||
expandForAppName,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return balena.models.device.getAll(expandForAppName);
|
|
||||||
}).tap(function (devices) {
|
|
||||||
devices = _.map(devices, function (device) {
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.dashboard_url = balena.models.device.getDashboardUrl(
|
|
||||||
device.uuid,
|
|
||||||
);
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.application_name = device.belongs_to__application?.[0]
|
|
||||||
? device.belongs_to__application[0].app_name
|
|
||||||
: 'N/a';
|
|
||||||
device.uuid = device.uuid.slice(0, 7);
|
|
||||||
return device;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
getVisuals().table.horizontal(devices, [
|
|
||||||
'id',
|
|
||||||
'uuid',
|
|
||||||
'device_name',
|
|
||||||
'device_type',
|
|
||||||
'application_name',
|
|
||||||
'status',
|
|
||||||
'is_online',
|
|
||||||
'supervisor_version',
|
|
||||||
'os_version',
|
|
||||||
'dashboard_url',
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const info = {
|
|
||||||
signature: 'device <uuid>',
|
|
||||||
description: 'list a single device',
|
|
||||||
help: `\
|
|
||||||
Use this command to show information about a single device.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device 7cf02a6\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
primary: true,
|
|
||||||
action(params) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
|
|
||||||
return balena.models.device
|
|
||||||
.get(params.uuid, expandForAppName)
|
|
||||||
.then((device) =>
|
|
||||||
// @ts-ignore `device.getStatus` requires a device with service info, but
|
|
||||||
// this device isn't typed with them, possibly needs fixing?
|
|
||||||
balena.models.device.getStatus(params.uuid).then(function (status) {
|
|
||||||
device.status = status;
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.dashboard_url = balena.models.device.getDashboardUrl(
|
|
||||||
device.uuid,
|
|
||||||
);
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.application_name = device.belongs_to__application?.[0]
|
|
||||||
? device.belongs_to__application[0].app_name
|
|
||||||
: 'N/a';
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.commit = device.is_on__commit;
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
getVisuals().table.vertical(device, [
|
|
||||||
`$${device.device_name}$`,
|
|
||||||
'id',
|
|
||||||
'device_type',
|
|
||||||
'status',
|
|
||||||
'is_online',
|
|
||||||
'ip_address',
|
|
||||||
'mac_address',
|
|
||||||
'application_name',
|
|
||||||
'last_seen',
|
|
||||||
'uuid',
|
|
||||||
'commit',
|
|
||||||
'supervisor_version',
|
|
||||||
'is_web_accessible',
|
|
||||||
'note',
|
|
||||||
'os_version',
|
|
||||||
'dashboard_url',
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const register = {
|
|
||||||
signature: 'device register <application>',
|
|
||||||
description: 'register a device',
|
|
||||||
help: `\
|
|
||||||
Use this command to register a device to an application.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device register MyApp
|
|
||||||
$ balena device register MyApp --uuid <uuid>\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
signature: 'uuid',
|
|
||||||
description: 'custom uuid',
|
|
||||||
parameter: 'uuid',
|
|
||||||
alias: 'u',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
action(params, options) {
|
|
||||||
const Promise = require('bluebird');
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
|
|
||||||
return Promise.join(
|
|
||||||
balena.models.application.get(params.application),
|
|
||||||
options.uuid ?? balena.models.device.generateUniqueKey(),
|
|
||||||
function (application, uuid) {
|
|
||||||
console.info(`Registering to ${application.app_name}: ${uuid}`);
|
|
||||||
return balena.models.device.register(application.id, uuid);
|
|
||||||
},
|
|
||||||
).get('uuid');
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const remove = {
|
|
||||||
signature: 'device rm <uuid>',
|
|
||||||
description: 'remove a device',
|
|
||||||
help: `\
|
|
||||||
Use this command to remove a device from balena.
|
|
||||||
|
|
||||||
Notice this command asks for confirmation interactively.
|
|
||||||
You can avoid this by passing the \`--yes\` boolean option.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device rm 7cf02a6
|
|
||||||
$ balena device rm 7cf02a6 --yes\
|
|
||||||
`,
|
|
||||||
options: [commandOptions.yes],
|
|
||||||
permission: 'user',
|
|
||||||
action(params, options) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
const patterns = require('../utils/patterns');
|
|
||||||
|
|
||||||
return patterns
|
|
||||||
.confirm(options.yes, 'Are you sure you want to delete the device?')
|
|
||||||
.then(() => balena.models.device.remove(params.uuid));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const identify = {
|
|
||||||
signature: 'device identify <uuid>',
|
|
||||||
description: 'identify a device with a UUID',
|
|
||||||
help: `\
|
|
||||||
Use this command to identify a device.
|
|
||||||
|
|
||||||
In the Raspberry Pi, the ACT led is blinked several times.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device identify 23c73a1\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
action(params) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
return balena.models.device.identify(params.uuid);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const reboot = {
|
|
||||||
signature: 'device reboot <uuid>',
|
|
||||||
description: 'restart a device',
|
|
||||||
help: `\
|
|
||||||
Use this command to remotely reboot a device
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device reboot 23c73a1\
|
|
||||||
`,
|
|
||||||
options: [commandOptions.forceUpdateLock],
|
|
||||||
permission: 'user',
|
|
||||||
action(params, options) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
return balena.models.device.reboot(params.uuid, options);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const shutdown = {
|
|
||||||
signature: 'device shutdown <uuid>',
|
|
||||||
description: 'shutdown a device',
|
|
||||||
help: `\
|
|
||||||
Use this command to remotely shutdown a device
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device shutdown 23c73a1\
|
|
||||||
`,
|
|
||||||
options: [commandOptions.forceUpdateLock],
|
|
||||||
permission: 'user',
|
|
||||||
action(params, options) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
return balena.models.device.shutdown(params.uuid, options);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const rename = {
|
|
||||||
signature: 'device rename <uuid> [newName]',
|
|
||||||
description: 'rename a balena device',
|
|
||||||
help: `\
|
|
||||||
Use this command to rename a device.
|
|
||||||
|
|
||||||
If you omit the name, you'll get asked for it interactively.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device rename 7cf02a6
|
|
||||||
$ balena device rename 7cf02a6 MyPi\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
action(params) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const Promise = require('bluebird');
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
const form = require('resin-cli-form');
|
|
||||||
|
|
||||||
return Promise.try(function () {
|
|
||||||
if (!_.isEmpty(params.newName)) {
|
|
||||||
return params.newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return form.ask({
|
|
||||||
message: 'How do you want to name this device?',
|
|
||||||
type: 'input',
|
|
||||||
});
|
|
||||||
}).then(_.partial(balena.models.device.rename, params.uuid));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const move = {
|
|
||||||
signature: 'device move <uuid>',
|
|
||||||
description: 'move a device to another application',
|
|
||||||
help: `\
|
|
||||||
Use this command to move a device to another application you own.
|
|
||||||
|
|
||||||
If you omit the application, you'll get asked for it interactively.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
$ balena device move 7cf02a6
|
|
||||||
$ balena device move 7cf02a6 --application MyNewApp\
|
|
||||||
`,
|
|
||||||
permission: 'user',
|
|
||||||
options: [commandOptions.optionalApplication],
|
|
||||||
action(params, options) {
|
|
||||||
normalizeUuidProp(params);
|
|
||||||
const balena = getBalenaSdk();
|
|
||||||
const patterns = require('../utils/patterns');
|
|
||||||
|
|
||||||
return balena.models.device
|
|
||||||
.get(params.uuid, expandForAppName)
|
|
||||||
.then(function (device) {
|
|
||||||
// @ts-ignore extending the device object with extra props
|
|
||||||
device.application_name = device.belongs_to__application?.[0]
|
|
||||||
? device.belongs_to__application[0].app_name
|
|
||||||
: 'N/a';
|
|
||||||
if (options.application) {
|
|
||||||
return options.application;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
balena.models.device.getManifestBySlug(device.device_type),
|
|
||||||
balena.models.config.getDeviceTypes(),
|
|
||||||
]).then(function ([deviceDeviceType, deviceTypes]) {
|
|
||||||
const compatibleDeviceTypes = deviceTypes.filter(
|
|
||||||
(dt) =>
|
|
||||||
balena.models.os.isArchitectureCompatibleWith(
|
|
||||||
deviceDeviceType.arch,
|
|
||||||
dt.arch,
|
|
||||||
) &&
|
|
||||||
!!dt.isDependent === !!deviceDeviceType.isDependent &&
|
|
||||||
dt.state !== 'DISCONTINUED',
|
|
||||||
);
|
|
||||||
|
|
||||||
return patterns.selectApplication((application) =>
|
|
||||||
_.every([
|
|
||||||
_.some(
|
|
||||||
compatibleDeviceTypes,
|
|
||||||
(dt) => dt.slug === application.device_type,
|
|
||||||
),
|
|
||||||
// @ts-ignore using the extended device object prop
|
|
||||||
device.application_name !== application.app_name,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.tap((application) => balena.models.device.move(params.uuid, application))
|
|
||||||
.then((application) => {
|
|
||||||
console.info(`${params.uuid} was moved to ${application}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const init = {
|
export const init = {
|
||||||
signature: 'device init',
|
signature: 'device init',
|
||||||
|
@ -53,17 +53,8 @@ capitano.command(actions.auth.logout);
|
|||||||
capitano.command(actions.auth.whoami);
|
capitano.command(actions.auth.whoami);
|
||||||
|
|
||||||
// ---------- Device Module ----------
|
// ---------- Device Module ----------
|
||||||
capitano.command(actions.device.list);
|
|
||||||
capitano.command(actions.device.rename);
|
|
||||||
capitano.command(actions.device.init);
|
capitano.command(actions.device.init);
|
||||||
capitano.command(actions.device.remove);
|
|
||||||
capitano.command(actions.device.identify);
|
|
||||||
capitano.command(actions.device.reboot);
|
|
||||||
capitano.command(actions.device.shutdown);
|
|
||||||
capitano.command(actions.device.register);
|
|
||||||
capitano.command(actions.device.move);
|
|
||||||
capitano.command(actions.device.osUpdate);
|
capitano.command(actions.device.osUpdate);
|
||||||
capitano.command(actions.device.info);
|
|
||||||
|
|
||||||
// ---------- OS Module ----------
|
// ---------- OS Module ----------
|
||||||
capitano.command(actions.os.versions);
|
capitano.command(actions.os.versions);
|
||||||
|
@ -139,7 +139,8 @@ const EXPECTED_ERROR_REGEXES = [
|
|||||||
/^BalenaApplicationNotFound/, // balena-sdk
|
/^BalenaApplicationNotFound/, // balena-sdk
|
||||||
/^BalenaDeviceNotFound/, // balena-sdk
|
/^BalenaDeviceNotFound/, // balena-sdk
|
||||||
/^BalenaExpiredToken/, // balena-sdk
|
/^BalenaExpiredToken/, // balena-sdk
|
||||||
/^Missing \w+$/, // Capitano, oclif parser: RequiredArgsError, RequiredFlagError
|
/^Missing \w+$/, // Capitano,
|
||||||
|
/^Missing \d required argument/, // oclif parser: RequiredArgsError, RequiredFlagError
|
||||||
/^Unexpected argument/, // oclif parser: UnexpectedArgsError
|
/^Unexpected argument/, // oclif parser: UnexpectedArgsError
|
||||||
/to be one of/, // oclif parser: FlagInvalidOptionError, ArgInvalidOptionError
|
/to be one of/, // oclif parser: FlagInvalidOptionError, ArgInvalidOptionError
|
||||||
];
|
];
|
||||||
|
@ -141,7 +141,16 @@ export const convertedCommands = [
|
|||||||
'app:rm',
|
'app:rm',
|
||||||
'apps',
|
'apps',
|
||||||
'api-key:generate',
|
'api-key:generate',
|
||||||
|
'device',
|
||||||
|
'device:identify',
|
||||||
|
'device:move',
|
||||||
'device:public-url',
|
'device:public-url',
|
||||||
|
'device:reboot',
|
||||||
|
'device:register',
|
||||||
|
'device:rename',
|
||||||
|
'device:rm',
|
||||||
|
'device:shutdown',
|
||||||
|
'devices',
|
||||||
'devices:supported',
|
'devices:supported',
|
||||||
'envs',
|
'envs',
|
||||||
'env:add',
|
'env:add',
|
||||||
|
@ -23,6 +23,10 @@ export const application = flags.string({
|
|||||||
char: 'a',
|
char: 'a',
|
||||||
description: 'application name',
|
description: 'application name',
|
||||||
});
|
});
|
||||||
|
// TODO: Consider remove second alias 'app' when we can, to simplify.
|
||||||
|
export const app = flags.string({
|
||||||
|
description: "same as '--application'",
|
||||||
|
});
|
||||||
|
|
||||||
export const device = flags.string({
|
export const device = flags.string({
|
||||||
char: 'd',
|
char: 'd',
|
||||||
@ -56,3 +60,8 @@ export const yes: IBooleanFlag<boolean> = flags.boolean({
|
|||||||
char: 'y',
|
char: 'y',
|
||||||
description: 'answer "yes" to all questions (non interactive use)',
|
description: 'answer "yes" to all questions (non interactive use)',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const force: IBooleanFlag<boolean> = flags.boolean({
|
||||||
|
char: 'f',
|
||||||
|
description: 'force action if the update lock is set',
|
||||||
|
});
|
||||||
|
@ -22,6 +22,7 @@ import * as _ from 'lodash';
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as ShellEscape from 'shell-escape';
|
import * as ShellEscape from 'shell-escape';
|
||||||
|
|
||||||
|
import { Device, PineOptionsFor } from 'balena-sdk';
|
||||||
import { ExpectedError } from '../errors';
|
import { ExpectedError } from '../errors';
|
||||||
import { getBalenaSdk, getChalk, getVisuals } from './lazy';
|
import { getBalenaSdk, getChalk, getVisuals } from './lazy';
|
||||||
|
|
||||||
@ -466,3 +467,7 @@ export function getProxyConfig(): ProxyConfig | undefined {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const expandForAppName: PineOptionsFor<Device> = {
|
||||||
|
$expand: { belongs_to__application: { $select: 'app_name' } },
|
||||||
|
};
|
||||||
|
@ -20,20 +20,28 @@ import { BalenaAPIMock } from '../../balena-api-mock';
|
|||||||
import { cleanOutput, runCommand } from '../../helpers';
|
import { cleanOutput, runCommand } from '../../helpers';
|
||||||
|
|
||||||
const HELP_RESPONSE = `
|
const HELP_RESPONSE = `
|
||||||
Usage: device move <uuid>
|
Move a device to another application.
|
||||||
|
|
||||||
Use this command to move a device to another application you own.
|
USAGE
|
||||||
|
$ balena device move <uuid>
|
||||||
|
|
||||||
If you omit the application, you'll get asked for it interactively.
|
ARGUMENTS
|
||||||
|
<uuid> the uuid of the device to move
|
||||||
|
|
||||||
Examples:
|
OPTIONS
|
||||||
|
-a, --application <application> application name
|
||||||
|
-h, --help show CLI help
|
||||||
|
--app <app> same as '--application'
|
||||||
|
|
||||||
\t$ balena device move 7cf02a6
|
DESCRIPTION
|
||||||
\t$ balena device move 7cf02a6 --application MyNewApp
|
Move a device to another application.
|
||||||
|
|
||||||
Options:
|
Note, if the application option is omitted it will be prompted
|
||||||
|
for interactively.
|
||||||
|
|
||||||
--application, -a, --app <application> application name
|
EXAMPLES
|
||||||
|
$ balena device move 7cf02a6
|
||||||
|
$ balena device move 7cf02a6 --application MyNewApp
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena device move', function () {
|
describe('balena device move', function () {
|
||||||
@ -49,7 +57,7 @@ describe('balena device move', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should print help text with the -h flag', async () => {
|
it('should print help text with the -h flag', async () => {
|
||||||
api.expectGetWhoAmI({ optional: true });
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
|
|
||||||
const { out, err } = await runCommand('device move -h');
|
const { out, err } = await runCommand('device move -h');
|
||||||
@ -59,16 +67,15 @@ describe('balena device move', function () {
|
|||||||
expect(err).to.eql([]);
|
expect(err).to.eql([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should error if uuid not provided', async () => {
|
it('should error if uuid not provided', async () => {
|
||||||
// TODO: Figure out how to test for expected errors with current setup
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
// including exit codes if possible.
|
|
||||||
api.expectGetWhoAmI({ optional: true });
|
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
|
|
||||||
const { out, err } = await runCommand('device move');
|
const { out, err } = await runCommand('device move');
|
||||||
const errLines = cleanOutput(err);
|
const errLines = cleanOutput(err);
|
||||||
|
|
||||||
expect(errLines[0]).to.equal('Missing uuid');
|
expect(errLines[0]).to.equal('Missing 1 required argument:');
|
||||||
|
expect(errLines[1]).to.equal('uuid : the uuid of the device to move');
|
||||||
expect(out).to.eql([]);
|
expect(out).to.eql([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,13 +22,22 @@ import { apiResponsePath, BalenaAPIMock } from '../../balena-api-mock';
|
|||||||
import { cleanOutput, runCommand } from '../../helpers';
|
import { cleanOutput, runCommand } from '../../helpers';
|
||||||
|
|
||||||
const HELP_RESPONSE = `
|
const HELP_RESPONSE = `
|
||||||
Usage: device <uuid>
|
Show info about a single device.
|
||||||
|
|
||||||
Use this command to show information about a single device.
|
USAGE
|
||||||
|
$ balena device <uuid>
|
||||||
|
|
||||||
Examples:
|
ARGUMENTS
|
||||||
|
<uuid> the device uuid
|
||||||
|
|
||||||
\t$ balena device 7cf02a6
|
OPTIONS
|
||||||
|
-h, --help show CLI help
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Show information about a single device.
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
$ balena device 7cf02a6
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena device', function () {
|
describe('balena device', function () {
|
||||||
@ -44,7 +53,7 @@ describe('balena device', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should print help text with the -h flag', async () => {
|
it('should print help text with the -h flag', async () => {
|
||||||
api.expectGetWhoAmI({ optional: true });
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
|
|
||||||
const { out, err } = await runCommand('device -h');
|
const { out, err } = await runCommand('device -h');
|
||||||
@ -54,16 +63,15 @@ describe('balena device', function () {
|
|||||||
expect(err).to.eql([]);
|
expect(err).to.eql([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should error if uuid not provided', async () => {
|
it('should error if uuid not provided', async () => {
|
||||||
// TODO: Figure out how to test for expected errors with current setup
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
// including exit codes if possible.
|
|
||||||
api.expectGetWhoAmI({ optional: true });
|
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
|
|
||||||
const { out, err } = await runCommand('device');
|
const { out, err } = await runCommand('device');
|
||||||
const errLines = cleanOutput(err);
|
const errLines = cleanOutput(err);
|
||||||
|
|
||||||
expect(errLines[0]).to.equal('Missing uuid');
|
expect(errLines[0]).to.equal('Missing 1 required argument:');
|
||||||
|
expect(errLines[1]).to.equal('uuid : the device uuid');
|
||||||
expect(out).to.eql([]);
|
expect(out).to.eql([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,22 +22,26 @@ import { apiResponsePath, BalenaAPIMock } from '../../balena-api-mock';
|
|||||||
import { cleanOutput, runCommand } from '../../helpers';
|
import { cleanOutput, runCommand } from '../../helpers';
|
||||||
|
|
||||||
const HELP_RESPONSE = `
|
const HELP_RESPONSE = `
|
||||||
Usage: devices
|
List all devices.
|
||||||
|
|
||||||
Use this command to list all devices that belong to you.
|
USAGE
|
||||||
|
$ balena devices
|
||||||
|
|
||||||
You can filter the devices by application by using the \`--application\` option.
|
OPTIONS
|
||||||
|
-a, --application <application> application name
|
||||||
|
-h, --help show CLI help
|
||||||
|
--app <app> same as '--application'
|
||||||
|
|
||||||
Examples:
|
DESCRIPTION
|
||||||
|
list all devices that belong to you.
|
||||||
|
|
||||||
\t$ balena devices
|
You can filter the devices by application by using the \`--application\` option.
|
||||||
\t$ balena devices --application MyApp
|
|
||||||
\t$ balena devices --app MyApp
|
|
||||||
\t$ balena devices -a MyApp
|
|
||||||
|
|
||||||
Options:
|
EXAMPLES
|
||||||
|
$ balena devices
|
||||||
--application, -a, --app <application> application name
|
$ balena devices --application MyApp
|
||||||
|
$ balena devices --app MyApp
|
||||||
|
$ balena devices -a MyApp
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('balena devices', function () {
|
describe('balena devices', function () {
|
||||||
@ -53,7 +57,7 @@ describe('balena devices', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should print help text with the -h flag', async () => {
|
it('should print help text with the -h flag', async () => {
|
||||||
api.expectGetWhoAmI({ optional: true });
|
api.expectGetWhoAmI({ optional: true, persist: true });
|
||||||
api.expectGetMixpanel({ optional: true });
|
api.expectGetMixpanel({ optional: true });
|
||||||
|
|
||||||
const { out, err } = await runCommand('devices -h');
|
const { out, err } = await runCommand('devices -h');
|
||||||
|
@ -14,7 +14,7 @@ Primary commands:
|
|||||||
apps list all applications
|
apps list all applications
|
||||||
app <name> display information about a single application
|
app <name> display information about a single application
|
||||||
devices list all devices
|
devices list all devices
|
||||||
device <uuid> list a single device
|
device <uuid> show info about a single device
|
||||||
tunnel <deviceOrApplication> Tunnel local ports to your balenaOS device
|
tunnel <deviceOrApplication> Tunnel local ports to your balenaOS device
|
||||||
preload <image> preload an app on a disk image (or Edison zip archive)
|
preload <image> preload an app on a disk image (or Edison zip archive)
|
||||||
build [source] Build a single image or a multicontainer project locally
|
build [source] Build a single image or a multicontainer project locally
|
||||||
@ -37,14 +37,14 @@ Additional commands:
|
|||||||
config read read a device configuration
|
config read read a device configuration
|
||||||
config reconfigure reconfigure a provisioned device
|
config reconfigure reconfigure a provisioned device
|
||||||
config write <key> <value> write a device configuration
|
config write <key> <value> write a device configuration
|
||||||
device identify <uuid> identify a device with a UUID
|
device identify <uuid> identify a device
|
||||||
device init initialise a device with balenaOS
|
device init initialise a device with balenaOS
|
||||||
device move <uuid> move a device to another application
|
device move <uuid> move a device to another application
|
||||||
device os-update <uuid> Start a Host OS update for a device
|
device os-update <uuid> Start a Host OS update for a device
|
||||||
device public-url <uuid> get or manage the public URL for a device
|
device public-url <uuid> get or manage the public URL for a device
|
||||||
device reboot <uuid> restart a device
|
device reboot <uuid> restart a device
|
||||||
device register <application> register a device
|
device register <application> register a device
|
||||||
device rename <uuid> [newName] rename a balena device
|
device rename <uuid> [newname] rename a device
|
||||||
device rm <uuid> remove a device
|
device rm <uuid> remove a device
|
||||||
device shutdown <uuid> shutdown a device
|
device shutdown <uuid> shutdown a device
|
||||||
devices supported list the supported device types (like 'raspberrypi3' or 'intel-nuc')
|
devices supported list the supported device types (like 'raspberrypi3' or 'intel-nuc')
|
||||||
|
@ -117,8 +117,9 @@ describe('handleError() function', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const messagesToMatch = [
|
const messagesToMatch = [
|
||||||
'Missing argument',
|
'Missing uuid', // Capitano
|
||||||
'Missing arguments',
|
'Missing 1 required argument', // oclif
|
||||||
|
'Missing 2 required arguments', // oclif
|
||||||
'Unexpected argument',
|
'Unexpected argument',
|
||||||
'Unexpected arguments',
|
'Unexpected arguments',
|
||||||
'to be one of',
|
'to be one of',
|
||||||
|
Loading…
Reference in New Issue
Block a user