Recategorize some errors as expected.

Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
This commit is contained in:
Scott Lowe 2020-06-26 13:46:58 +02:00
parent 17089a35c3
commit 1308b64c67
9 changed files with 37 additions and 33 deletions

View File

@ -117,7 +117,7 @@ export default class EnvAddCmd extends Command {
params.value = process.env[params.name];
if (params.value == null) {
throw new Error(
throw new ExpectedError(
`Value not found for environment variable: ${params.name}`,
);
} else if (!options.quiet) {

View File

@ -51,7 +51,7 @@ const deployProject = function (docker, logger, composeOpts, opts) {
project.descriptors.length > 1 &&
!opts.app.application_type?.[0]?.supports_multicontainer
) {
throw new Error(
throw new ExpectedError(
'Target application does not support multiple containers. Aborting!',
);
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2017 Balena
Copyright 2017-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.
@ -16,7 +16,9 @@ limitations under the License.
import type { CommandDefinition } from 'capitano';
import type * as SDK from 'etcher-sdk';
import { getChalk, getVisuals, stripIndent } from '../../utils/lazy';
import { ExpectedError } from '../../errors';
async function getDrive(options: {
drive?: string;
@ -31,7 +33,7 @@ async function getDrive(options: {
try {
const d = scanner.getBy('device', drive);
if (d === undefined || !(d instanceof sdk.sourceDestination.BlockDevice)) {
throw new Error(`Drive not found: ${options.drive}`);
throw new ExpectedError(`Drive not found: ${options.drive}`);
}
return d;
} finally {

View File

@ -21,6 +21,7 @@ import { createServer, Server, Socket } from 'net';
import { getBalenaSdk, stripIndent } from '../utils/lazy';
import { getOnlineTargetUuid } from '../utils/patterns';
import { tunnelConnectionToDevice } from '../utils/tunnel';
import { ExpectedError } from '../errors';
interface Args {
deviceOrApplication: string;
@ -223,7 +224,7 @@ export const tunnel: CommandDefinition<Args, Options> = {
const results = await Promise.all(localListeners);
if (!results.includes(true)) {
throw new Error('No ports are valid for tunnelling');
throw new ExpectedError('No ports are valid for tunnelling');
}
logger.logInfo('Waiting for connections...');

View File

@ -21,6 +21,7 @@ import type { Socket } from 'net';
import * as path from 'path';
import * as utils from './utils';
import { ExpectedError } from '../errors';
const serverSockets: Socket[] = [];
@ -87,11 +88,11 @@ export const awaitForToken = (options: {
try {
const token = request.body.token?.trim();
if (!token) {
throw new Error('No token');
throw new ExpectedError('No token');
}
const loggedIn = await utils.loginIfTokenValid(token);
if (!loggedIn) {
throw new Error('Invalid token');
throw new ExpectedError('Invalid token');
}
response.status(200).render('success');
resolve(token);

View File

@ -355,7 +355,7 @@ async function parseRegistrySecrets(
if (/.+\.ya?ml$/i.test(secretsFilename)) {
isYaml = true;
} else if (!/.+\.json$/i.test(secretsFilename)) {
throw new Error('Filename must end with .json, .yml or .yaml');
throw new ExpectedError('Filename must end with .json, .yml or .yaml');
}
const raw = (await fs.readFile(secretsFilename)).toString();
const registrySecrets = new MultiBuild.RegistrySecretValidator().validateRegistrySecrets(
@ -459,7 +459,7 @@ async function performResolution(
(clonedStream: tar.Pack) => {
buildTask.buildStream = clonedStream;
if (!buildTask.external && !buildTask.resolved) {
throw new Error(
throw new ExpectedError(
`Project type for service "${buildTask.serviceName}" could not be determined. Missing a Dockerfile?`,
);
}

View File

@ -19,6 +19,7 @@
import * as Bluebird from 'bluebird';
import * as _ from 'lodash';
import { ExpectedError } from '../errors';
// Use this function to seed an action's list of capitano options
// with the docker options. Using this interface means that
@ -122,7 +123,7 @@ const generateConnectOpts = function (opts) {
connectOpts.port = opts.dockerPort || 2376;
} else if (opts.docker != null && opts.dockerHost != null) {
// Both provided, no obvious way to continue
throw new Error(
throw new ExpectedError(
"Both a local docker socket and docker host have been provided. Don't know how to continue.",
);
} else {
@ -142,7 +143,7 @@ const generateConnectOpts = function (opts) {
if (opts.ca != null || opts.cert != null || opts.key != null) {
// but not all
if (!(opts.ca != null && opts.cert != null && opts.key != null)) {
throw new Error(
throw new ExpectedError(
'You must provide a CA, certificate and key in order to use TLS',
);
}
@ -172,7 +173,7 @@ const parseBuildArgs = function (args) {
if (pair != null) {
buildArgs[pair[1]] = pair[2] ?? '';
} else {
throw new Error(`Could not parse build argument: '${arg}'`);
throw new ExpectedError(`Could not parse build argument: '${arg}'`);
}
});
return buildArgs;

View File

@ -1,5 +1,5 @@
/*
Copyright 2016-2020 Balena
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.
@ -19,10 +19,14 @@ import Bluebird = require('bluebird');
import _ = require('lodash');
import _form = require('resin-cli-form');
import { exitWithExpectedError, instanceOf, NotLoggedInError } from '../errors';
import {
exitWithExpectedError,
instanceOf,
NotLoggedInError,
ExpectedError,
} from '../errors';
import { getBalenaSdk, getVisuals, stripIndent } from './lazy';
import validation = require('./validation');
import { isV12 } from './version';
const getForm = _.once((): typeof _form => require('resin-cli-form'));
@ -65,7 +69,7 @@ export function authenticate(options: {}): Bluebird<void> {
error.name === 'BalenaRequestError' &&
error.statusCode === 401
) {
throw new Error('Invalid two factor authentication code');
throw new ExpectedError('Invalid two factor authentication code');
}
throw error;
});
@ -80,16 +84,9 @@ export function authenticate(options: {}): Bluebird<void> {
export async function checkLoggedIn(): Promise<void> {
const balena = getBalenaSdk();
if (!(await balena.auth.isLoggedIn())) {
if (isV12()) {
throw new NotLoggedInError(stripIndent`
Login required: use the balena login command to log in.
`);
} else {
throw new NotLoggedInError(stripIndent`
You have to log in to continue
Run the following command to go through the login wizard:
$ balena login`);
}
throw new NotLoggedInError(stripIndent`
Login required: use the balena login command to log in.
`);
}
}
@ -175,7 +172,7 @@ export function selectApplication(
.hasAny()
.then(function (hasAnyApplications) {
if (!hasAnyApplications) {
throw new Error("You don't have any applications");
throw new ExpectedError("You don't have any applications");
}
return balena.models.application.getAll();
@ -316,7 +313,7 @@ export function inferOrSelectDevice(preferredUuid: string) {
.filter<BalenaSdk.Device>((device) => device.is_online)
.then((onlineDevices) => {
if (_.isEmpty(onlineDevices)) {
throw new Error("You don't have any devices online");
throw new ExpectedError("You don't have any devices online");
}
const defaultUuid = _(onlineDevices).map('uuid').includes(preferredUuid)
@ -348,7 +345,9 @@ export async function getOnlineTargetUuid(
const uuidTest = validation.validateUuid(applicationOrDevice);
if (!appTest && !uuidTest) {
throw new Error(`Device or application not found: ${applicationOrDevice}`);
throw new ExpectedError(
`Device or application not found: ${applicationOrDevice}`,
);
}
// if we have a definite device UUID...
@ -375,7 +374,7 @@ export async function getOnlineTargetUuid(
});
if (_.isEmpty(devices)) {
throw new Error('No accessible devices are online');
throw new ExpectedError('No accessible devices are online');
}
return await getForm().ask({

View File

@ -180,7 +180,7 @@ async function getOrSelectLocalDevice(deviceIp?: string): Promise<string> {
});
if (!ip) {
throw new Error('No device selected');
throw new ExpectedError('No device selected');
}
return ip;
@ -211,7 +211,7 @@ async function getOrSelectApplication(
const allDeviceTypes = await sdk.models.config.getDeviceTypes();
const deviceTypeManifest = _.find(allDeviceTypes, { slug: deviceType });
if (!deviceTypeManifest) {
throw new Error(`"${deviceType}" is not a valid device type`);
throw new ExpectedError(`"${deviceType}" is not a valid device type`);
}
const compatibleDeviceTypes = _(allDeviceTypes)
.filter(
@ -274,7 +274,7 @@ async function getOrSelectApplication(
);
if (validApplications.length === 0) {
throw new Error('No application found with a matching device type');
throw new ExpectedError('No application found with a matching device type');
}
if (validApplications.length === 1) {