Skip to content

Commit 8fc9e94

Browse files
committed
LXC container move notes. Not fully implemented!
1 parent e6c57f1 commit 8fc9e94

File tree

2 files changed

+110
-11
lines changed

2 files changed

+110
-11
lines changed

CHANGES.rst

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Changes
33

44
* **HEAD** - xxxx-xx-xx
55

6+
New features:
7+
8+
- Partial LXC container move implemented. Not complete.
9+
610
* **v0.0.7** - 2016-10-07
711

812
Bugs fixed:

proxmove

+106-11
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,20 @@ class _HumanSizeScan(object):
9696
human_size_scan = _HumanSizeScan()
9797

9898

99+
def name_from_conf(type_, config):
100+
"""
101+
For 'lxc', the unique name is in 'hostname'. For others it is in 'name'.
102+
"""
103+
if type_ == 'lxc':
104+
assert 'name' not in config, config
105+
assert 'hostname' in config, config
106+
return config['hostname']
107+
108+
assert 'hostname' not in config, config
109+
assert 'name' in config, config
110+
return config['name']
111+
112+
99113
class ProxmoveError(Exception):
100114
pass
101115

@@ -299,42 +313,73 @@ class ProxmoxCluster(object):
299313
nodeid = self.get_random_node()
300314

301315
log.info('Creating new VM {!r} on {!r}, node {!r}'.format(
302-
config['name'], self.name, nodeid))
316+
name_from_conf(type_, config), self.name, nodeid))
303317

304318
# Create disks according to config. Temporarily set ide\d+ and
305319
# virtio\d+ devices to none until we can get them copied over.
306320
mutable_config = {}
307321
for key, value in config.items():
308-
if key == 'name':
322+
if ((type_ == 'lxc' and key == 'hostname') or
323+
(type_ != 'lxc' and key == 'name')):
309324
mutable_config[key] = value + SUFFIX_CREATING
325+
310326
elif re.match(
311327
'^({})\d+$'.format('|'.join(PROXMOX_VOLUME_TYPES)), key):
312328
# Wipe it. We'll add the disks manually later on.
313329
pass
330+
314331
else:
315332
mutable_config[key] = value
316333

317-
# Guess new VMID and create one.
334+
# Guess new VMID.
318335
vmid = self.get_free_vmid()
336+
337+
if type_ == 'lxc':
338+
# LXC(FIXME): We need to create the dst filesystem here.
339+
# A matter of:
340+
# zfs create -o refquota=HUMAN_SIZE ZFS_PATH_NO_LEAD_SLASH
341+
# For example:
342+
# zfs create -o refquota=20G rpool/data/images/subvol-160-disk-1
343+
# Next: decide whether we want a super-minimal tar.gz which we'll
344+
# simply overwrite during the filesystem copy, or do the copy first
345+
# and "install" that image.
346+
# Note: possibly also PVEDatastoreAdmin permissions are required
347+
# for the untar.
348+
assert 'ostemplate' not in mutable_config, mutable_config
349+
mutable_config['ostemplate'] = (
350+
# Note that 'vztmpl' is a magic constant that defines
351+
# that this is a tar.gz source filesystem. See
352+
# PVE/Storage/Plugin.pm. Also, for sane debugging of
353+
# 500-errors, do an ngrep on port 85 on the destination
354+
# host (lo-interface) to get a few more clues.
355+
# This file is hardcoded for now, and will not work on
356+
# your system.
357+
'SRCDISK:vztmpl/ubuntu-14.04-standard_14.04-1_amd64.tar.gz')
358+
mutable_config['rootfs'] = (
359+
# This requires a leading zfs create. See comments above.
360+
'DSTDISK:subvol-{vmid}-disk-1,size=20G'.format(
361+
vmid=vmid))
362+
363+
# Create new VM.
319364
api_node = self.api.nodes(nodeid)
320365
vmhash = getattr(api_node, type_).create(vmid=vmid, **mutable_config)
321366

322367
# Wait a while to ensure that we get the VM.
323368
log.info(
324369
'- created new VM {!r} as {}; waiting for it to show up'.format(
325-
mutable_config['name'], vmhash))
370+
name_from_conf(type_, mutable_config), vmhash))
326371
for i in range(30):
327372
try:
328373
self._cache = {} # purge cache, we expect changes
329-
vm = self.get_vm(mutable_config['name'])
374+
vm = self.get_vm(name_from_conf(type_, mutable_config))
330375
except ProxmoxVm.DoesNotExist:
331376
pass
332377
else:
333378
break
334379
time.sleep(1)
335380
else:
336381
raise ProxmoveError('Could not get newly created VM {!r}'.format(
337-
mutable_config['name']))
382+
name_from_conf(type_, mutable_config)))
338383

339384
log.info('- created new VM {!r}: {}'.format(vm.name, vm))
340385
return vm
@@ -840,7 +885,22 @@ class ProxmoxVm(object):
840885
vm = cls(
841886
dict_['name'], dict_['node'], dict_['type'], dict_['vmid'],
842887
dict_['status'], api, cluster)
843-
vm.get_config() # get config and check for pending changes at once
888+
889+
# LXC(FIXME): When creating an LXC container, the get_config()
890+
# may contain a 'digest' only. We need to wait until its fully
891+
# populated with at least the name. This is a hack, and we
892+
# definitely should not use AssertionError for it.
893+
for i in range(10):
894+
try:
895+
# Get config and check for pending changes at once.
896+
vm.get_config()
897+
except AssertionError:
898+
time.sleep(1)
899+
else:
900+
break
901+
else:
902+
raise
903+
844904
return vm
845905

