@@ -96,6 +96,20 @@ class _HumanSizeScan(object):
96
96
human_size_scan = _HumanSizeScan ()
97
97
98
98
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
+
99
113
class ProxmoveError (Exception ):
100
114
pass
101
115
@@ -299,42 +313,73 @@ class ProxmoxCluster(object):
299
313
nodeid = self .get_random_node ()
300
314
301
315
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 ))
303
317
304
318
# Create disks according to config. Temporarily set ide\d+ and
305
319
# virtio\d+ devices to none until we can get them copied over.
306
320
mutable_config = {}
307
321
for key , value in config .items ():
308
- if key == 'name' :
322
+ if ((type_ == 'lxc' and key == 'hostname' ) or
323
+ (type_ != 'lxc' and key == 'name' )):
309
324
mutable_config [key ] = value + SUFFIX_CREATING
325
+
310
326
elif re .match (
311
327
'^({})\d+$' .format ('|' .join (PROXMOX_VOLUME_TYPES )), key ):
312
328
# Wipe it. We'll add the disks manually later on.
313
329
pass
330
+
314
331
else :
315
332
mutable_config [key ] = value
316
333
317
- # Guess new VMID and create one .
334
+ # Guess new VMID.
318
335
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.
319
364
api_node = self .api .nodes (nodeid )
320
365
vmhash = getattr (api_node , type_ ).create (vmid = vmid , ** mutable_config )
321
366
322
367
# Wait a while to ensure that we get the VM.
323
368
log .info (
324
369
'- 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 ))
326
371
for i in range (30 ):
327
372
try :
328
373
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 ) )
330
375
except ProxmoxVm .DoesNotExist :
331
376
pass
332
377
else :
333
378
break
334
379
time .sleep (1 )
335
380
else :
336
381
raise ProxmoveError ('Could not get newly created VM {!r}' .format (
337
- mutable_config [ 'name' ] ))
382
+ name_from_conf ( type_ , mutable_config ) ))
338
383
339
384
log .info ('- created new VM {!r}: {}' .format (vm .name , vm ))
340
385
return vm
@@ -840,7 +885,22 @@ class ProxmoxVm(object):
840
885
vm = cls (
841
886
dict_ ['name' ], dict_ ['node' ], dict_ ['type' ], dict_ ['vmid' ],
842
887
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
+
844
904
return vm
845
905
846
906
def __init__ (self , name , node , type_ , id_ , status , api , cluster ):
@@ -858,11 +918,15 @@ class ProxmoxVm(object):
858
918
"""
859
919
Check whether we can move this VM.
860
920
"""
921
+ if self .type == 'lxc' :
922
+ # No pending changes
923
+ return
924
+
861
925
config = self .get_config ()
862
926
863
927
# Check pending. We expect a list of dictionaries with a 'key'
864
928
# 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
866
930
pending = []
867
931
for dict_ in pending_config :
868
932
keys = dict_ .keys ()
@@ -886,7 +950,7 @@ class ProxmoxVm(object):
886
950
"""
887
951
if 'config' not in self ._cache :
888
952
next_config = self .api_vm .config .get ()
889
- self .name = next_config [ 'name' ]
953
+ self .name = name_from_conf ( self . type , next_config )
890
954
self ._cache ['config' ] = next_config
891
955
return self ._cache ['config' ]
892
956
@@ -928,7 +992,11 @@ class ProxmoxVm(object):
928
992
return self ._cache ['volumes' ]
929
993
930
994
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
+
932
1000
self .name = new_name
933
1001
934
1002
def ensure_started (self , timeout = 120 ):
@@ -1287,6 +1355,33 @@ class VmMover(object):
1287
1355
# Stop old VM, create storage, copy storage.
1288
1356
src_vm .ensure_stopped ()
1289
1357
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
+
1290
1385
for key , volume in src_vm .get_volumes ().items ():
1291
1386
assert key not in dst_vm .get_volumes (), key
1292
1387
@@ -1301,7 +1396,7 @@ class VmMover(object):
1301
1396
dst_vm .create_volume (key , volume , storage = storage )
1302
1397
1303
1398
# Done? Rename both.
1304
- dst_vm .rename (dst_config [ 'name' ] )
1399
+ dst_vm .rename (name_from_conf ( dst_vm . type , dst_config ) )
1305
1400
src_vm .rename (src_vm_name + SUFFIX_MIGRATED )
1306
1401
src_vm .add_comment ('{} UTC: Migrated to {}' .format (
1307
1402
datetime .utcnow (), dst_vm ))
0 commit comments