Add device start-service and stop-service commands

Change-type: minor
This commit is contained in:
Morgan Larsson 2023-11-04 15:38:30 +01:00 committed by Otávio Jacobi
parent d2150c5cb7
commit 221c213791
6 changed files with 332 additions and 2 deletions

View File

@ -99,6 +99,8 @@ const capitanoDoc = {
'build/commands/device/rm.js',
'build/commands/device/shutdown.js',
'build/commands/device/track-fleet.js',
'build/commands/device/start-service.js',
'build/commands/device/stop-service.js',
],
},
{

View File

@ -14,7 +14,7 @@ _balena() {
app_cmds=( create )
block_cmds=( create )
config_cmds=( generate inject read reconfigure write )
device_cmds=( deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown track-fleet )
device_cmds=( deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown start-service stop-service track-fleet )
devices_cmds=( supported )
env_cmds=( add rename rm )
fleet_cmds=( create pin purge rename restart rm track-latest )

View File

@ -13,7 +13,7 @@ _balena_complete()
app_cmds="create"
block_cmds="create"
config_cmds="generate inject read reconfigure write"
device_cmds="deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown track-fleet"
device_cmds="deactivate identify init local-mode move os-update pin public-url purge reboot register rename restart rm shutdown start-service stop-service track-fleet"
devices_cmds="supported"
env_cmds="add rename rm"
fleet_cmds="create pin purge rename restart rm track-latest"

View File

@ -215,6 +215,8 @@ are encouraged to regularly update the balena CLI to the latest version.
- [device rm <uuid(s)>](#device-rm-uuid-s)
- [device shutdown <uuid>](#device-shutdown-uuid)
- [device track-fleet <uuid>](#device-track-fleet-uuid)
- [device start-service <uuid>](#device-start-service-uuid)
- [device stop-service <uuid>](#device-stop-service-uuid)
- Devices
@ -1709,6 +1711,54 @@ the uuid of the device to make track the fleet's release
### Options
## device start-service <uuid>
Start containers on a device.
Multiple devices and services may be specified with a comma-separated list
of values (no spaces).
Examples:
$ balena device start-service 23c73a1 myService
$ balena device start-service 23c73a1 myService1,myService2
### Arguments
#### UUID
comma-separated list (no blank spaces) of device UUIDs
#### SERVICE
comma-separated list (no blank spaces) of service names
### Options
## device stop-service <uuid>
Stop containers on a device.
Multiple devices and services may be specified with a comma-separated list
of values (no spaces).
Examples:
$ balena device stop-service 23c73a1 myService
$ balena device stop-service 23c73a1 myService1,myService2
### Arguments
#### UUID
comma-separated list (no blank spaces) of device UUIDs
#### SERVICE
comma-separated list (no blank spaces) of service names
### Options
# Devices
## devices

View File

@ -0,0 +1,139 @@
/**
* @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 { Args } from '@oclif/core';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
import type { BalenaSDK } from 'balena-sdk';
export default class DeviceStartServiceCmd extends Command {
public static description = stripIndent`
Start containers on a device.
Start containers on a device.
Multiple devices and services may be specified with a comma-separated list
of values (no spaces).
`;
public static examples = [
'$ balena device start-service 23c73a1 myService',
'$ balena device start-service 23c73a1 myService1,myService2',
];
public static args = {
uuid: Args.string({
description: 'comma-separated list (no blank spaces) of device UUIDs',
required: true,
}),
service: Args.string({
description: 'comma-separated list (no blank spaces) of service names',
required: true,
}),
};
public static usage = 'device start-service <uuid>';
public static flags = {
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params } = await this.parse(DeviceStartServiceCmd);
const balena = getBalenaSdk();
const ux = getCliUx();
const deviceUuids = params.uuid.split(',');
const serviceNames = params.service.split(',');
// Iterate sequentially through deviceUuids.
// We may later want to add a batching feature,
// so that n devices are processed in parallel
for (const uuid of deviceUuids) {
ux.action.start(`Starting services on device ${uuid}`);
await this.startServices(balena, uuid, serviceNames);
ux.action.stop();
}
}
async startServices(
balena: BalenaSDK,
deviceUuid: string,
serviceNames: string[],
) {
const { ExpectedError } = await import('../../errors');
const { getExpandedProp } = await import('../../utils/pine');
// Get device
const device = await balena.models.device.getWithServiceDetails(
deviceUuid,
{
$expand: {
is_running__release: { $select: 'commit' },
},
},
);
const activeReleaseCommit = getExpandedProp(
device.is_running__release,
'commit',
);
// Check specified services exist on this device before startinganything
serviceNames.forEach((service) => {
if (!device.current_services[service]) {
throw new ExpectedError(
`Service ${service} not found on device ${deviceUuid}.`,
);
}
});
// Start services
const startPromises: Array<Promise<void>> = [];
for (const serviceName of serviceNames) {
const service = device.current_services[serviceName];
// Each service is an array of `CurrentServiceWithCommit`
// because when service is updating, it will actually hold 2 services
// Target commit matching `device.is_running__release`
const serviceContainer = service.find((s) => {
return s.commit === activeReleaseCommit;
});
if (serviceContainer) {
startPromises.push(
balena.models.device.startService(
deviceUuid,
serviceContainer.image_id,
),
);
}
}
try {
await Promise.all(startPromises);
} catch (e) {
if (e.message.toLowerCase().includes('no online device')) {
throw new ExpectedError(`Device ${deviceUuid} is not online.`);
} else {
throw e;
}
}
}
}

View File

@ -0,0 +1,139 @@
/**
* @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 { Args } from '@oclif/core';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, getCliUx, stripIndent } from '../../utils/lazy';
import type { BalenaSDK } from 'balena-sdk';
export default class DeviceStopServiceCmd extends Command {
public static description = stripIndent`
Stop containers on a device.
Stop containers on a device.
Multiple devices and services may be specified with a comma-separated list
of values (no spaces).
`;
public static examples = [
'$ balena device stop-service 23c73a1 myService',
'$ balena device stop-service 23c73a1 myService1,myService2',
];
public static args = {
uuid: Args.string({
description: 'comma-separated list (no blank spaces) of device UUIDs',
required: true,
}),
service: Args.string({
description: 'comma-separated list (no blank spaces) of service names',
required: true,
}),
};
public static usage = 'device stop-service <uuid>';
public static flags = {
help: cf.help,
};
public static authenticated = true;
public async run() {
const { args: params } = await this.parse(DeviceStopServiceCmd);
const balena = getBalenaSdk();
const ux = getCliUx();
const deviceUuids = params.uuid.split(',');
const serviceNames = params.service.split(',');
// Iterate sequentially through deviceUuids.
// We may later want to add a batching feature,
// so that n devices are processed in parallel
for (const uuid of deviceUuids) {
ux.action.start(`Stopping services on device ${uuid}`);
await this.stopServices(balena, uuid, serviceNames);
ux.action.stop();
}
}
async stopServices(
balena: BalenaSDK,
deviceUuid: string,
serviceNames: string[],
) {
const { ExpectedError } = await import('../../errors');
const { getExpandedProp } = await import('../../utils/pine');
// Get device
const device = await balena.models.device.getWithServiceDetails(
deviceUuid,
{
$expand: {
is_running__release: { $select: 'commit' },
},
},
);
const activeReleaseCommit = getExpandedProp(
device.is_running__release,
'commit',
);
// Check specified services exist on this device before stoppinganything
serviceNames.forEach((service) => {
if (!device.current_services[service]) {
throw new ExpectedError(
`Service ${service} not found on device ${deviceUuid}.`,
);
}
});
// Stop services
const stopPromises: Array<Promise<void>> = [];
for (const serviceName of serviceNames) {
const service = device.current_services[serviceName];
// Each service is an array of `CurrentServiceWithCommit`
// because when service is updating, it will actually hold 2 services
// Target commit matching `device.is_running__release`
const serviceContainer = service.find((s) => {
return s.commit === activeReleaseCommit;
});
if (serviceContainer) {
stopPromises.push(
balena.models.device.stopService(
deviceUuid,
serviceContainer.image_id,
),
);
}
}
try {
await Promise.all(stopPromises);
} catch (e) {
if (e.message.toLowerCase().includes('no online device')) {
throw new ExpectedError(`Device ${deviceUuid} is not online.`);
} else {
throw e;
}
}
}
}