Commit 992a1245 authored by Joanne Hugé's avatar Joanne Hugé

Update Release Candidate

parents 09cf1404 3725205d
...@@ -112,7 +112,6 @@ setup(name=name, ...@@ -112,7 +112,6 @@ setup(name=name,
'ipv4toipv6 = slapos.recipe.6tunnel:FourToSix', 'ipv4toipv6 = slapos.recipe.6tunnel:FourToSix',
'ipv6toipv4 = slapos.recipe.6tunnel:SixToFour', 'ipv6toipv4 = slapos.recipe.6tunnel:SixToFour',
'jsondump = slapos.recipe.jsondump:Recipe', 'jsondump = slapos.recipe.jsondump:Recipe',
'kvm.frontend = slapos.recipe.kvm_frontend:Recipe',
'logrotate = slapos.recipe.logrotate:Recipe', 'logrotate = slapos.recipe.logrotate:Recipe',
'logrotate.d = slapos.recipe.logrotate:Part', 'logrotate.d = slapos.recipe.logrotate:Part',
'mkdirectory = slapos.recipe.mkdirectory:Recipe', 'mkdirectory = slapos.recipe.mkdirectory:Recipe',
...@@ -147,7 +146,6 @@ setup(name=name, ...@@ -147,7 +146,6 @@ setup(name=name,
'requestoptional.serialised = ' 'requestoptional.serialised = '
'slapos.recipe.request:RequestOptionalJSONEncoded', 'slapos.recipe.request:RequestOptionalJSONEncoded',
're6stnet.registry = slapos.recipe.re6stnet:Recipe', 're6stnet.registry = slapos.recipe.re6stnet:Recipe',
'reverseproxy.nginx = slapos.recipe.reverse_proxy_nginx:Recipe',
'sheepdogtestbed = slapos.recipe.sheepdogtestbed:SheepDogTestBed', 'sheepdogtestbed = slapos.recipe.sheepdogtestbed:SheepDogTestBed',
'shell = slapos.recipe.shell:Recipe', 'shell = slapos.recipe.shell:Recipe',
'signalwrapper= slapos.recipe.signal_wrapper:Recipe', 'signalwrapper= slapos.recipe.signal_wrapper:Recipe',
...@@ -169,7 +167,6 @@ setup(name=name, ...@@ -169,7 +167,6 @@ setup(name=name,
'webchecker = slapos.recipe.web_checker:Recipe', 'webchecker = slapos.recipe.web_checker:Recipe',
'wrapper = slapos.recipe.wrapper:Recipe', 'wrapper = slapos.recipe.wrapper:Recipe',
'zabbixagent = slapos.recipe.zabbixagent:Recipe', 'zabbixagent = slapos.recipe.zabbixagent:Recipe',
'zimbra.kvm = slapos.recipe.zimbra_kvm:Recipe',
'zeo = slapos.recipe.zeo:Recipe', 'zeo = slapos.recipe.zeo:Recipe',
'zero-knowledge.read = slapos.recipe.zero_knowledge:ReadRecipe', 'zero-knowledge.read = slapos.recipe.zero_knowledge:ReadRecipe',
'zero-knowledge.write = slapos.recipe.zero_knowledge:WriteRecipe' 'zero-knowledge.write = slapos.recipe.zero_knowledge:WriteRecipe'
......
kvm
===
kvm: Introduction
-----------------
The erp5.recipe.kvm aims to integrate KVM setups and buildout. This recipe is
able to download one remote image and setup a KVM environment to use it.
This recipe is also capable to reuse images or partitions already present on
disk to create the setup.
Examples
--------
The follow examples lists different kind of configurations.
KVM with Remote and gzipped Image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
[kvm-testing-with-remote-gzip-image]
image = http://URL/public.mdv2010.0_x86_64.qcow2.img.gz
# md5 checks are optional
md5_download = adcff8adcff8adcff8adcff8
md5_image = 1a4e371a4e371a4e371a4e371a4e37
gzip = true
# Use -hda instead -drive arg
# Default is drive (see Options below)
image_type = hda
### Common Configuration below. ###
# VNC is optional
kvm_vnc = <SOME-IP>:<VNC-DISPLAY>
# Graphic is optional
kvm_graphic = std
# Define list of redirections.
kvm_redir =
tcp:13480::80
kvm_net =
user,hostname=publicmandriva
nic,model=ne2k_pci
# This automatically create a redirection for 13456 -> 22
ssh_port = 13456
ssh_key_path = /path/to/mykey.key
KVM with Remote and raw Image
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
[kvm-testing-with-remote-raw-image]
image = http://URL/public.mdv2010.0_x86_64.qcow2.img
md5_download = 1a4e371a4e371a4e371a4e371a4e37
md5_image = 1a4e371a4e371a4e371a4e371a4e37
gzip = false
### The Rest Same configuration as previous ###
KVM with direct local Image file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This does not copy and/or download the image::
[kvm-testing-with-local-image]
file = /home/you/public.mdv2010.0_x86_64.qcow2.img
md5_image = 1a4e371a4e371a4e371a4e371a4e37
### The Rest Same configuration as previous ###
KVM with a linux partition
~~~~~~~~~~~~~~~~~~~~~~~~~~
This does not copy and/or download the image::
[kvm-testing-a-linux-partition]
file = /dev/sdb
### The Rest Same configuration as previous ###
Options
-------
location
When define, it does not use buildout parts directory to allocate the image.
image
URL to a remote image.
file
Use file makes recipe ignore image option. You can define a path to a image
or partion to use.
image_type
You can define how the KVM will use the image with "-hdx" or "-drive". By
default it uses drive and the result is:
"kvm -drive file=IMAGE,if=virtio,cache=none,boot=on ..."
if you use image_type=hda:
"kvm -hda IMAGE ..."
gzip
If true means the image is compressed (gzipped), and the recipe will
uncompress the image before copy it.
md5_download
When defined, this values is used to verify the file downloaded.
md5_image
When defined, this values is used to verify the image generated, don't use it
when a partition is used in file parameter.
kvm_vnc
Define the ip-address:display used by KVM to start the VNC server. If not
defined, no VNC port is created.
kvm_redir
Define port redirections to the buildout.
kvm_graphic
If defined it adds the "-vga value" at the KVM command.
kvm_net
Define the net definitions, each value defines one "-net" in kvm command.
Example:
kvm_net =
user,hostname=publicmandriva
nic,model=ne2k_pci
It generates:
"kvm -net user,hostname=publicmandriva -net nic,model=ne2k_pci ..."
kvm_snapshot
Use "-snapshot" when run a KVM. This not write the changes direct into the
image. Default value is False.
ssh_port
If defined creates a new redirection for port 22 and creates few script to
connect to the instance.
ssh_hostname
By default it uses localhost. You don't need to define this.
ssh_key_path
Path to the ssh key used to connect without password to the image running.
ssh_user
Define the server that will be used to connect to the instance.
kvm_bin_directory
Place where the scripts will be created. By default it uses bin-directory from
buildout.
kvm_run_directory
Place where the pid file will be created, by default it uses var-directory
from buildout.
Generated Commands
------------------
Few scripts are generated to you manage your KVM instance. The scripts names are
created with the followed standard:
KVM-PARTS-NAME-ctl
Commands usage
~~~~~~~~~~~~~~
KVM-PARTS-NAME-ctl (start|stop|status|restart)
This script is used to manage the KVM instance.
KVM-PARTS-NAME-sendfile REMOTEFILE LOCALFILE
Copy the local file to a remote place.
KVM-PARTS-NAME-getfile REMOTEFILE LOCALFILE
Copy the remote file to a local place.
KVM-PARTS-NAME-runscript COMMAND
Run a command into remote KVM computer.
kvm_frontend
=============
kvm_frontend: Introduction
---------------------------
The ``slapos.recipe.kvm_frontend`` aims to provide proxy server to KVM instances.
It allows HTTPS IPv4/IPv6 proxying (with or without domain name), and supports
the WebSocket technology needed for VNC-in-webapplication noVNC.
It works following the master/slave instances system. A master instance is
created, containing all what is needed to run the proxy. Slave instances
are later created, adding one line in the master instance's proxy configuration
that specify the IP/port to proxy to the KVM.
The slave instance (kvm) is then accessible from
http://[masterinstanceIPorhostname]/[randomgeneratednumber]
Instance parameters
-------------------
Incoming master instance parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``port`` - Port of server, optional, defaults to 4443.
* ``domain`` - domain name to use, optional, default to ``host.vifib.net``.
* ``redirect_plain_http`` - if value is one of ``['y', 'yes', '1', 'true']``,
will try to create a simple http server on port 80 redirecting to the proxy. Optional.
Incoming slave instance parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``host`` - KVM instance IP or hostname. Mandatory.
* ``port`` - KVM instance port, Mandatory.
* ``https`` - if value is one of ``['n', 'no', '0', 'false']``, will try to connect to target in plain http. Optional.
Connection parameters
---------------------
Outgoing master connection parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``domain_ipv6_address`` - Proxy IP
* ``site_url`` - Proxy URL
Outgoing slave connection parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``site_url`` - URL of instance
* ``domain_name`` - Domain name of proxy
* ``port`` - Port of proxy
##############################################################################
#
# Copyright (c) 2011 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe, GenericSlapRecipe
import json
import traceback
import zc.buildout
class Recipe(GenericSlapRecipe):
"""
kvm frontend instance configuration.
"""
def _getRewriteRuleContent(self, slave_instance_list):
"""Generate rewrite rules list from slaves list"""
rewrite_rule_list = []
for slave_instance in slave_instance_list:
self.logger.info("Processing slave instance %s..." %
slave_instance['slave_reference'])
# Check for mandatory fields
if slave_instance.get('host', None) is None:
self.logger.warn('No "host" parameter is defined for %s slave'\
'instance. Ignoring it.' % slave_instance['slave_reference'])
continue
if slave_instance.get('port', None) is None:
self.logger.warn('No "host" parameter is defined for %s slave'\
'instance. Ignoring it.' % slave_instance['slave_reference'])
continue
current_slave_dict = dict()
# Get host, and if IPv6 address, remove "[" and "]"
current_slave_dict['host'] = slave_instance['host'].\
replace('[', '').replace(']', '')
current_slave_dict['port'] = slave_instance['port']
# Check if target is https or http
current_slave_dict['https'] = slave_instance.get('https', 'true')
if current_slave_dict['https'] in GenericBaseRecipe.FALSE_VALUES:
current_slave_dict['https'] = 'false'
# Set reference and resource url
# Reference is raw reference from SlapOS Master, resource is
# URL-compatible name
reference = slave_instance.get('slave_reference')
current_slave_dict['reference'] = reference
current_slave_dict['resource'] = reference.replace('-', '')
rewrite_rule_list.append(current_slave_dict)
return rewrite_rule_list
def _getProxyTableContent(self, rewrite_rule_list):
"""Generate proxy table file content from rewrite rules list"""
proxy_table = dict()
for rewrite_rule in rewrite_rule_list:
proxy_table[rewrite_rule['resource']] = {
'port': rewrite_rule['port'],
'host': rewrite_rule['host'],
'https': rewrite_rule['https'],
}
proxy_table_content = json.dumps(proxy_table)
return proxy_table_content
def _install(self):
# Check for mandatory field
if self.options.get('domain', None) is None:
raise zc.buildout.UserError('No domain name specified. Please define '
'the "domain" instance parameter.')
# Generate rewrite rules
rewrite_rule_list = self._getRewriteRuleContent(
json.loads(self.options['slave-instance-list']))
# Create Map
map_content = self._getProxyTableContent(rewrite_rule_list)
map_file = self.createFile(self.options['map-path'], map_content)
# Create configuration
conf = open(self.getTemplateFilename('kvm-proxy.js'), 'r')
conf_file = self.createFile(self.options['conf-path'], conf.read())
conf.close()
# Do we create http dummy server used to redirect to https?
if self.options['http-redirection'] in GenericBaseRecipe.TRUE_VALUES:
http_redirect_server = '1'
else:
http_redirect_server = ''
config = dict(
ipv6=self.options['ipv6'],
ipv4=self.options['ipv4'],
port=self.options['port'],
key=self.options['ssl-key-path'],
certificate=self.options['ssl-cert-path'],
name=self.options['domain'],
shell_path=self.options['shell-path'],
node_path=self.options['node-binary'],
node_env=self.options['node-env'],
conf_path=conf_file,
map_path=map_file,
plain_http=http_redirect_server,
)
runner_path = self.createExecutable(
self.options['wrapper-path'],
self.substituteTemplate(self.getTemplateFilename('nodejs_run.in'),
config))
# Send connection parameters of slave instances
site_url = "https://%s:%s/" % (self.options['domain'], self.options['port'])
for slave in rewrite_rule_list:
try:
self.setConnectionDict(
dict(url="%s%s" % (site_url, slave['resource']),
domainname=self.options['domain'],
port=str(self.options['port']),
resource=slave['resource']),
slave['reference'])
except:
self.logger.fatal("Error while sending slave %s informations: %s",
slave['reference'], traceback.format_exc())
return [map_file, conf_file, runner_path]
/*****************************************************************************
*
* Copyright (c) 2012 Vifib SARL and Contributors. All Rights Reserved.
*
* WARNING: This program as such is intended to be used by professional
* programmers who take the whole responsibility of assessing all potential
* consequences resulting from its eventual inadequacies and bugs
* End users who are looking for a ready-to-use solution with commercial
* guarantees and support are strongly adviced to contract a Free Software
* Service Company
*
* This program is Free Software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*****************************************************************************/
/* Wrapper used to configure the httpproxy node package to proxy
http://myhost/myinstance
to real IP/URL of myinstance
*/
var fs = require('fs'),
util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('http-proxy'),
proxyByUrl = require('proxy-by-url');
var listenInterfacev6 = process.argv[2],
listenInterfacev4 = process.argv[3],
port = process.argv[4],
sslKeyFile = process.argv[5],
sslCertFile = process.argv[6],
proxyTable = process.argv[7],
redirect = process.argv[8] || false,
isRawIPv6;
if (process.argv.length < 7) {
console.error("Too few arguments. Exiting.");
process.exit(1);
}
/**
* Dummy middleware that throws 404 not found. Does not contain websocket
* middleware.
*/
var middlewareNotFound = function(req, res, proxy) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('This URL is not known. Please check your URL or contact your ' +
'SlapOS administrator.');
};
/**
* Create server
*/
var proxyServerv6 = httpProxy.createServer(
// We declare our proxyByUrl middleware
proxyByUrl(proxyTable),
// Then we add your dummy middleware, called when proxyByUrl doesn't find url.
middlewareNotFound,
// And we set HTTPS options for server. HTTP will be forbidden.
{
https: {
key: fs.readFileSync(
sslKeyFile,
'utf8'
),
cert: fs.readFileSync(
sslCertFile,
'utf8'
)
},
source: {
host: listenInterfacev6,
port: port
}}
);
var proxyServerv4 = httpProxy.createServer(
// We declare our proxyByUrl middleware
proxyByUrl(proxyTable),
// Then we add your dummy middleware, called when proxyByUrl doesn't find url.
middlewareNotFound,
// And we set HTTPS options for server. HTTP will be forbidden.
{
https: {
key: fs.readFileSync(
sslKeyFile,
'utf8'
),
cert: fs.readFileSync(
sslCertFile,
'utf8'
)
},
source: {
host: listenInterfacev4,
port: port
}}
);
console.log('HTTPS server starting and trying to listen on ' +
listenInterfacev4 + ':' + port);
// Release the beast.
proxyServerv6.listen(port, listenInterfacev6);
proxyServerv4.listen(port, listenInterfacev4);
// Dummy HTTP server redirecting to HTTPS. Only has sense if we can use port 80
if (redirect === '1') {
console.log('HTTP redirect server starting and trying to listen on ' +
listenInterface + ':' + httpPort);
/*
*try {
* var httpPort = 80;
* http.createServer(function(req, res) {
* var url;
* if (isRawIPv6 === true) {
* url = 'https://[' + listenInterface + ']';
* } else {
* url = 'https://' + listenInterface;
* }
* // If non standard port : need to specify it
* if (port !== 443) {
* url = url + ':' + port;
* }
* // Add last part of URL
* url = url + req.url;
* console.log(url);
* // Anwser "permanently redirected"
* res.statusCode = 301;
* res.setHeader('Location', url);
* res.end();
* }).listen(httpPort, listenInterface);
* } catch (error) {
* console.log('Couldn\'t start plain HTTP redirection server : ' + error)
* }
*/
}
#!%(shell_path)s
# BEWARE: This file is operated by slapos node
# BEWARE: It will be overwritten automatically
export NODE_PATH=%(node_env)s
exec %(node_path)s %(conf_path)s %(ipv6)s %(ipv4)s %(port)s %(key)s %(certificate)s %(map_path)s %(plain_http)s
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import operator
from slapos.recipe.librecipe import GenericSlapRecipe
import zc.buildout
class Recipe(GenericSlapRecipe):
def _install(self):
path_list = []
# Check for mandatory arguments
domain_name = self.options['domain']
if not domain_name:
raise zc.buildout.UserError('No domain name specified. Please define '
'the "domain" instance parameter.')
# XXX: add HTTP support
#https_port_number = self.options['https-port']
#http_port_number = self.options['http-port']
# Parse list of slaves
slave_instance_list = sorted(self.options['slave-instance-list'],
key=operator.itemgetter('slave_reference'))
# Now, we only take first instance and only use this one.
# XXX: TODO real implementation of slaves
zimbra_slave_instance = slave_instance_list[0]
# Generate Nginx configuration
nginx_configuration_dict = {
'listen-local-ipv4': self.options['ipv4'],
'listen-global-ipv6': '[%s]' % self.options['ipv6'],
'domain-name': domain_name,
'smtp-port-number': self.options['smtp-port'],
'error-log': self.options['error-log'],
'access-log': self.options['access-log'],
'htdocs': self.options['htdocs'],
'smtp-upstream-host': zimbra_slave_instance['smtp-upstream-host'],
'smtp-upstream-port': zimbra_slave_instance['smtp-upstream-port'],
}
nginx_configuration_file = self.createFile(
self.options['configuration-file'],
self.substituteTemplate(self.getTemplateFilename('nginx.conf.in'),
nginx_configuration_dict)
)
path_list.append(nginx_configuration_file)
# Generate Nginx wrapper
path_list.append(self.createWrapper(
self.options['wrapper'],
(self.options['nginx-executable'],
'-c', self.options['configuration-file'],
'-p', self.options['home-directory']
)))
# TODO: reload configuration or have feature like apache_map
# Send connection informations about each slave
for slave_instance in slave_instance_list:
reference = slave_instance.get("slave_reference")
self.logger.debug('Sending connection parameters of slave '
'instance: %s' % reference)
try:
connection_dict = {
'listening-ipv6': self.options['ipv6'],
# Arbitrary, as the instance doesn't know its public IP.
'listening-ipv4': self.options['public-ipv4'],
# XXX-TODO
#'site_url': url,
}
self.setConnectionDict(connection_dict, reference)
except:
self.logger.fatal("Error while sending slave %s informations: %s",
reference, traceback.format_exc())
return path_list
daemon off;
worker_processes 1;
#XXX-Cedric: TODO separate the different logs
error_log %(error-log)s info;
events {
worker_connections 1024;
use epoll;
}
http {
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
server {
listen %(listen-local-ipv4)s:8008;
server_name localhost;
access_log %(access-log)s main;
error_log %(error-log)s info;
root %(htdocs)s;
location ~ $ {
add_header Auth-Server %(smtp-upstream-host)s;
add_header Auth-Port %(smtp-upstream-port)s;
return 200;
}
}
}
mail {
server_name %(domain-name)s;
auth_http %(listen-local-ipv4)s:8008;
server {
listen %(listen-local-ipv4)s:%(smtp-port-number)s;
listen %(listen-global-ipv6)s:%(smtp-port-number)s;
protocol smtp;
timeout 5s;
proxy on;
xclient off;
smtp_auth none;
}
}
##############################################################################
#
# Copyright (c) 2011 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe
import sys
class Recipe(GenericBaseRecipe):
"""
kvm instance configuration.
"""
def install(self):
config = dict(
vnc_ip=self.options['vnc-ip'],
vnc_port=self.options['vnc-port'],
boot_disk_path=self.options['boot-disk-path'],
disk_path=self.options['data-disk-path'],
disk_size=self.options['data-disk-size'],
disk_type=self.options['data-disk-type'],
mac_address=self.options['mac-address'],
smp_count=self.options['smp-count'],
ram_size=self.options['ram-size'],
socket_path=self.options['socket-path'],
pid_file_path=self.options['pid-path'],
python_path=sys.executable,
shell_path=self.options['shell-path'],
qemu_path=self.options['qemu-path'],
qemu_img_path=self.options['qemu-img-path'],
vnc_passwd=self.options['passwd']
)
# Runners
runner_path = self.createExecutable(
self.options['runner-path'],
self.substituteTemplate(self.getTemplateFilename('kvm_run.in'), config))
controller_path = self.createExecutable(
self.options['controller-path'],
self.substituteTemplate(self.getTemplateFilename('kvm_controller_run.in'),
config))
return [runner_path, controller_path]
#!%(python_path)s
# BEWARE: This file is operated by slapos node
# BEWARE: It will be overwritten automatically
# Echo client program
import socket
import time
# Connect to KVM qmp socket
so = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
connected = False
while not connected:
try:
so.connect('%(socket_path)s')
except socket.error:
time.sleep(1)
else:
connected = True
data = so.recv(1024)
# Enable qmp
so.send('{ "execute": "qmp_capabilities" }')
data = so.recv(1024)
# Set VNC password
so.send('{ "execute": "change", ' \
'"arguments": { "device": "vnc", "target": "password", ' \
' "arg": "%(vnc_passwd)s" } }')
data = so.recv(1024)
# Finish
so.close()
#!%(python_path)s
# BEWARE: This file is operated by slapos node
# 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
# 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 = ",".join("hostfwd=tcp:%(vnc_ip)s:%%s-:%%s" %% (port, port) for port in [25, 80, 110, 143, 443, 465, 587, 993, 995, 7071])
kvm_argument_list = ['%(qemu_path)s',
'-enable-kvm', '-net', 'nic,macaddr=%(mac_address)s',
'-net', 'user,hostfwd=tcp:%(vnc_ip)s:2222-:22,%%s' %% nat_rules,
'-smp', '%(smp_count)s',
'-m', '%(ram_size)s',
'-drive', 'file=%(disk_path)s,if=%(disk_type)s',
#'-drive', 'file=%(boot_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',
]
os.execv('%(qemu_path)s', kvm_argument_list)
...@@ -20,23 +20,23 @@ md5sum = 9d5f4fc9ed3664140d33dd7c447dbd63 ...@@ -20,23 +20,23 @@ md5sum = 9d5f4fc9ed3664140d33dd7c447dbd63
[template-lte-enb-epc] [template-lte-enb-epc]
_update_hash_filename_ = instance-enb-epc.jinja2.cfg _update_hash_filename_ = instance-enb-epc.jinja2.cfg
md5sum = 8ea71fb85a30e5f57d823ea2f48cb9de md5sum = 2dce6e5aa97ffb331bae8fc95b9f8cf0
[template-lte-enb] [template-lte-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg _update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 78b83842ca2e49dd9f19eab117dc2733 md5sum = 79f3c30ab08efbb22b0cbcbbc45a66cb
[template-lte-gnb-epc] [template-lte-gnb-epc]
_update_hash_filename_ = instance-gnb-epc.jinja2.cfg _update_hash_filename_ = instance-gnb-epc.jinja2.cfg
md5sum = 33a6236150551c5328d27d3b7f07f690 md5sum = c43e4233ec44abdc87aa3068ebb8640b
[template-lte-gnb] [template-lte-gnb]
_update_hash_filename_ = instance-gnb.jinja2.cfg _update_hash_filename_ = instance-gnb.jinja2.cfg
md5sum = 690761b983087465a118a49f1379f0b6 md5sum = 7d25976008c3aa588527db2b461ad72c
[template-lte-epc] [template-lte-epc]
_update_hash_filename_ = instance-epc.jinja2.cfg _update_hash_filename_ = instance-epc.jinja2.cfg
md5sum = 83ad87a675ce1ccf1449e80f3848af80 md5sum = 5e7a832ca1be147948ae562f3b45c88b
[ue_db.jinja2.cfg] [ue_db.jinja2.cfg]
filename = config/ue_db.jinja2.cfg filename = config/ue_db.jinja2.cfg
......
...@@ -70,5 +70,5 @@ lte-epc-request = ${lte-epc-request:connection-monitor-base-url} ...@@ -70,5 +70,5 @@ lte-epc-request = ${lte-epc-request:connection-monitor-base-url}
lte-enb-request = ${lte-enb-request:connection-monitor-base-url} lte-enb-request = ${lte-enb-request:connection-monitor-base-url}
[publish-connection-information] [publish-connection-information]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish.serialised
<= monitor-publish <= monitor-publish
...@@ -119,7 +119,7 @@ output = ${directory:etc}/enb.cfg ...@@ -119,7 +119,7 @@ output = ${directory:etc}/enb.cfg
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish.serialised
[monitor-instance-parameter] [monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %} {% if slapparameter_dict.get("name", None) %}
......
...@@ -146,7 +146,7 @@ password = {{ slapparameter_dict['monitor-password'] | string }} ...@@ -146,7 +146,7 @@ password = {{ slapparameter_dict['monitor-password'] | string }}
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish.serialised
epc-ip = ${slap-configuration:ipv6-random} epc-ip = ${slap-configuration:ipv6-random}
# Add custom promise to check if /dev/sdr0 is busy # Add custom promise to check if /dev/sdr0 is busy
......
...@@ -70,5 +70,5 @@ lte-epc-request = ${lte-epc-request:connection-monitor-base-url} ...@@ -70,5 +70,5 @@ lte-epc-request = ${lte-epc-request:connection-monitor-base-url}
lte-gnb-request = ${lte-gnb-request:connection-monitor-base-url} lte-gnb-request = ${lte-gnb-request:connection-monitor-base-url}
[publish-connection-information] [publish-connection-information]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish.serialised
<= monitor-publish <= monitor-publish
...@@ -120,7 +120,7 @@ output = ${directory:etc}/gnb.cfg ...@@ -120,7 +120,7 @@ output = ${directory:etc}/gnb.cfg
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish.serialised
[monitor-instance-parameter] [monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %} {% if slapparameter_dict.get("name", None) %}
......
zimbra-kvm
==========
Introduction
------------
Zimbra single-machine deployment inside of a virtual machine.
Internals
---------
The following ports are reachable from the outside world:
22 -> 2222
443 -> 4443
Others?
For each port, KVM does a NAT redirection from the VM to the local ipv4. Then, 6tunnel is called to redirect it to the outside world using ipv6.
Deployment
----------
To deploy a new Zimbra service, you just need to request a new instance of it,
then connect the the machine using ssh with root:zimbra credentials, reconfigure
Zimbra to use another domain name, and change root password.
Disk Image content
------------------
Ubuntu 12.04, Zimbra install from official packages, 8.0.3
admin password: Cedric de Saint Martin has it.
bind9: http://wiki.zimbra.com/index.php?title=Split_dns
resolv.conf: http://askubuntu.com/questions/30942/why-does-my-resolv-conf-file-get-regenerated-every-time
Todo
----
* SMTP master/slave design implemented
* Reverse proxy for web works
* Automatically download the proper boot disk image.
* Have two virtual disks: one for system/zimbra, one for data.
* Unify smtp frontend and web frontend
[buildout]
extends =
../../component/6tunnel/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/dcron/buildout.cfg
../../component/gzip/buildout.cfg
../../component/qemu-kvm/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/noVNC/buildout.cfg
../../component/openssl/buildout.cfg
../../stack/slapos.cfg
parts =
template
eggs
[eggs]
recipe = z3c.recipe.scripts
eggs =
${lxml-python:egg}
websockify
slapos.cookbook
slapos.toolbox
[template-kvm]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-kvm.cfg.in
#md5sum = f36565408d3ed82d165727a7ba66bf4f
output = ${buildout:directory}/template-kvm.cfg
mode = 0644
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in
#md5sum = 68788763d23f70f24b9e575871c903a8
output = ${buildout:directory}/template.cfg
mode = 0644
[versions]
# Numpy 1.7.0 doesn't install well
numpy = 1.6.2
[buildout]
extends =
../../component/git/buildout.cfg
common.cfg
parts +=
slapos.cookbook-repository
slapos.toolbox-repository
check-recipe
develop =
${:parts-directory}/slapos.cookbook-repository
${:parts-directory}/slapos.toolbox-repository
[slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone
repository = https://lab.nexedi.com/nexedi/slapos.git
branch = zimbra-kvm
git-executable = ${git:location}/bin/git
[slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone
repository = https://lab.nexedi.com/nexedi/slapos.toolbox.git
branch = master
git-executable = ${git:location}/bin/git
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
#############################
#
# Instanciate kvm
#
#############################
[buildout]
parts =
certificate-authority
request-web-frontend
kvm-promise
tunnel-ipv6-kvm-https
tunnel-ipv6-kvm-ssh
tunnel-ipv6-kvm-zimbra-admin
tunnel-ipv6-kvm-smtp
tunnel-ipv6-kvm-smtp-submission
websockify-sighandler
novnc-promise
publish-kvm-connection-information
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[directory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
bin = $${buildout:directory}/bin
srv = $${buildout:directory}/srv
var = $${buildout:directory}/var
scripts = $${:etc}/run
services = $${:etc}/service
promises = $${:etc}/promise
novnc-conf = $${:etc}/novnc
run = $${:var}/run
ca-dir = $${:srv}/ssl
[create-mac]
recipe = slapos.cookbook:generate.mac
storage-path = $${directory:srv}/mac
[gen-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${directory:srv}/passwd
bytes = 4
[kvm-instance]
# XXX-Cedric: change "KVM" recipe to simple "create wrappers". No need for this
# Specific code
recipe = slapos.cookbook:zimbra.kvm
vnc-ip = $${slap-network-information:local-ipv4}
vnc-port = 5901
boot-disk-path = $${directory:srv}/boot.qcow2
data-disk-path = $${directory:srv}/virtual.qcow2
data-disk-size = $${slap-parameter:disk-size}
data-disk-type = $${slap-parameter:disk-type}
socket-path = $${directory:var}/qmp_socket
pid-path = $${directory:run}/pid_file
smp-count = $${slap-parameter:cpu-count}
ram-size = $${slap-parameter:ram-size}
disk-type = virtio
mac-address = $${create-mac:mac-address}
runner-path = $${directory:services}/kvm
controller-path = $${directory:scripts}/kvm_controller
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}
[kvm-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/vnc_promise
hostname = $${kvm-instance:vnc-ip}
port = $${kvm-instance:vnc-port}
# 6tunnel
# Refers to http://wiki.zimbra.com/wiki/Ports#External_Access
[tunnel-ipv6-kvm-https]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 443
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 443
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-https
[tunnel-ipv6-kvm-zimbra-admin]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 7071
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 7071
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-zimbra_admin
[tunnel-ipv6-kvm-ssh]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 2222
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 2222
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-ssh
[tunnel-ipv6-kvm-smtp]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 25
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 25
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-smtp
[tunnel-ipv6-kvm-smtp-submission]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 587
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 587
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-smtp-submission
[novnc-instance]
recipe = slapos.cookbook:novnc
path = $${ca-novnc:executable}
ip = $${slap-network-information:global-ipv6}
port = 6080
vnc-ip = $${kvm-instance:vnc-ip}
vnc-port = $${kvm-instance:vnc-port}
novnc-location = ${noVNC:location}
websockify-path = ${buildout:directory}/bin/websockify
ssl-key-path = $${ca-novnc:key-file}
ssl-cert-path = $${ca-novnc:cert-file}
[websockify-sighandler]
recipe = slapos.cookbook:signalwrapper
wrapper-path = $${directory:services}/websockify
wrapped-path = $${novnc-instance:path}
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${directory:services}/certificate_authority
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests/
private = $${directory:ca-dir}/private/
certs = $${directory:ca-dir}/certs/
newcerts = $${directory:ca-dir}/newcerts/
crl = $${directory:ca-dir}/crl/
[ca-novnc]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${directory:novnc-conf}/novnc.key
cert-file = $${directory:novnc-conf}/novnc.crt
executable = $${directory:bin}/novnc
wrapper = $${directory:bin}/websockify
[novnc-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/novnc_promise
hostname = $${novnc-instance:ip}
port = $${novnc-instance:port}
[request-slave-frontend]
recipe = slapos.cookbook:requestoptional
software-url = $${slap-parameter:frontend-software-url}
server-url = $${slap-connection:server-url}
key-file = $${slap-connection:key-file}
cert-file = $${slap-connection:cert-file}
computer-id = $${slap-connection:computer-id}
partition-id = $${slap-connection:partition-id}
name = VNC Frontend
software-type = $${slap-parameter:frontend-software-type}
slave = true
config-host = $${novnc-instance:ip}
config-port = $${novnc-instance:port}
return = url resource port domainname
sla-instance_guid = $${slap-parameter:frontend-instance-guid}
[request-web-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Web Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config-url = https://[$${tunnel-ipv6-kvm-https:ipv6}]:$${tunnel-ipv6-kvm-https:ipv6-port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
[request-smtp-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = SMTP Frontend
# XXX We have hardcoded SR URL here.
#software-url = https://lab.nexedi.com/nexedi/slapos/raw/zimbra-kvm/software/reverse-proxy-nginx/development.cfg
software-url = /opt/slapdev/software/reverse-proxy-nginx/development.cfg
slave = true
config-smtp-upstream-host = $${tunnel-ipv6-kvm-smtp:ipv6}
config-smtp-upstream-port = $${tunnel-ipv6-kvm-smtp:port}
return = listening-ipv4
[publish-kvm-connection-information]
recipe = slapos.cookbook:publish
web-backend-url = https://[$${tunnel-ipv6-kvm-https:ipv6}]:$${tunnel-ipv6-kvm-https:ipv6-port}/
web-url = $${request-web-frontend:connection-site_url}
vnc-backend-url = https://[$${novnc-instance:ip}]:$${novnc-instance:port}/vnc_auto.html?host=[$${novnc-instance:ip}]&port=$${novnc-instance:port}&encrypt=1
vnc-password = $${kvm-instance:passwd}
vnc-url = $${request-slave-frontend:connection-url}/vnc_auto.html?host=$${request-slave-frontend:connection-domainname}&port=$${request-slave-frontend:connection-port}&encrypt=1&path=$${request-slave-frontend:connection-resource}
ssh = ssh root@$${tunnel-ipv6-kvm-ssh:ipv6} -p $${tunnel-ipv6-kvm-ssh:ipv6-port}
smtp-listening-ipv4 = $${request-smtp-frontend:connection-listening-ipv4}
[slap-parameter]
# Default values if not specified
frontend-instance-guid =
frontend-software-type = frontend
frontend-software-url = https://lab.nexedi.com/nexedi/slapos/raw/slapos-0.92/software/kvm/software.cfg
ram-size = 4096
disk-size = 50
disk-type = virtio
cpu-count = 4
domain =
[buildout]
parts =
switch-softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch-softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-kvm:output}
[slap-connection]
# part to migrate to new - separated words
computer-id = $${slap_connection:computer_id}
partition-id = $${slap_connection:partition_id}
server-url = $${slap_connection:server_url}
software-release-url = $${slap_connection:software_release_url}
key-file = $${slap_connection:key_file}
cert-file = $${slap_connection:cert_file}
[buildout]
extends = common.cfg
[versions]
numpy = 1.6.2
Jinja2 = 2.6
Werkzeug = 0.8.3
async = 0.6.1
buildout-versions = 1.7
gitdb = 0.5.4
hexagonit.recipe.cmmi = 1.6
lxml = 3.1.0
meld3 = 0.6.10
plone.recipe.command = 1.1
pycrypto = 2.6
slapos.recipe.template = 2.4.2
smmap = 0.8.2
websockify = 0.3.0
z3c.recipe.scripts = 1.0.1
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