KVM SR: Add support for NAT based networking (User Mode Network).

Note: Duplicates code, and heavy use of recipes.
parent a1c5eccf
......@@ -65,11 +65,40 @@ class Recipe(GenericBaseRecipe):
default_disk_image=self.options['default-disk-image'],
)
# Runners
runner_path = self.createExecutable(
self.options['runner-path'],
self.substituteTemplate(self.getTemplateFilename('kvm_run.in'),
config))
path_list = []
use_tap = self.options.get('use-tap')
if self.isTrueValue(use_tap):
runner_path = self.createExecutable(
self.options['runner-path'],
self.substituteTemplate(self.getTemplateFilename('kvm_run.in'),
config))
path_list.append(runner_path)
else:
config['nat_rules'] = self.options['nat-rules']
runner_path = self.createExecutable(
self.options['runner-path'],
self.substituteTemplate(self.getTemplateFilename('kvm_run_nat.in'),
config))
path_list.append(runner_path)
# XXX This could be done using Jinja.
for port in self.options['nat-rules'].split():
ipv6_port = int(port) + 10000
tunnel_path = self.createExecutable(
'%s-%sto%s' % (self.options['6tunnel-wrapper-path'], port, ipv6_port),
self.substituteTemplate(
self.getTemplateFilename('6to4.in'),
{
'ipv6': self.options['ipv6'],
'ipv6_port': ipv6_port,
'ipv4': self.options['ipv4'],
'ipv4_port': port,
'shell_path': self.options['shell-path'],
'6tunnel_path': self.options['6tunnel-path'],
},
),
)
path_list.append(tunnel_path)
controller_path = self.createExecutable(
self.options['controller-path'],
......@@ -77,4 +106,4 @@ class Recipe(GenericBaseRecipe):
config))
return [runner_path, controller_path]
return path_list
#!%(shell_path)s
# BEWARE: This file is operated by slapgrid
# BEWARE: It will be overwritten automatically
exec %(6tunnel_path)s -6 -4 -d -l %(ipv6)s %(ipv6_port)s %(ipv4)s %(ipv4_port)s
#!%(python_path)s
# BEWARE: This file is operated by slapgrid
# BEWARE: It will be overwritten automatically
# Echo client program
import os
import socket
import subprocess
def getSocketStatus(host, port):
s = None
for res in socket.getaddrinfo(host, port,
socket.AF_UNSPEC, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except socket.error, msg:
s = None
continue
try:
s.connect(sa)
except socket.error, msg:
s.close()
s = None
continue
break
return s
# XXX: give all of this through parameter, don't use this as template
default_disk_image = '%(default_disk_image)s'
# create disk if doesn't exist
disk_path = '%(disk_path)s'
if not os.path.exists(disk_path):
subprocess.Popen(['%(qemu_img_path)s', 'create' ,'-f', 'qcow2',
disk_path, '%(disk_size)sG'])
# Generate NAT rules
nat_rules = '%(nat_rules)s'
nat_rules = ','.join('hostfwd=tcp:%(vnc_ip)s:%%s-:%%s' %% (int(port) + 10000, port) for port in nat_rules.split())
kvm_argument_list = ['%(qemu_path)s',
'-enable-kvm', '-net', 'nic,macaddr=%(mac_address)s',
'-net', 'user,%%s' %% nat_rules,
'-smp', '%(smp_count)s',
'-m', '%(ram_size)s',
'-drive', 'file=%(disk_path)s,if=%(disk_type)s',
'-vnc', '%(vnc_ip)s:1,ipv4,password',
'-boot', 'menu=on',
'-qmp', 'unix:%(socket_path)s,server',
'-pidfile', '%(pid_file_path)s',
]
# Try to connect to NBD server (and second nbd if defined)
for nbd_ip, nbd_port in (
('%(nbd_ip)s', %(nbd_port)s), ('%(nbd2_ip)s', %(nbd2_port)s)):
if nbd_ip and nbd_port:
s = getSocketStatus(nbd_ip, nbd_port)
if s is None:
# NBD is not available : launch kvm without it
print 'Warning : Nbd is not available.'
else:
# NBD is available
kvm_argument_list.extend([
'-drive',
'file=nbd:[%%s]:%%s,media=cdrom' %% (nbd_ip, nbd_port)])
# If no NBD is specified/available: use internal disk image
else:
kvm_argument_list.extend([
'-drive', 'file=%%s,media=cdrom' %% default_disk_image
])
os.execv('%(qemu_path)s', kvm_argument_list)
[buildout]
extends =
../../component/6tunnel/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/dcron/buildout.cfg
......@@ -84,7 +85,7 @@ mode = 0644
[template-kvm]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-kvm.cfg.in
md5sum = f7c0e2172dac4ee70daae50f38d610ef
md5sum = c3c888c78bbff334135be9e8ad5885a9
output = ${buildout:directory}/template-kvm.cfg
mode = 0644
......
......@@ -68,6 +68,18 @@
"maximum": 65535
},
"use-tap": {
"title": "Use QEMU TAP network interface",
"description": "Use QEMU TAP network interface, requires a bridge on SlapOS Node. If false, use user-mode network stack (NAT).",
"type": "boolean",
"default": false
},
"nat-rules": {
"title": "List of rules for NAT of QEMU user mode network stack.",
"description": "List of rules for NAT of QEMU user mode network stack, as comma-separated list of ports. For each port specified, it will redirect port x of the VM (example: 80) to the port x + 10000 of the public IPv6 (example: 10080). Defaults to \"22 80 443\". Ignored if \"use-tap\" parameter is enabled.",
"type": "string",
},
"frontend-instance-guid": {
"title": "Frontend Instance ID",
......
......@@ -50,6 +50,8 @@ bytes = 8
# Specific code
recipe = slapos.cookbook:kvm
vnc-ip = $${slap-network-information:local-ipv4}
ipv4 = $${slap-network-information:local-ipv4}
ipv6 = $${slap-network-information:global-ipv6}
vnc-port = 5901
default-disk-image = ${debian-amd64-netinst.iso:location}/${debian-amd64-netinst.iso:filename}
nbd-host = $${slap-parameter:nbd-host}
......@@ -67,10 +69,14 @@ ram-size = $${slap-parameter:ram-size}
mac-address = $${create-mac:mac-address}
runner-path = $${directory:services}/kvm
controller-path = $${directory:scripts}/kvm_controller
use-tap = $${slap-parameter:use-tap}
nat-rules = $${slap-parameter:nat-rules}
shell-path = ${dash:location}/bin/dash
qemu-path = ${kvm:location}/bin/qemu-system-x86_64
qemu-img-path = ${kvm:location}/bin/qemu-img
passwd = $${gen-passwd:passwd}
6tunnel-path = ${6tunnel:location}/bin/6tunnel
6tunnel-wrapper-path = $${directory:services}/6tunnel
[kvm-promise]
recipe = slapos.cookbook:check_port_listening
......@@ -214,3 +220,7 @@ disk-size = 10
disk-type = virtio
cpu-count = 1
nat-rules = 22 80 443
use-tap = False
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 sign in to comment