Commit 76f67bcf authored by Alain Takoudjou's avatar Alain Takoudjou

Merge branch 'kvm-cluster'

parents 828d9382 2d79471e
......@@ -9,6 +9,8 @@ import subprocess
import urllib
import gzip
import shutil
from random import shuffle
import glob
# XXX: give all of this through parameter, don't use this as template, but as module
qemu_img_path = '%(qemu-img-path)s'
......@@ -30,10 +32,13 @@ listen_ip = '%(ipv4)s'
mac_address = '%(mac-address)s'
tap_mac_address = '%(tap-mac-address)s'
smp_count = '%(smp-count)s'
smp_options = '%(smp-options)s'.strip()
numa_list = '%(numa)s'.split()
ram_size = '%(ram-size)s'
pid_file_path = '%(pid-file-path)s'
external_disk_number = %(external-disk-number)s
external_disk_size = '%(external-disk-size)s'
external_disk_format = '%(external-disk-format)s'
disk_storage_dict = {}
disk_storage_list = """%(disk-storage-list)s""".split('\n')
map_storage_list = []
......@@ -68,21 +73,41 @@ def getSocketStatus(host, port):
break
return s
def getMapStorageList(disk_storage_dict):
def getMapStorageList(disk_storage_dict, external_disk_number):
map_disk_file = os.path.join(etc_directory, '.data-disk-ids')
last_disk_num_f = os.path.join(etc_directory, '.data-disk-amount')
id_list = []
if os.path.exists(map_disk_file):
last_amount = 0
map_f_exist = os.path.exists(map_disk_file)
if os.path.exists(last_disk_num_f):
with open(last_disk_num_f, 'r') as lf:
last_amount = int(lf.readline())
if map_f_exist:
with open(map_disk_file, 'r') as mf:
# ID are writen in one line: data1 data3 data2 ...
content = mf.readline()
if content:
id_list = [id for id in content.split(' ') if disk_storage_dict.has_key(id)]
for id in content.split(' '):
if disk_storage_dict.has_key(id):
id_list.append(id)
else:
# Mean that this disk path has been removed (disk unmounted)
last_amount -= 1
for key in disk_storage_dict:
if not key in id_list:
id_list.append(key)
with open(map_disk_file, 'w') as mf:
mf.write(' '.join(id_list))
return id_list
if id_list:
if not map_f_exist:
# shuffle the list to not write disk in data1, data2, ... everytime
shuffle(id_list)
if external_disk_number < last_amount:
# Drop created disk is not allowed
external_disk_number = last_amount
with open(map_disk_file, 'w') as mf:
mf.write(' '.join(id_list))
with open(last_disk_num_f, 'w') as lf:
lf.write('%%s' %% external_disk_number)
return id_list, external_disk_number
# Download existing hard drive if needed at first boot
if not os.path.exists(disk_path) and virtual_hard_drive_url != '':
......@@ -122,24 +147,34 @@ if not os.path.exists(disk_path):
# Check and create external disk
additional_disk_list = []
for storage in sorted(disk_storage_list):
for storage in disk_storage_list:
if storage:
key, val = storage.split(' ')
disk_storage_dict[key.strip()] = val.strip()
map_storage_list = getMapStorageList(disk_storage_dict)
if not external_disk_format in ['qcow2', 'raw', 'vdi', 'vmdk', 'cloop']:
external_disk_format = 'qcow2'
map_storage_list, external_disk_number = getMapStorageList(disk_storage_dict,
int(external_disk_number))
assert len(map_storage_list) == len(disk_storage_dict)
if disk_storage_dict:
if int(external_disk_number) > 0:
if external_disk_number > 0:
index = 0
while (index < len(disk_storage_dict)) and (index < external_disk_number):
path = disk_storage_dict[map_storage_list[index]]
if os.path.exists(path):
disk_filepath = os.path.join(path, 'kvm_virtual_disk.qcow2')
if not os.path.exists(disk_filepath):
disk_filepath = os.path.join(path,
'kvm_virtual_disk.%%s' %% external_disk_format)
disk_list = glob.glob('%%s.*' %% os.path.join(path, 'kvm_virtual_disk'))
if disk_list == []:
print('Creating one additional virtual hard drive...')
subprocess.Popen([qemu_img_path, 'create' ,'-f', 'qcow2',
subprocess.Popen([qemu_img_path, 'create' ,'-f', '%%s' %% external_disk_format,
disk_filepath, '%%sG' %% external_disk_size])
else:
# Cannot change or recreate if disk is exists
disk_filepath = disk_list[0]
additional_disk_list.append(disk_filepath)
else:
print('Data folder %%s was not used to create external disk %%r' %% (index +1))
......@@ -150,6 +185,7 @@ if disk_storage_dict:
# XXX: use_tap should be a boolean
tap_network_parameter = []
nat_network_parameter = []
numa_parameter = []
number = -1
if use_nat == 'True':
number += 1
......@@ -164,8 +200,11 @@ if use_tap == 'True':
tap_interface),
'-device', 'e1000,netdev=lan%%s,mac=%%s' %% (number, tap_mac_address)]
smp = smp_count
if smp_options:
smp += ',%%s' %% smp_options
kvm_argument_list = [qemu_path,
'-enable-kvm', '-smp', smp_count,
'-enable-kvm', '-smp', smp,
'-m', ram_size, '-vga', 'std',
'-drive', 'file=%%s,if=%%s' %% (disk_path, disk_type),
'-vnc', '%%s:1,ipv4,password' %% listen_ip,
......@@ -173,6 +212,11 @@ kvm_argument_list = [qemu_path,
'-qmp', 'unix:%%s,server' %% socket_path,
'-pidfile', pid_file_path,
]
for numa in numa_list:
numa_parameter.extend(['-numa', numa])
kvm_argument_list += numa_parameter
if tap_network_parameter == [] and nat_network_parameter == []:
print 'Warning : No network interface defined.'
else:
......@@ -201,4 +245,5 @@ else:
'-drive', 'file=%%s,media=cdrom' %% default_disk_image
])
print 'Starting KVM: \n %%s' %% ' '.join(kvm_argument_list)
os.execv(qemu_path, kvm_argument_list)
......@@ -93,7 +93,7 @@ mode = 0644
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/instance-kvm.cfg.jinja2
mode = 644
md5sum = 5506e1df6ba32c6ead647636ebece79e
md5sum = c8f69039aff15e20447c6e522267c152
download-only = true
on-update = true
......@@ -101,7 +101,7 @@ on-update = true
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/instance-kvm-cluster.cfg.jinja2.in
mode = 644
md5sum = 214c46a9aa7605951b8a1f98572dac28
md5sum = a5c1f0620510a979daf8fd60120f6253
download-only = true
on-update = true
......
......@@ -166,6 +166,16 @@
"minimum": 1,
"maximum": 8
},
"cpu-options": {
"title": "Additional options (cores, threads, sockets, maxcpus) to use with cpu-count.",
"description": "Additional options to use with cpu-count. Options are separated by coma: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]. Only set this option if you really know what you're doing.",
"type": "string"
},
"numa": {
"title": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally.",
"description": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. Each numa option are separated by space: node,nodeid=4,cpus=40-49,mem=64g node,nodeid=1,cpus=10-19,mem=128g. Only set this option if you really know what you're doing.",
"type": "string"
},
"nbd-host": {
"title": "NBD hostname",
"description": "hostname (or IP) of the NBD server containing the boot image.",
......@@ -235,6 +245,13 @@
"maximum": 100,
"default": 20
},
"external-disk-format": {
"title": "Type of external disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop"]
},
"use-tap": {
"title": "Use QEMU TAP network interface",
"description": "Use QEMU TAP network interface, might require a bridge on SlapOS Node.",
......
......@@ -38,6 +38,8 @@ config-ram-size = {{ dumps(kvm_parameter_dict.get('ram-size', 1024)) }}
config-disk-size = {{ dumps(kvm_parameter_dict.get('disk-size', 10)) }}
config-disk-type = {{ dumps(kvm_parameter_dict.get('disk-type', 'virtio')) }}
config-cpu-count = {{ dumps(kvm_parameter_dict.get('cpu-count', 1)) }}
config-cpu-options = {{ dumps(kvm_parameter_dict.get('cpu-options', '')) }}
config-numa = {{ dumps(kvm_parameter_dict.get('numa', '')) }}
{% set nat_rules_list = kvm_parameter_dict.get('nat-rules', [22, 80, 443]) -%}
config-nat-rules = {{ nat_rules_list | join(' ') }}
......@@ -49,6 +51,7 @@ config-virtual-hard-drive-md5sum = {{ dumps(kvm_parameter_dict.get('virtual-hard
config-virtual-hard-drive-gzipped = {{ dumps(kvm_parameter_dict.get('virtual-hard-drive-gzipped', False)) }}
config-external-disk-number = {{ dumps(kvm_parameter_dict.get('external-disk-number', 0)) }}
config-external-disk-size = {{ dumps(kvm_parameter_dict.get('external-disk-size', 20)) }}
config-external-disk-format = {{ dumps(kvm_parameter_dict.get('external-disk-format', 'qcow2')) }}
return =
backend-url
url
......
......@@ -36,6 +36,16 @@
"minimum": 1,
"maximum": 8
},
"cpu-options": {
"title": "Additional options (cores, threads, sockets, maxcpus) to use with cpu-count.",
"description": "Additional options to use with cpu-count. Options are separated by coma: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]. Only set this option if you really know what you're doing.",
"type": "string"
},
"numa": {
"title": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally.",
"description": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. Each numa option are separated by space: node,nodeid=4,cpus=40-49,mem=64g node,nodeid=1,cpus=10-19,mem=128g. Only set this option if you really know what you're doing.",
"type": "string"
},
"nbd-host": {
"title": "NBD hostname",
......@@ -101,6 +111,13 @@
"maximum": 100,
"default": 20
},
"external-disk-format": {
"title": "Type of external disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop"]
},
"use-tap": {
"title": "Use QEMU TAP network interface",
......
......@@ -81,7 +81,9 @@ socket-path = ${directory:var}/qmp_socket
pid-file-path = ${directory:run}/pid_file
smp-count = ${slap-parameter:cpu-count}
smp-options = ${slap-parameter:cpu-options}
ram-size = ${slap-parameter:ram-size}
numa = ${slap-parameter:numa}
mac-address = ${create-mac:mac-address}
tap-mac-address = ${create-tap-mac:mac-address}
......@@ -110,6 +112,7 @@ disk-storage-list =
{% endfor -%}
external-disk-number = ${slap-parameter:external-disk-number}
external-disk-size = ${slap-parameter:external-disk-size}
external-disk-format = ${slap-parameter:external-disk-format}
[kvm-vnc-promise]
recipe = slapos.cookbook:check_port_listening
......@@ -275,6 +278,10 @@ disk-size = 10
disk-type = virtio
cpu-count = 1
# cpu-option is a string: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]
cpu-options =
# list of numa options separate by space: node,nodeid=1,cpus=9-15 node,nodeid=2,cpus=1,3,7
numa =
nat-rules = 22 80 443
use-nat = True
......@@ -286,3 +293,4 @@ virtual-hard-drive-gzipped = False
external-disk-number = 0
external-disk-size = 20
external-disk-format = qcow2
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment