Skip to content

Commit

Permalink
Add ability to write network configuration for migration
Browse files Browse the repository at this point in the history
Change-type: patch
Signed-off-by: Ken Bannister <kb2ma@runbox.com>
  • Loading branch information
kb2ma committed Jul 17, 2023
1 parent 087b777 commit 181afa9
Showing 1 changed file with 51 additions and 12 deletions.
63 changes: 51 additions & 12 deletions lib/migrator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
calcRequiredPartitionSize,
getTargetBlockDevice,
findNewPartitions,
findFilesystemLabel
findFilesystemLabel,
ConnectionProfile,
writeNetworkConfig
} from './helpers';
import { copyBootloaderFromImage } from './copy-bootloader';
import winCommands from './windows-commands';
Expand Down Expand Up @@ -62,7 +64,9 @@ interface TargetPartition {
/** Options for migrate(): */
export interface MigrateOptions {
// don't perform these tasks; comma separated list like 'bootloader,reboot'
omitTasks: string
omitTasks: string;
// Network connection profiles to write to boot partition
connectionProfiles: ConnectionProfile[]
}

/**
Expand All @@ -79,13 +83,15 @@ export interface MigrateOptions {
*
* * shrink -- shrink existing Windows partition as needed to accommodate the new partitions
* * copy -- create/copy partitions from image
* * config -- write host configuration like networking to boot partition
* * bootloader -- copy/setup bootloader for new boot partition
* * reboot -- actually execute the reboot
*
* @param {string} imagePath - balenaOS flasher image to use as source
* @param {string} windowsPartition - partition label of the device where we want to add the new data; defauls to "C"
* @param {string} deviceName - storage device name, default: '\\.\PhysicalDrive0'
* @param {string} efiLabel - label to use when mounting the EFI partition, in case the default "M" is already in use
* @param {string} efiLabel - label to use when mounting the EFI partition, in case the default "M" is already in use;
* letter following efiLabel is used when mounting boot partition to write host config
* @param {MigrateOptions} options - various options to qualify how migrate runs
* @returns
*/
Expand All @@ -94,7 +100,7 @@ export const migrate = async (
windowsPartition: string = 'C',
deviceName: string = '\\\\.\\PhysicalDrive0',
efiLabel: string = 'M',
options: MigrateOptions = { omitTasks: '' }
options: MigrateOptions = { omitTasks: '', connectionProfiles: [] }
) => {
console.log(`Migrate ${deviceName} with image ${imagePath}`);
try {
Expand All @@ -105,7 +111,7 @@ export const migrate = async (
const BOOT_FILES_SOURCE_PATH = '/EFI/BOOT';
const BOOT_FILES_TARGET_PATH = '/EFI/Boot';
const REBOOT_DELAY_SEC = 10
const ALL_TASKS = [ 'shrink', 'copy', 'bootloader', 'reboot'];
const ALL_TASKS = [ 'shrink', 'copy', 'config', 'bootloader', 'reboot'];

// initial validations
if (process.platform !== 'win32') {
Expand All @@ -117,6 +123,9 @@ export const migrate = async (
if (!existsSync(imagePath)) {
throw Error(`Image ${imagePath} not found`);
}
if (efiLabel == 'Z') {
throw Error("Can't use last letter of alphabet for EFI label");
}

const tasks = ALL_TASKS.filter(task => !options.omitTasks.includes(task));

Expand Down Expand Up @@ -239,17 +248,47 @@ export const migrate = async (
// Must ensure volume offline before overwrite.
await diskpart.setPartitionOnlineStatus(bootPartition.volumeId, false)
}
// Sets volume online only if a new partition.
await copyPartitionFromImageToDevice(sourceFile, 1, targetDevice.etcher, bootPartition.etcher!.offset);
console.log("Copy complete")
console.log("Copy flasherRootAPartition from image to disk");
// We never set rootA partition online, so no need to offline.
await copyPartitionFromImageToDevice(sourceFile, 2, targetDevice.etcher, rootAPartition.etcher!.offset);
console.log("Copy complete")
try {
// Sets volume online only if a new partition.
await copyPartitionFromImageToDevice(sourceFile, 1, targetDevice.etcher, bootPartition.etcher!.offset);
console.log("Copy complete")
console.log("Copy flasherRootAPartition from image to disk");
// We never set rootA partition online, so no need to offline.
await copyPartitionFromImageToDevice(sourceFile, 2, targetDevice.etcher, rootAPartition.etcher!.offset);
console.log("Copy complete")
} finally {
if (tasks.includes('config') && bootPartition.volumeId) {
// Ensure online if set offline above, to find volume ID from partition label.
await diskpart.setPartitionOnlineStatus(bootPartition.volumeId, true)
}
}
} else {
console.log(`\nSkip task: create and copy partitions`)
}

if (tasks.includes('config')) {
console.log("\nWrite network configuration");
// Verify device is online in all cases; must be so to write file.
bootPartition.volumeId = await diskpart.findVolume(targetDevice.name, BOOT_PARTITION_LABEL)
if (!bootPartition.volumeId) {
throw Error(`Can't find Windows volume for boot partition`)
}
// use character following EFI label
const driveLetter = String.fromCharCode(efiLabel.charCodeAt(0) + 1)
await diskpart.setDriveLetter(bootPartition.volumeId, driveLetter)
try {
for (let profile of options.connectionProfiles) {
const pathname = `${driveLetter}:\\system-connections\\${profile.name}`
await writeNetworkConfig(pathname, profile)
console.log(`Wrote network configuration for ${profile.name}`)
}
} finally {
await diskpart.clearDriveLetter(bootPartition.volumeId, driveLetter)
}
} else {
console.log(`\nSkip task: write configuration`)
}

if (tasks.includes('bootloader')) {
// mount the boot partition and copy bootloader
console.log("\nMount Windows boot partition and copy grub bootloader from image");
Expand Down

0 comments on commit 181afa9

Please sign in to comment.