Introduce workaround that fixes windows dns issue on balena push using .local device names.

Improve error handling in deployToDevice so that versionErrors don't mask other errors.

Resolves:#1518
Change-type:patch
Signed-off-by:Scott Lowe <scott@balena.io>
This commit is contained in:
Scott Lowe 2019-11-27 11:34:24 +01:00
parent 622c510d65
commit 53325b7c05
2 changed files with 37 additions and 3 deletions

View File

@ -30,9 +30,11 @@ import { Readable } from 'stream';
import { BALENA_ENGINE_TMP_PATH } from '../../config';
import { checkBuildSecretsRequirements, makeBuildTasks } from '../compose_ts';
import { workaroundWindowsDnsIssue } from '../helpers';
import Logger = require('../logger');
import { DeviceAPI, DeviceInfo } from './api';
import * as LocalPushErrors from './errors';
import { DeviceAPIError } from './errors';
import LivepushManager from './live';
import { displayBuildLog } from './logs';
@ -74,7 +76,7 @@ async function environmentFromInput(
const varRegex = /^(?:([^\s:]+):)?([^\s]+?)=(.*)$/;
const ret: ParsedEnvironment = {};
// Propolulate the object with the servicenames, as it
// Populate the object with the servicenames, as it
// also means that we can do a fast lookup of whether a
// service exists
for (const service of serviceNames) {
@ -139,6 +141,8 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
);
}
await workaroundWindowsDnsIssue(opts.deviceHost);
const versionError = new Error(
'The supervisor version on this remote device does not support multicontainer local mode. ' +
'Please update your device to balenaOS v2.20.0 or greater from the dashboard.',
@ -156,10 +160,18 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
);
opts.nolive = true;
}
} catch {
exitWithExpectedError(versionError);
} catch (e) {
// Very old supervisor versions do not support /version endpoint
// a DeviceAPIError is expected in this case
if (e instanceof DeviceAPIError) {
exitWithExpectedError(versionError);
} else {
throw e;
}
}
await workaroundWindowsDnsIssue(opts.deviceHost);
globalLogger.logInfo(`Starting build on device ${opts.deviceHost}`);
const project = await loadProject(
@ -183,6 +195,8 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
// Try to detect the device information
const deviceInfo = await api.getDeviceInformation();
await workaroundWindowsDnsIssue(opts.deviceHost);
let buildLogs: Dictionary<string> | undefined;
if (!opts.nolive) {
buildLogs = {};
@ -218,6 +232,8 @@ export async function deployToDevice(opts: DeviceDeployOptions): Promise<void> {
await api.setTargetState(targetState);
await workaroundWindowsDnsIssue(opts.deviceHost);
// Now that we've set the target state, the device will do it's thing
// so we can either just display the logs, or start a livepush session
// (whilst also display logs)

View File

@ -338,3 +338,21 @@ function windowsCmdExeEscapeArg(arg: string): string {
// duplicate internal double quotes, and double quote overall
return `"${arg.replace(/["]/g, '""')}"`;
}
/*
* Workaround a window system bug which causes multiple rapid DNS lookups
* to fail for mDNS.
*
* It introduces a simple pause, and should be used between operations that
* trigger mDNS resolutions.
*
* Windows bug: https://support.microsoft.com/en-gb/help/4057932/getaddrinfo-failed-with-wsahost-not-found-11001-error
*/
export async function workaroundWindowsDnsIssue(ipOrHostname: string) {
// 300ms seemed to be the smallest delay that worked reliably but may
// vary between systems.
const delay = 500;
if (process.platform === 'win32' && ipOrHostname.includes('.local')) {
await new Promise(r => setTimeout(r, delay));
}
}