[WIP] finish implementing cross pve-host disk transfers and mounting
This commit is contained in:
parent
9eddb96402
commit
0545c8337b
@ -44,6 +44,8 @@ export class Volumes extends Controller {
|
||||
mountpoint = rawMountpoint
|
||||
}
|
||||
|
||||
console.log('Mount options', this.request.input('options'))
|
||||
|
||||
vol = await this.provisioner.mountVolume(vol, mountpoint)
|
||||
return vol.toAPI()
|
||||
}
|
||||
@ -54,7 +56,24 @@ export class Volumes extends Controller {
|
||||
}
|
||||
|
||||
public async transfer(vol: Volume, toNode: Node) {
|
||||
const fromNode = await vol.getNode()
|
||||
|
||||
if ( fromNode.pveId === toNode.pveId ) {
|
||||
// The volume is already attached to the target node, so we're done
|
||||
} else if ( fromNode.pveHost === toNode.pveHost ) {
|
||||
// If the from/to nodes are on the same physical host, just transfer the volume directly
|
||||
vol = await this.provisioner.transferVolume(vol, toNode)
|
||||
} else {
|
||||
// If the nodes are on different physical hosts, we need to create a temporary container
|
||||
// on shared storage to attach the volume to. We'll then migrate that container to the
|
||||
// target physical host.
|
||||
let carrier = await this.provisioner.provisionCarrierContainer(fromNode)
|
||||
vol = await this.provisioner.transferVolume(vol, carrier)
|
||||
carrier = await this.provisioner.migrateNode(carrier, toNode.pveHost)
|
||||
vol = await this.provisioner.transferVolume(vol, toNode)
|
||||
await this.provisioner.unprovisionCarrierContainer(carrier)
|
||||
}
|
||||
|
||||
return vol.toAPI()
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export class ConfigLines extends Collection<string> {
|
||||
@Injectable()
|
||||
export class Node extends Model<Node> {
|
||||
protected static table = 'p5x_nodes'
|
||||
protected static key = 'node_id'
|
||||
protected static key = 'id'
|
||||
|
||||
public static async getMaster(): Promise<Node> {
|
||||
const master = await Node.query<Node>()
|
||||
|
@ -208,14 +208,14 @@ export class Provisioner {
|
||||
return volume
|
||||
}
|
||||
|
||||
public async provisionCarrierContainer(node: Node): Promise<string> {
|
||||
public async provisionCarrierContainer(node: Node): Promise<Node> {
|
||||
// Get the Proxmox API!
|
||||
const proxmox = await this.getApi()
|
||||
const nodeName = node.pveHost.split('/')[1]
|
||||
const pveHost = proxmox.nodes.$(nodeName)
|
||||
|
||||
// Ensure the empty filesystem template exists
|
||||
const host = await node.getHost() // fixme this is wrong -- need pve host
|
||||
const host = await this.getPVEHost(node.unqualifiedPVEHost())
|
||||
const fs = await host.getFilesystem()
|
||||
const stat = await fs.stat({ storePath: '/var/lib/vz/template/cache/p5x-empty.tar.xz' })
|
||||
if ( !stat.exists ) {
|
||||
@ -239,7 +239,7 @@ export class Provisioner {
|
||||
cores: 1,
|
||||
description: 'Temporary container managed by P5x',
|
||||
hostname: name,
|
||||
memory: 10, // in MB
|
||||
memory: 16, // in MB
|
||||
start: false,
|
||||
storage: await Setting.loadOneRequired('pveStoragePool'),
|
||||
tags: 'p5x',
|
||||
@ -249,7 +249,30 @@ export class Provisioner {
|
||||
await this.waitForNodeTask(nodeName, createUPID)
|
||||
|
||||
this.logging.info(`Created carrier container: ${name}`)
|
||||
return name
|
||||
const carrierNode = this.container.makeNew<Node>(Node)
|
||||
carrierNode.pveId = carrierVMID
|
||||
carrierNode.hostname = name
|
||||
carrierNode.assignedIp = carrierIP
|
||||
carrierNode.assignedSubnet = ipRange.subnet
|
||||
carrierNode.pveHost = node.pveHost
|
||||
await carrierNode.save()
|
||||
return carrierNode
|
||||
}
|
||||
|
||||
public async unprovisionCarrierContainer(node: Node): Promise<void> {
|
||||
this.logging.info(`Deleting carrier container ${node.pveId}`)
|
||||
const api = await this.getApi()
|
||||
const upid = await api
|
||||
.nodes.$(node.unqualifiedPVEHost())
|
||||
.lxc.$(node.pveId)
|
||||
.$delete({
|
||||
purge: true,
|
||||
'destroy-unreferenced-disks': true,
|
||||
})
|
||||
|
||||
await this.waitForNodeTask(node.unqualifiedPVEHost(), upid)
|
||||
await node.delete()
|
||||
this.logging.success(`Deleted carrier container ${node.pveId}`)
|
||||
}
|
||||
|
||||
public async provisionNode(group: HostGroup): Promise<Node> {
|
||||
@ -615,6 +638,27 @@ export class Provisioner {
|
||||
return vol
|
||||
}
|
||||
|
||||
public async migrateNode(node: Node, qualifiedPveHost: string): Promise<Node> {
|
||||
this.logging.info(`Migrating node ${node.pveId} from ${node.pveHost} to ${qualifiedPveHost}`)
|
||||
const api = await this.getApi()
|
||||
const originalUnqualifiedPveHost = node.unqualifiedPVEHost()
|
||||
|
||||
node.pveHost = qualifiedPveHost
|
||||
const upid = await api
|
||||
.nodes.$(originalUnqualifiedPveHost)
|
||||
.lxc.$(node.pveId)
|
||||
.migrate.$post({
|
||||
target: node.unqualifiedPVEHost(),
|
||||
})
|
||||
|
||||
this.logging.info(`Waiting for migrate task: ${upid}`)
|
||||
await this.waitForNodeTask(originalUnqualifiedPveHost, upid)
|
||||
|
||||
await node.save()
|
||||
this.logging.success(`Migrated node ${node.pveId} from ${node.pveHost} to ${qualifiedPveHost}`)
|
||||
return node
|
||||
}
|
||||
|
||||
public async getPVEHost(pveHost: string): Promise<Host> {
|
||||
const api = await this.getApi()
|
||||
const ifaces = await api.nodes.$(pveHost).network.$get()
|
||||
|
Loading…
Reference in New Issue
Block a user