846906
def __init__(self, name, node, type_, id_, status, api, cluster):
@@ -858,11 +918,15 @@ class ProxmoxVm(object):
858918
"""
859919
Check whether we can move this VM.
860920
"""
921+
if self.type == 'lxc':
922+
# No pending changes
923+
return
924+
861925
config = self.get_config()
862926

863927
# Check pending. We expect a list of dictionaries with a 'key'
864928
# key and 'value' and/or 'pending' keys.
865-
pending_config = self.api_vm.pending.get() # may not exist for lxc
929+
pending_config = self.api_vm.pending.get() # does not exist for lxc
866930
pending = []
867931
for dict_ in pending_config:
868932
keys = dict_.keys()
@@ -886,7 +950,7 @@ class ProxmoxVm(object):
886950
"""
887951
if 'config' not in self._cache:
888952
next_config = self.api_vm.config.get()
889-
self.name = next_config['name']
953+
self.name = name_from_conf(self.type, next_config)
890954
self._cache['config'] = next_config
891955
return self._cache['config']
892956

@@ -928,7 +992,11 @@ class ProxmoxVm(object):
928992
return self._cache['volumes']
929993

930994
def rename(self, new_name):
931-
self.api_vm.config.put(name=new_name)
995+
if self.type == 'lxc':
996+
self.api_vm.config.put(hostname=new_name)
997+
else:
998+
self.api_vm.config.put(name=new_name)
999+
9321000
self.name = new_name
9331001

9341002
def ensure_started(self, timeout=120):
@@ -1287,6 +1355,33 @@ class VmMover(object):
12871355
# Stop old VM, create storage, copy storage.
12881356
src_vm.ensure_stopped()
12891357
src_vm.rename(src_vm_name + SUFFIX_CLONING)
1358+
1359+
# LXC(FIXME): Here we should migrate/copy the ROOTFS data
1360+
# for LXC too. Example old config: {
1361+
# 'rootfs': 'pool0-pve2-ssd:subvol-105-disk-1,size=20G',
1362+
# 'searchdomain': '91.xxx.xxx.xx', 'cpuunits': 1024,
1363+
# 'cpulimit': '2', 'swap': 0, 'hostname': 'osso-xxxxxxxxxxxxxx',
1364+
# 'net1': 'bridge=vmbr535,hwaddr=32:xx:xx:xx:xx:xx,'
1365+
# 'ip=10.xx.xx.xx/24,name=eth1,type=veth',
1366+
# 'memory': 2048, 'net0': 'bridge=vmbr0,gw=10.xxx.x.x,'
1367+
# 'hwaddr=66:xx:xx:xx:xx:xx,ip=10.xxx.x.xx/24,'
1368+
# 'name=eth0,type=veth',
1369+
# 'ostype': 'ubuntu', 'nameserver': '91.xxx.xxx.xx 8.8.8.8',
1370+
# 'arch': 'amd64'}
1371+
# Example new config: {
1372+
# 'rootfs': 'mc11-6-local-ssd:subvol-160-disk-1,size=20G',
1373+
# 'searchdomain': '91.xxx.xxx.xx', 'cpuunits': 1024,
1374+
# 'ostemplate':
1375+
# # Note that 'vztmpl' is hardcoded in PVE/Storage/Plugin.pm
1376+
# 'san06:vztmpl/ubuntu-14.04-standard_14.04-1_amd64.tar.gz',
1377+
# 'arch': 'amd64', 'cpulimit': '2',
1378+
# 'hostname': 'osso-swift-mgmt-tcn--CREATING',
1379+
# 'nameserver': '91.xxx.xxx.xx 8.8.8.8', 'memory': 2048,
1380+
# 'net0': 'bridge=vmbr0,gw=10.xxx.x.x,hwaddr=66:xx:xx:xx:xx:xx,'
1381+
# 'ip=10.xxx.x.xx/24,name=eth0,type=veth', 'ostype': 'ubuntu',
1382+
# 'net1': 'bridge=vmbr535,hwaddr=32:xx:xx:xx:xx:xx,'
1383+
# 'ip=10.xx.xx.xx/24,name=eth1,type=veth', 'swap': 0}
1384+
12901385
for key, volume in src_vm.get_volumes().items():
12911386
assert key not in dst_vm.get_volumes(), key
12921387

@@ -1301,7 +1396,7 @@ class VmMover(object):
13011396
dst_vm.create_volume(key, volume, storage=storage)
13021397

13031398
# Done? Rename both.
1304-
dst_vm.rename(dst_config['name'])
1399+
dst_vm.rename(name_from_conf(dst_vm.type, dst_config))
13051400
src_vm.rename(src_vm_name + SUFFIX_MIGRATED)
13061401
src_vm.add_comment('{} UTC: Migrated to {}'.format(
13071402
datetime.utcnow(), dst_vm))

0 commit comments

Comments
 (0)