Merge pull request #2702 from balena-io/trim

Trim
This commit is contained in:
Alexis Svinartchouk 2019-06-14 15:41:29 +02:00 committed by GitHub
commit bab9069dee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 86 deletions

View File

@ -37,6 +37,7 @@ const DEFAULT_SETTINGS = {
errorReporting: true, errorReporting: true,
unmountOnSuccess: true, unmountOnSuccess: true,
validateWriteOnSuccess: true, validateWriteOnSuccess: true,
trim: false,
updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType), updatesEnabled: packageJSON.updates.enabled && !_.includes([ 'rpm', 'deb' ], packageJSON.packageType),
lastSleptUpdateNotifier: null, lastSleptUpdateNotifier: null,
lastSleptUpdateNotifierVersion: null, lastSleptUpdateNotifierVersion: null,

View File

@ -172,7 +172,8 @@ exports.performWrite = (image, drives, onProgress) => {
uuid: flashState.getFlashUuid(), uuid: flashState.getFlashUuid(),
flashInstanceUuid: flashState.getFlashUuid(), flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'), unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess') validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
trim: settings.get('trim')
} }
ipc.server.on('fail', ({ device, error }) => { ipc.server.on('fail', ({ device, error }) => {
@ -200,6 +201,7 @@ exports.performWrite = (image, drives, onProgress) => {
imagePath: image, imagePath: image,
destinations: drives, destinations: drives,
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'), validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
trim: settings.get('trim'),
unmountOnSuccess: settings.get('unmountOnSuccess') unmountOnSuccess: settings.get('unmountOnSuccess')
}) })
}) })
@ -312,6 +314,7 @@ exports.flash = (image, drives) => {
flashInstanceUuid: flashState.getFlashUuid(), flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'), unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'), validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
trim: settings.get('trim'),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid, applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid
} }
@ -375,6 +378,7 @@ exports.cancel = () => {
flashInstanceUuid: flashState.getFlashUuid(), flashInstanceUuid: flashState.getFlashUuid(),
unmountOnSuccess: settings.get('unmountOnSuccess'), unmountOnSuccess: settings.get('unmountOnSuccess'),
validateWriteOnSuccess: settings.get('validateWriteOnSuccess'), validateWriteOnSuccess: settings.get('validateWriteOnSuccess'),
trim: settings.get('trim'),
applicationSessionUuid: store.getState().toJS().applicationSessionUuid, applicationSessionUuid: store.getState().toJS().applicationSessionUuid,
flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid, flashingWorkflowUuid: store.getState().toJS().flashingWorkflowUuid,
status: 'cancel' status: 'cancel'

View File

@ -43,6 +43,17 @@
</label> </label>
</div> </div>
<div class="checkbox">
<label>
<input type="checkbox"
tabindex="8"
ng-model="settings.currentData.trim"
ng-change="settings.toggle('trim')">
<span>Trim ext{2,3,4} partitions before writing (raw images only)</span>
</label>
</div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" <input type="checkbox"

View File

@ -82,12 +82,10 @@ const terminate = (code) => {
* @example * @example
* handleError(new Error('Something bad happened!')) * handleError(new Error('Something bad happened!'))
*/ */
const handleError = (error) => { const handleError = async (error) => {
ipc.of[IPC_SERVER_ID].emit('error', errors.toJSON(error)) ipc.of[IPC_SERVER_ID].emit('error', errors.toJSON(error))
Bluebird.delay(DISCONNECT_DELAY) await Bluebird.delay(DISCONNECT_DELAY)
.then(() => { terminate(EXIT_CODES.GENERAL_ERROR)
terminate(EXIT_CODES.GENERAL_ERROR)
})
} }
/** /**
@ -95,42 +93,45 @@ const handleError = (error) => {
* @param {SourceDestination} source - source * @param {SourceDestination} source - source
* @param {SourceDestination[]} destinations - destinations * @param {SourceDestination[]} destinations - destinations
* @param {Boolean} verify - whether to validate the writes or not * @param {Boolean} verify - whether to validate the writes or not
* @param {Boolean} trim - whether to trim ext partitions before writing
* @param {Function} onProgress - function to call on progress * @param {Function} onProgress - function to call on progress
* @param {Function} onFail - function to call on fail * @param {Function} onFail - function to call on fail
* @param {Function} onFinish - function to call on finish * @returns {Promise<{ bytesWritten, devices, errors} >}
* @param {Function} onError - function to call on error
* @returns {Promise<void>}
* *
* @example * @example
* writeAndValidate(source, destinations, verify, onProgress, onFail, onFinish, onError) * writeAndValidate(source, destinations, verify, onProgress, onFail, onFinish, onError)
*/ */
const writeAndValidate = (source, destinations, verify, onProgress, onFail, onFinish, onError) => { const writeAndValidate = async (source, destinations, verify, trim, onProgress, onFail) => {
return source.getInnerSource() let innerSource = await source.getInnerSource()
.then((innerSource) => { if (trim && (await innerSource.canRead())) {
return sdk.multiWrite.pipeSourceToDestinations( innerSource = new sdk.sourceDestination.ConfiguredSource(
innerSource, innerSource,
destinations, trim,
onFail,
onProgress, // Create stream from file-disk (not source stream)
verify true
) )
}) }
.then(({ failures, bytesWritten }) => { const { failures, bytesWritten } = await sdk.multiWrite.pipeSourceToDestinations(
const result = { innerSource,
bytesWritten, destinations,
devices: { onFail,
failed: failures.size, onProgress,
successful: destinations.length - failures.size verify
}, )
errors: [] const result = {
} bytesWritten,
for (const [ destination, error ] of failures) { devices: {
error.device = destination.drive.device failed: failures.size,
result.errors.push(error) successful: destinations.length - failures.size
} },
onFinish(result) errors: []
}) }
.catch(onError) for (const [ destination, error ] of failures) {
error.device = destination.drive.device
result.errors.push(error)
}
return result
} }
ipc.connectTo(IPC_SERVER_ID, () => { ipc.connectTo(IPC_SERVER_ID, () => {
@ -159,7 +160,7 @@ ipc.connectTo(IPC_SERVER_ID, () => {
terminate(EXIT_CODES.SUCCESS) terminate(EXIT_CODES.SUCCESS)
}) })
ipc.of[IPC_SERVER_ID].on('write', (options) => { ipc.of[IPC_SERVER_ID].on('write', async (options) => {
/** /**
* @summary Progress handler * @summary Progress handler
* @param {Object} state - progress state * @param {Object} state - progress state
@ -172,52 +173,20 @@ ipc.connectTo(IPC_SERVER_ID, () => {
let exitCode = EXIT_CODES.SUCCESS let exitCode = EXIT_CODES.SUCCESS
/**
* @summary Finish handler
* @param {Object} results - Flash results
* @example
* writer.on('finish', onFinish)
*/
const onFinish = (results) => {
log(`Finish: ${results.bytesWritten}`)
results.errors = _.map(results.errors, (error) => {
return errors.toJSON(error)
})
ipc.of[IPC_SERVER_ID].emit('done', { results })
Bluebird.delay(DISCONNECT_DELAY)
.then(() => {
terminate(exitCode)
})
}
/** /**
* @summary Abort handler * @summary Abort handler
* @example * @example
* writer.on('abort', onAbort) * writer.on('abort', onAbort)
*/ */
const onAbort = () => { const onAbort = async () => {
log('Abort') log('Abort')
ipc.of[IPC_SERVER_ID].emit('abort') ipc.of[IPC_SERVER_ID].emit('abort')
Bluebird.delay(DISCONNECT_DELAY) await Bluebird.delay(DISCONNECT_DELAY)
.then(() => { terminate(exitCode)
terminate(exitCode)
})
} }
ipc.of[IPC_SERVER_ID].on('cancel', onAbort) ipc.of[IPC_SERVER_ID].on('cancel', onAbort)
/**
* @summary Error handler
* @param {Error} error - error
* @example
* writer.on('error', onError)
*/
const onError = (error) => {
log(`Error: ${error.message}`)
exitCode = EXIT_CODES.GENERAL_ERROR
ipc.of[IPC_SERVER_ID].emit('error', errors.toJSON(error))
}
/** /**
* @summary Failure handler (non-fatal errors) * @summary Failure handler (non-fatal errors)
* @param {SourceDestination} destination - destination * @param {SourceDestination} destination - destination
@ -234,24 +203,36 @@ ipc.connectTo(IPC_SERVER_ID, () => {
} }
const destinations = _.map(options.destinations, 'device') const destinations = _.map(options.destinations, 'device')
const dests = _.map(options.destinations, (destination) => {
return new sdk.sourceDestination.BlockDevice(destination, options.unmountOnSuccess)
})
const source = new sdk.sourceDestination.File(options.imagePath, sdk.sourceDestination.File.OpenFlags.Read)
writeAndValidate(
source,
dests,
options.validateWriteOnSuccess,
onProgress,
onFail,
onFinish,
onError
)
log(`Image: ${options.imagePath}`) log(`Image: ${options.imagePath}`)
log(`Devices: ${destinations.join(', ')}`) log(`Devices: ${destinations.join(', ')}`)
log(`Umount on success: ${options.unmountOnSuccess}`) log(`Umount on success: ${options.unmountOnSuccess}`)
log(`Validate on success: ${options.validateWriteOnSuccess}`) log(`Validate on success: ${options.validateWriteOnSuccess}`)
log(`Trim: ${options.trim}`)
const dests = _.map(options.destinations, (destination) => {
return new sdk.sourceDestination.BlockDevice(destination, options.unmountOnSuccess)
})
const source = new sdk.sourceDestination.File(options.imagePath, sdk.sourceDestination.File.OpenFlags.Read)
try {
const results = await writeAndValidate(
source,
dests,
options.validateWriteOnSuccess,
options.trim,
onProgress,
onFail
)
log(`Finish: ${results.bytesWritten}`)
results.errors = _.map(results.errors, (error) => {
return errors.toJSON(error)
})
ipc.of[IPC_SERVER_ID].emit('done', { results })
await Bluebird.delay(DISCONNECT_DELAY)
terminate(exitCode)
} catch (error) {
log(`Error: ${error.message}`)
exitCode = EXIT_CODES.GENERAL_ERROR
ipc.of[IPC_SERVER_ID].emit('error', errors.toJSON(error))
}
}) })
ipc.of[IPC_SERVER_ID].on('connect', () => { ipc.of[IPC_SERVER_ID].on('connect', () => {