wip2
This commit is contained in:
@@ -4,7 +4,7 @@ import { strictEqual } from 'node:assert'
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
import parseVmx from './parsers/vmx.mjs'
|
||||
import { basename, dirname } from 'node:path'
|
||||
import { dirname } from 'node:path'
|
||||
import parseVmdk, { VhdCowd } from './parsers/vmdk.mjs'
|
||||
import parseVmsd from './parsers/vmsd.mjs';
|
||||
import VhdEsxiRaw from './VhdEsxiRaw.mjs';
|
||||
@@ -173,29 +173,36 @@ export default class Esxi extends EventEmitter {
|
||||
descriptionLabel: ' from esxi',
|
||||
vhd: async () => {
|
||||
console.log('vhd from snapshot')
|
||||
|
||||
if(fileName.endsWith('-flat.vmdk')){
|
||||
return
|
||||
console.log('snapshot flat.vmdk vhd ')
|
||||
const vhd = await VhdEsxiRaw.open(this,diskDataStore, dirname(diskPath) + '/' + fileName)
|
||||
console.log('snapshot flat.vmdk vhd openned')
|
||||
await vhd.readBlockAllocationTable()
|
||||
console.log('snapshot flat.vmdk bat openned')
|
||||
return vhd.stream()
|
||||
}
|
||||
console.log('vhd from snapshot filename ok')
|
||||
console.log('snapshot current.vmdk filenameok')
|
||||
// last snasphot only works when vm is powered off
|
||||
const vhd = await VhdCowd.open(this, diskDataStore, dirname(diskPath) + '/' + fileName, parentFileName)
|
||||
console.log('realy vhd from snapshot openned')
|
||||
console.log('snapshot current.vmdk vhd openned')
|
||||
await vhd.readBlockAllocationTable()
|
||||
console.log('realy vhd from snapshot bat ok ')
|
||||
console.log('snapshot current.vmdk bat openned')
|
||||
|
||||
return vhd.stream()
|
||||
},
|
||||
rawStream: async () => {
|
||||
console.log('rawStream from snapshot')
|
||||
console.log('snapshot rawStream from snapshot')
|
||||
if(!fileName.endsWith('-flat.vmdk')){
|
||||
return
|
||||
}
|
||||
console.log('flat.vmdk ')
|
||||
const vhd = await VhdEsxiRaw.open(this, diskDataStore, dirname(diskPath) + '/' + fileName, parentFileName)
|
||||
console.log('flat.vmdk vhd openned')
|
||||
await vhd.readBlockAllocationTable()
|
||||
console.log('flat.vmdk bat openned')
|
||||
return vhd.stream()
|
||||
|
||||
console.log('snapshot rawStream from snapshot filename ok')
|
||||
// @todo : only if vm is powered off
|
||||
const stream = (await this.download(diskDataStore, dirname(diskPath) + '/' + fileName)).body
|
||||
console.log('snapshot realy vhd from snapshot got stream ')
|
||||
stream.length = capacity
|
||||
return stream
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -276,7 +283,12 @@ export default class Esxi extends EventEmitter {
|
||||
vhd: async () => {
|
||||
console.log('current.vmdk')
|
||||
if(fileName.endsWith('-flat.vmdk')){
|
||||
return
|
||||
console.log('flat.vmdk vhd ')
|
||||
const vhd = await VhdEsxiRaw.open(this, datastore, path + '/' + fileName)
|
||||
console.log('flat.vmdk vhd openned')
|
||||
await vhd.readBlockAllocationTable()
|
||||
console.log('flat.vmdk bat openned')
|
||||
return vhd.stream()
|
||||
}
|
||||
console.log('current.vmdk filenameok')
|
||||
// last snasphot only works when vm is powered off
|
||||
@@ -291,12 +303,14 @@ export default class Esxi extends EventEmitter {
|
||||
if(fileName.endsWith('-flat.vmdk')){
|
||||
return
|
||||
}
|
||||
// @todo : only if vm is powered off or with snapshot
|
||||
const vhd = await VhdEsxiRaw.open(this, datastore, path + '/' + fileName, parentFileName)
|
||||
console.log('flat.vmdk vhd openned')
|
||||
await vhd.readBlockAllocationTable()
|
||||
console.log('flat.vmdk bat openned')
|
||||
return vhd.stream()
|
||||
|
||||
console.log('rawStream from snapshot filename ok')
|
||||
// @todo : only if vm is powered off
|
||||
const stream = (await this.download(datastore, path + '/' + fileName)).body
|
||||
console.log('realy vhd from snapshot got stream ')
|
||||
stream.length = other.capacity
|
||||
return stream
|
||||
|
||||
},
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -23,11 +23,8 @@ export class VhdCowd extends VhdAbstract{
|
||||
#grainDirectory
|
||||
|
||||
static async open(esxi, datastore, path) {
|
||||
console.log('vmdcowd.open ', datastore, path)
|
||||
const vhd = new VhdCowd(esxi, datastore, path)
|
||||
console.log('vmdcowd.open instantiated ')
|
||||
await vhd.readHeaderAndFooter()
|
||||
console.log('vmdcowd.open readHeaderAndFooter ')
|
||||
return vhd
|
||||
}
|
||||
constructor(esxi, datastore, path, parentFileName){
|
||||
@@ -85,7 +82,6 @@ export class VhdCowd extends VhdAbstract{
|
||||
this.#header.parentUnicodeName = this.#parentFileName
|
||||
const geometry = _computeGeometryForSize(size)
|
||||
const actualSize = geometry.actualSize
|
||||
console.log(' DELTA ? ',this.#parentFileName ? 'yes' : 'no')
|
||||
this.#footer = unpackFooter(createFooter(actualSize, Math.floor(Date.now() / 1000), geometry, FOOTER_SIZE, this.#parentFileName ? DISK_TYPES.DIFFERENCING : DISK_TYPES.DYNAMIC))
|
||||
|
||||
}
|
||||
@@ -140,7 +136,6 @@ export class VhdCowd extends VhdAbstract{
|
||||
const OVERPROVISION = 3
|
||||
for(let i=1; i < offsets.length; i ++){
|
||||
if(offsets[i-1] + OVERPROVISION < offsets[i]){
|
||||
// console.log('non contiguous', startOffset, offsets[i-1], offsets[i] )
|
||||
ranges.push({startOffset, endOffset: offsets[i-1]})
|
||||
startOffset = offsets[i]
|
||||
}
|
||||
@@ -152,13 +147,10 @@ export class VhdCowd extends VhdAbstract{
|
||||
const startIndex = fileOffsetToIndexInGrainTable[startOffset]
|
||||
const startInBlock = startIndex * 512 + 512 /* block bitmap */
|
||||
const sectors = await this.#read(startOffset*512,endOffset*512 - 1)
|
||||
console.log({startOffset, endOffset, sectors})
|
||||
// @todo : if overprovision > 1 , it may copy random data from the vmdk
|
||||
sectors.copy(buf,startInBlock)
|
||||
// console.log('got sectors and copied',sectors.length,' to ',startInBlock)
|
||||
|
||||
}
|
||||
//console.log({blockId, buf})
|
||||
return {
|
||||
id: blockId,
|
||||
bitmap: buf.slice(0, 512),
|
||||
|
||||
@@ -1300,9 +1300,9 @@ export { import_ as import }
|
||||
|
||||
|
||||
|
||||
export async function importFomEsxi({host, user, password, sslVerify, sr, network}){
|
||||
//console.log({host, user, password, sslVerify, sr, network})
|
||||
await this.migrationfromEsxi({host, user, password, sslVerify, sr, network})
|
||||
export async function importFomEsxi({host, user, password, sslVerify=true, sr, network, vm, thin=false}){
|
||||
console.log({host, user, password, sslVerify, sr, network, vm, thin})
|
||||
await this.migrationfromEsxi({host, user, password, sslVerify, thin, vm, sr, network})
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1312,7 +1312,9 @@ importFomEsxi.params = {
|
||||
password: { type: 'string' },
|
||||
user: { type: 'string' },
|
||||
sr: { type: 'string' },
|
||||
sslVerify: {type: 'boolean'}
|
||||
sslVerify: {type: 'boolean', optional: true},
|
||||
vm:{type: 'string'},
|
||||
thin:{type: 'boolean', optional: true}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -5,30 +5,6 @@ import OTHER_CONFIG_TEMPLATE from '../xapi/other-config-template.mjs'
|
||||
import asyncMapSettled from '@xen-orchestra/async-map/legacy.js'
|
||||
import { fromEvent } from 'promise-toolbox'
|
||||
import { VDI_FORMAT_RAW, VDI_FORMAT_VHD } from '@xen-orchestra/xapi'
|
||||
import { readChunk } from '@vates/read-chunk'
|
||||
|
||||
async function checkEmpty(stream){
|
||||
let chunk
|
||||
let nbEmpty = 0
|
||||
let nbFull = 0
|
||||
const empty = Buffer.alloc(2*1024*1024, 0)
|
||||
while(chunk = await readChunk(stream, 2 * 1024 * 1024)){
|
||||
|
||||
const isEmpty = empty.equals(chunk)
|
||||
if(isEmpty){
|
||||
nbEmpty ++
|
||||
} else {
|
||||
nbFull ++
|
||||
}
|
||||
if((nbEmpty + nbFull)%10 ===0){
|
||||
console.log('.',{nbEmpty, nbFull})
|
||||
}
|
||||
}
|
||||
|
||||
console.log({nbEmpty, nbFull})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default class MigrateVm {
|
||||
constructor(app) {
|
||||
@@ -136,22 +112,8 @@ export default class MigrateVm {
|
||||
}
|
||||
}
|
||||
|
||||
async #coldMigrationFromEsxi({ memory, numCpu, name_label, disks, networks, powerState, ...other }, srId, networkId){
|
||||
|
||||
|
||||
console.log('metadata', { memory, numCpu, name_label, disks, networks, other })
|
||||
if (powerState !== 'powerOff') {
|
||||
console.log('RUNNING ', powerState)
|
||||
}
|
||||
const sr = this._app.getXapiObject(srId)
|
||||
const xapi = sr.$xapi
|
||||
// find correspondig networks
|
||||
|
||||
console.log('disk and network created')
|
||||
return vmChooseCoresPerSocket
|
||||
}
|
||||
|
||||
async migrationfromEsxi({ host, user, password, sslVerify, sr: srId, network: networkId }) {
|
||||
async migrationfromEsxi({ host, user, password, sslVerify, sr: srId, network: networkId, vm:vmId ,thin}) {
|
||||
const esxi = new Esxi(host, user, password, sslVerify)
|
||||
const app = this._app
|
||||
const sr = app.getXapiObject(srId)
|
||||
@@ -161,7 +123,7 @@ export default class MigrateVm {
|
||||
await fromEvent(esxi, 'ready')
|
||||
console.log('connected')
|
||||
const esxiVmMetadata = await esxi.getTransferableVmMetadata(
|
||||
'9'
|
||||
vmId
|
||||
)
|
||||
const { memory,name_label, networks, numCpu } = esxiVmMetadata
|
||||
const vm = await xapi._getOrWaitObject(
|
||||
@@ -185,7 +147,6 @@ export default class MigrateVm {
|
||||
])
|
||||
|
||||
const vifDevices = await xapi.call('VM.get_allowed_VIF_devices', vm.$ref)
|
||||
console.log({ vifDevices })
|
||||
|
||||
await Promise.all(networks.map((network, i) =>
|
||||
xapi.VIF_create({
|
||||
@@ -195,40 +156,6 @@ export default class MigrateVm {
|
||||
})
|
||||
))
|
||||
console.log('network created')
|
||||
/*
|
||||
await Promise.all(
|
||||
disks
|
||||
.map(async disk => {
|
||||
const vdi = await xapi._getOrWaitObject(
|
||||
await xapi.VDI_create({
|
||||
name_description: disk.descriptionLabel,
|
||||
name_label: disk.nameLabel,
|
||||
SR: sr.$ref,
|
||||
virtual_size: disk.capacity,
|
||||
})
|
||||
)
|
||||
await xapi.VBD_create({
|
||||
userdevice: String(disk.position),
|
||||
VDI: vdi.$ref,
|
||||
VM: vm.$ref,
|
||||
})
|
||||
console.log('will import disk', (await disk.rawStream()).length)
|
||||
console.log('')
|
||||
|
||||
let format = VDI_FORMAT_VHD
|
||||
let stream = await disk.vhd()
|
||||
if(!stream){
|
||||
format = VDI_FORMAT_RAW
|
||||
stream = await disk.rawStream()
|
||||
}
|
||||
await vdi.$importContent(stream, { format })
|
||||
console.log('disk imported')
|
||||
})
|
||||
)
|
||||
*/
|
||||
// CREATE VM
|
||||
|
||||
|
||||
|
||||
// get the snapshot to migrate
|
||||
const snapshots = esxiVmMetadata.snapshots
|
||||
@@ -239,8 +166,7 @@ export default class MigrateVm {
|
||||
|
||||
const chain = [currentSnapshot.disks]
|
||||
while(currentSnapshot = snapshots.snapshots.find(({uid})=> uid === currentSnapshot.parent)){
|
||||
console.log('found parent ', currentSnapshot)
|
||||
chain.push(currentSnapshot.disks)
|
||||
// chain.push(currentSnapshot.disks)
|
||||
}
|
||||
chain.reverse()
|
||||
chain.push( esxiVmMetadata.disks)
|
||||
@@ -253,9 +179,7 @@ export default class MigrateVm {
|
||||
})
|
||||
})
|
||||
|
||||
console.log(chainsByNodes)
|
||||
for(const node in chainsByNodes){
|
||||
console.log('IMPORTING chain' , node)
|
||||
let chainByNode = chainsByNodes[node]
|
||||
|
||||
const vdi = await xapi._getOrWaitObject(
|
||||
@@ -266,14 +190,12 @@ export default class MigrateVm {
|
||||
virtual_size: chainByNode[0].capacity,
|
||||
})
|
||||
)
|
||||
console.log('vdi created')
|
||||
|
||||
await xapi.VBD_create({
|
||||
userdevice: String(0),
|
||||
VDI: vdi.$ref,
|
||||
VM: vm.$ref,
|
||||
})
|
||||
console.log('vbd created')
|
||||
for(const disk of chainByNode){
|
||||
|
||||
// the first one is a RAW disk ( full )
|
||||
@@ -282,16 +204,17 @@ export default class MigrateVm {
|
||||
|
||||
console.log('will import ',{ disk})
|
||||
let format = VDI_FORMAT_VHD
|
||||
let stream = await disk.vhd()
|
||||
if(!stream){
|
||||
// format = VDI_FORMAT_RAW
|
||||
let stream
|
||||
if(!thin){
|
||||
stream = await disk.rawStream()
|
||||
format = VDI_FORMAT_RAW
|
||||
}
|
||||
if(!stream){
|
||||
stream = await disk.vhd()
|
||||
}
|
||||
console.log('will import in format ',{format})
|
||||
//await checkEmpty(stream)
|
||||
await vdi.$importContent(stream, { format })
|
||||
console.log('disk imported')
|
||||
break;
|
||||
}
|
||||
|
||||
// and then we can import the running disk ( after shutting down the VM)
|
||||
|
||||
Reference in New Issue
Block a user