@@ -339,6 +339,35 @@ async function zfsSnapshotExists(snapshot: string): Promise<boolean> {
339339 return ( await runAllowFailure ( [ "zfs" , "list" , "-H" , "-t" , "snapshot" , snapshot ] ) ) . exitCode === 0 ;
340340}
341341
342+ export function rollbackSnapshotsForDatasetTree ( snapshot : string , availableSnapshots : string [ ] ) : string [ ] {
343+ const snapshotMarker = snapshot . indexOf ( "@" ) ;
344+ if ( snapshotMarker === - 1 ) {
345+ throw new Error ( `invalid ZFS snapshot name: ${ snapshot } ` ) ;
346+ }
347+
348+ const dataset = snapshot . slice ( 0 , snapshotMarker ) ;
349+ const snapshotSuffix = snapshot . slice ( snapshotMarker ) ;
350+ const descendants = availableSnapshots
351+ . map ( ( item ) => item . trim ( ) )
352+ . filter ( ( item ) => item . startsWith ( `${ dataset } /` ) && item . endsWith ( snapshotSuffix ) )
353+ . sort ( ( left , right ) => right . split ( "/" ) . length - left . split ( "/" ) . length || right . localeCompare ( left ) ) ;
354+
355+ return [ ...descendants , snapshot ] ;
356+ }
357+
358+ async function rollbackDatasetTreeToSnapshot ( snapshot : string ) : Promise < void > {
359+ const snapshotMarker = snapshot . indexOf ( "@" ) ;
360+ if ( snapshotMarker === - 1 ) {
361+ throw new Error ( `invalid ZFS snapshot name: ${ snapshot } ` ) ;
362+ }
363+
364+ const dataset = snapshot . slice ( 0 , snapshotMarker ) ;
365+ const snapshots = await runText ( [ "zfs" , "list" , "-H" , "-t" , "snapshot" , "-o" , "name" , "-r" , dataset ] , PREFIX ) ;
366+ for ( const item of rollbackSnapshotsForDatasetTree ( snapshot , snapshots . split ( "\n" ) ) ) {
367+ await runText ( [ "zfs" , "rollback" , "-r" , item ] , PREFIX ) ;
368+ }
369+ }
370+
342371function restoreTempDatasetName ( targetDataset : string , label : string ) : string {
343372 const suffix = `${ label } -${ process . pid } -${ Date . now ( ) } ` . replace ( / [ ^ A - Z a - z 0 - 9 _ . : - ] / g, "-" ) ;
344373 return `${ targetDataset } -${ suffix } ` ;
@@ -452,7 +481,7 @@ async function restoreLocal(
452481 if ( mode === "in-place" ) {
453482 await confirmDestructive ( `Rollback ${ instance } in place to ${ snapshot } ?` ) ;
454483 await stopInstanceForRestore ( instance ) ;
455- await runText ( [ "zfs" , "rollback" , "-r" , snapshot ] , PREFIX ) ;
484+ await rollbackDatasetTreeToSnapshot ( snapshot ) ;
456485 console . log ( success ( `Rolled back ${ instance } to ${ snapshot } ` ) ) ;
457486 console . log ( `${ label ( "Next:" ) } ${ value ( `lxc start ${ instance } ` ) } ` ) ;
458487 return ;
0 commit comments