Commit ef18cc42 authored by Alain Takoudjou's avatar Alain Takoudjou

Merge branch 'kvm-cluster'

Conflicts:
	software/kvm/common.cfg
	software/wendelin/software.cfg
parents e244ebb0 8d221be7
...@@ -24,10 +24,10 @@ default_disk_image = '%(default-disk-image)s' ...@@ -24,10 +24,10 @@ default_disk_image = '%(default-disk-image)s'
disk_path = '%(disk-path)s' disk_path = '%(disk-path)s'
virtual_hard_drive_url = '%(virtual-hard-drive-url)s'.strip() virtual_hard_drive_url = '%(virtual-hard-drive-url)s'.strip()
virtual_hard_drive_md5sum = '%(virtual-hard-drive-md5sum)s'.strip() virtual_hard_drive_md5sum = '%(virtual-hard-drive-md5sum)s'.strip()
virtual_hard_drive_gzipped = '%(virtual-hard-drive-gzipped)s'.strip() virtual_hard_drive_gzipped = '%(virtual-hard-drive-gzipped)s'.strip().lower()
nat_rules = '%(nat-rules)s'.strip() nat_rules = '%(nat-rules)s'.strip()
use_tap = '%(use-tap)s' use_tap = '%(use-tap)s'.lower()
use_nat = '%(use-nat)s' use_nat = '%(use-nat)s'.lower()
tap_interface = '%(tap-interface)s' tap_interface = '%(tap-interface)s'
listen_ip = '%(ipv4)s' listen_ip = '%(ipv4)s'
mac_address = '%(mac-address)s' mac_address = '%(mac-address)s'
...@@ -119,7 +119,7 @@ if not os.path.exists(disk_path) and virtual_hard_drive_url != '': ...@@ -119,7 +119,7 @@ if not os.path.exists(disk_path) and virtual_hard_drive_url != '':
print('Downloading virtual hard drive...') print('Downloading virtual hard drive...')
try: try:
downloaded_disk = disk_path downloaded_disk = disk_path
if virtual_hard_drive_gzipped == 'True': if virtual_hard_drive_gzipped == 'true':
downloaded_disk = '%%s.gz' %% disk_path downloaded_disk = '%%s.gz' %% disk_path
urllib.urlretrieve(virtual_hard_drive_url, downloaded_disk) urllib.urlretrieve(virtual_hard_drive_url, downloaded_disk)
except: except:
...@@ -162,7 +162,7 @@ for storage in disk_storage_list: ...@@ -162,7 +162,7 @@ for storage in disk_storage_list:
key, val = storage.split(' ') key, val = storage.split(' ')
disk_storage_dict[key.strip()] = val.strip() disk_storage_dict[key.strip()] = val.strip()
if not external_disk_format in ['qcow2', 'raw', 'vdi', 'vmdk', 'cloop']: if not external_disk_format in ['qcow2', 'raw', 'vdi', 'vmdk', 'cloop', 'qed']:
external_disk_format = 'qcow2' external_disk_format = 'qcow2'
map_storage_list, external_disk_number = getMapStorageList(disk_storage_dict, map_storage_list, external_disk_number = getMapStorageList(disk_storage_dict,
...@@ -197,7 +197,7 @@ tap_network_parameter = [] ...@@ -197,7 +197,7 @@ tap_network_parameter = []
nat_network_parameter = [] nat_network_parameter = []
numa_parameter = [] numa_parameter = []
number = -1 number = -1
if use_nat == 'True': if use_nat == 'true':
number += 1 number += 1
rules = 'user,id=lan%%s,' %% number + ','.join('hostfwd=tcp:%%s:%%s-:%%s' %% (listen_ip, rules = 'user,id=lan%%s,' %% number + ','.join('hostfwd=tcp:%%s:%%s-:%%s' %% (listen_ip,
int(port) + 10000, port) for port in nat_rules.split()) int(port) + 10000, port) for port in nat_rules.split())
...@@ -209,7 +209,7 @@ if use_nat == 'True': ...@@ -209,7 +209,7 @@ if use_nat == 'True':
cluster_doc_host, cluster_doc_port) cluster_doc_host, cluster_doc_port)
nat_network_parameter = ['-netdev', rules, nat_network_parameter = ['-netdev', rules,
'-device', 'e1000,netdev=lan%%s,mac=%%s' %% (number, mac_address)] '-device', 'e1000,netdev=lan%%s,mac=%%s' %% (number, mac_address)]
if use_tap == 'True': if use_tap == 'true':
number += 1 number += 1
tap_network_parameter = ['-netdev', tap_network_parameter = ['-netdev',
'tap,id=lan%%s,ifname=%%s,script=no,downscript=no' %% (number, 'tap,id=lan%%s,ifname=%%s,script=no,downscript=no' %% (number,
......
...@@ -33,6 +33,7 @@ class Recipe(GenericBaseRecipe): ...@@ -33,6 +33,7 @@ class Recipe(GenericBaseRecipe):
def __init__(self, buildout, name, options): def __init__(self, buildout, name, options):
base_path = options['base-path'] base_path = options['base-path']
if options.get('use-hash-url', 'True') in ['true', 'True']:
pool = string.letters + string.digits pool = string.letters + string.digits
hash_string = ''.join(random.choice(pool) for i in xrange(64)) hash_string = ''.join(random.choice(pool) for i in xrange(64))
path = os.path.join(base_path, hash_string) path = os.path.join(base_path, hash_string)
...@@ -47,6 +48,9 @@ class Recipe(GenericBaseRecipe): ...@@ -47,6 +48,9 @@ class Recipe(GenericBaseRecipe):
options['root-dir'] = path options['root-dir'] = path
options['path'] = hash_string options['path'] = hash_string
else:
options['root-dir'] = base_path
options['path'] = ''
return GenericBaseRecipe.__init__(self, buildout, name, options) return GenericBaseRecipe.__init__(self, buildout, name, options)
...@@ -59,8 +63,9 @@ class Recipe(GenericBaseRecipe): ...@@ -59,8 +63,9 @@ class Recipe(GenericBaseRecipe):
'port': int(self.options['port']), 'port': int(self.options['port']),
'cwd': self.options['base-path'], 'cwd': self.options['base-path'],
'log-file': self.options['log-file'], 'log-file': self.options['log-file'],
'cert-file': self.options['cert-file'], 'cert-file': self.options.get('cert-file', ''),
'key-file': self.options['key-file'] 'key-file': self.options.get('key-file', ''),
'root-dir': self.options['root-dir']
} }
server = self.createPythonScript( server = self.createPythonScript(
......
# -*- coding: utf-8 -*-
from SimpleHTTPServer import SimpleHTTPRequestHandler from SimpleHTTPServer import SimpleHTTPRequestHandler
from BaseHTTPServer import HTTPServer from BaseHTTPServer import HTTPServer
import ssl import ssl
...@@ -5,23 +6,71 @@ import os ...@@ -5,23 +6,71 @@ import os
import logging import logging
from netaddr import valid_ipv4, valid_ipv6 from netaddr import valid_ipv4, valid_ipv6
import socket import socket
import cgi, errno
class ServerHandler(SimpleHTTPRequestHandler): class ServerHandler(SimpleHTTPRequestHandler):
def respond(self, code=200, type='text/plain'): document_path = ''
restrict_root_folder = True
def respond(self, code=200, type='text/html'):
self.send_response(code) self.send_response(code)
self.send_header("Content-type", type) self.send_header("Content-type", type)
self.end_headers() self.end_headers()
def do_GET(self): def restrictedRootAccess(self):
logging.info('%s - GET: %s \n%s' % (self.client_address[0], self.path, self.headers)) if self.restrict_root_folder and self.path and self.path == '/':
if not self.path or self.path == '/':
# no access to root path # no access to root path
self.respond(403) self.respond(403)
self.wfile.write("Forbidden") self.wfile.write("Forbidden")
return True
return False
def do_GET(self):
logging.info('%s - GET: %s \n%s' % (self.client_address[0], self.path, self.headers))
if self.restrictedRootAccess():
return return
SimpleHTTPRequestHandler.do_GET(self) SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
logging.info('%s - POST: %s \n%s' % (self.client_address[0], self.path, self.headers))
if self.restrictedRootAccess():
return
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type']}
)
name = form['path'].value
content = form['content'].value
method = 'a'
if form.has_key('clear') and form['clear'].value == '1':
method = 'w'
self.writeFile(name, content, method)
self.respond(200, type=self.headers['Content-Type'])
self.wfile.write("Content written to %s" % name)
def writeFile(self, filename, content, method='a'):
file_path = os.path.join(self.document_path, filename)
try:
os.makedirs(os.path.dirname(file_path))
except OSError as exception:
if exception.errno != errno.EEXIST:
logging.error('Failed to create file in %s. The error is \n%s' % (
file_path, str(exception)))
logging.info('Writing recieved content to file %s' % file_path)
try:
with open(file_path, method) as myfile:
myfile.write(content.decode('utf-8'))
logging.info('Done.')
except IOError as e:
logging.error('Something happened while processing \'writeFile\'. The message is %s' %
str(e))
class HTTPServerV6(HTTPServer): class HTTPServerV6(HTTPServer):
address_family = socket.AF_INET6 address_family = socket.AF_INET6
...@@ -38,6 +87,8 @@ def run(args): ...@@ -38,6 +87,8 @@ def run(args):
os.chdir(args['cwd']) os.chdir(args['cwd'])
Handler = ServerHandler Handler = ServerHandler
Handler.document_path = args['root-dir']
Handler.restrict_root_folder = (args['root-dir'] != args['cwd'])
if valid_ipv6(host): if valid_ipv6(host):
server = HTTPServerV6 server = HTTPServerV6
...@@ -45,11 +96,14 @@ def run(args): ...@@ -45,11 +96,14 @@ def run(args):
server = HTTPServer server = HTTPServer
httpd = server((host, port), Handler) httpd = server((host, port), Handler)
if args.has_key('cert-file') and args.has_key('key-file'): scheme = 'http'
if args.has_key('cert-file') and args.has_key('key-file') and \
os.path.exists(args['cert-file']) and os.path.exists(args['key-file']):
scheme = 'https'
httpd.socket = ssl.wrap_socket (httpd.socket, httpd.socket = ssl.wrap_socket (httpd.socket,
server_side=True, server_side=True,
certfile=args['cert-file'], certfile=args['cert-file'],
keyfile=args['key-file']) keyfile=args['key-file'])
logging.info("Starting simple http server at https://%s:%s" % (host, port)) logging.info("Starting simple http server at %s://%s:%s" % (scheme, host, port))
httpd.serve_forever() httpd.serve_forever()
...@@ -87,7 +87,7 @@ command = ...@@ -87,7 +87,7 @@ command =
[template] [template]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in url = ${:_profile_base_location_}/instance.cfg.in
md5sum = cf67212d3155767d0d0d8a6d75d2d8ad md5sum = 3bca2c959d19881270c64f94ad1ebba8
output = ${buildout:directory}/template.cfg output = ${buildout:directory}/template.cfg
mode = 0644 mode = 0644
...@@ -95,7 +95,7 @@ mode = 0644 ...@@ -95,7 +95,7 @@ mode = 0644
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/instance-kvm.cfg.jinja2 url = ${:_profile_base_location_}/instance-kvm.cfg.jinja2
mode = 644 mode = 644
md5sum = 3e3354844b2052609e3c49eca03b607e md5sum = ea1e8f4a7c1878beec83267fd40728c2
download-only = true download-only = true
on-update = true on-update = true
...@@ -103,7 +103,7 @@ on-update = true ...@@ -103,7 +103,7 @@ on-update = true
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/instance-kvm-cluster.cfg.jinja2.in url = ${:_profile_base_location_}/instance-kvm-cluster.cfg.jinja2.in
mode = 644 mode = 644
md5sum = 1f7dc7b7f2740cf416927b144e93ccb1 md5sum = 5a864099760e3a37fa4604044d708657
download-only = true download-only = true
on-update = true on-update = true
...@@ -173,7 +173,7 @@ recipe = hexagonit.recipe.download ...@@ -173,7 +173,7 @@ recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/template/apache.conf.in url = ${:_profile_base_location_}/template/apache.conf.in
mode = 644 mode = 644
filename = apache.conf.in filename = apache.conf.in
md5sum = 91f05377aff35ffbac7f2687e90b5dcc md5sum = e9c9fd88d71e9dc7416149af5bcfb951
download-only = true download-only = true
on-update = true on-update = true
...@@ -182,7 +182,7 @@ recipe = hexagonit.recipe.download ...@@ -182,7 +182,7 @@ recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/template/template-content.in url = ${:_profile_base_location_}/template/template-content.in
mode = 644 mode = 644
filename = template-content.in filename = template-content.in
md5sum = 47d492dafe5cb314bdc49bf013d21ead md5sum = 822737e483864bf255ad1259237bef2a
download-only = true download-only = true
on-update = true on-update = true
...@@ -191,9 +191,10 @@ recipe = slapos.recipe.template:jinja2 ...@@ -191,9 +191,10 @@ recipe = slapos.recipe.template:jinja2
filename = template-httpd.cfg filename = template-httpd.cfg
template = ${:_profile_base_location_}/instance-kvm-http.cfg.in template = ${:_profile_base_location_}/instance-kvm-http.cfg.in
rendered = ${buildout:parts-directory}/${:_buildout_section_name_}/instance-kvm-http.cfg rendered = ${buildout:parts-directory}/${:_buildout_section_name_}/instance-kvm-http.cfg
md5sum = 84b96dfc78e8d2611bf7210b8b6bb9c5 md5sum = fc8b3259942d6dedbc01065358a00d71
context = context =
key apache_location apache:location key apache_location apache:location
raw openssl_executable_location ${openssl:location}/bin/openssl
raw template_apache_conf ${template-apache-conf:location}/${template-apache-conf:filename} raw template_apache_conf ${template-apache-conf:location}/${template-apache-conf:filename}
...@@ -122,11 +122,16 @@ ...@@ -122,11 +122,16 @@
}, },
"type": "object" "type": "object"
}, },
"authorized-key": { "authorized-keys": {
"title": "Public keys for virtual machines.", "title": "Public keys for virtual machines.",
"description": "Set the list of public keys to add in your virtual machine. The public key file will be available in the VM via url http://10.0.2.100/authorized_keys if you keep the NAT interface enabled", "description": "Set the list of public keys to add in your virtual machine. The public key file will be available in the VM via url http://10.0.2.100/authorized_keys if you keep the NAT interface enabled",
"type": "array" "type": "array"
}, },
"cluster-data": {
"title": "Text content to share with virtual machines.",
"description": "Text content which will be written in a file data of cluster http server. All VM will be able to download that file via the static URL of cluster HTTP server: https://10.0.2.101/FOLDER_HASH/data.",
"type": "string"
},
"kvm-partition-dict": { "kvm-partition-dict": {
"title": "kvm instances definition", "title": "kvm instances definition",
"description": "kvm instances definition", "description": "kvm instances definition",
...@@ -261,7 +266,7 @@ ...@@ -261,7 +266,7 @@
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop"] "enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"]
}, },
"use-tap": { "use-tap": {
"title": "Use QEMU TAP network interface", "title": "Use QEMU TAP network interface",
...@@ -284,6 +289,11 @@ ...@@ -284,6 +289,11 @@
80, 80,
443 443
] ]
},
"data-to-vm": {
"title": "Text content to send to this virtual machine.",
"description": "Text content which will be written in a file 'data' of http server of this virtual machine instance. The file will be available via URL: http://10.0.2.100/data in the VM.",
"type": "string"
} }
}, },
"type": "object" "type": "object"
......
...@@ -22,7 +22,7 @@ config-use-ipv6 = {{ dumps(slapparameter_dict.get('use-ipv6', False)) }} ...@@ -22,7 +22,7 @@ config-use-ipv6 = {{ dumps(slapparameter_dict.get('use-ipv6', False)) }}
# Request kvm instances # Request kvm instances
{% for instance_name, kvm_parameter_dict in slapparameter_dict.get('kvm-partition-dict', {'kvm-default': {}}).items() -%} {% for instance_name, kvm_parameter_dict in slapparameter_dict.get('kvm-partition-dict', {'kvm-default': {}}).items() -%}
{% set section = 'request-' ~ instance_name -%} {% set section = 'request-' ~ instance_name -%}
{% set use_nat = kvm_parameter_dict.get('use-nat', True) -%} {% set use_nat = kvm_parameter_dict.get('use-nat', 'True') -%}
[{{ section }}] [{{ section }}]
<= request-common <= request-common
software-type = kvm software-type = kvm
...@@ -34,8 +34,8 @@ config-frontend-software-type = {{ dumps(frontend_dict.get('software-type', 'fro ...@@ -34,8 +34,8 @@ config-frontend-software-type = {{ dumps(frontend_dict.get('software-type', 'fro
config-frontend-software-url = {{ dumps(frontend_dict.get('software-url', 'http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg')) }} config-frontend-software-url = {{ dumps(frontend_dict.get('software-url', 'http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg')) }}
config-frontend-instance-guid = {{ dumps(frontend_dict.get('instance-guid', '')) }} config-frontend-instance-guid = {{ dumps(frontend_dict.get('instance-guid', '')) }}
config-name = {{ instance_name }} config-name = {{ instance_name }}
{% if slapparameter_dict.get('authorized-key', []) -%} {% if slapparameter_dict.get('authorized-keys', []) -%}
config-authorized-key = {{ slapparameter_dict.get('authorized-key') | join('##') }} config-authorized-key = {{ dumps(slapparameter_dict.get('authorized-keys') | join('\n')) }}
{% endif -%} {% endif -%}
config-nbd-port = {{ dumps(kvm_parameter_dict.get('nbd-port', 1024)) }} config-nbd-port = {{ dumps(kvm_parameter_dict.get('nbd-port', 1024)) }}
config-nbd-host = {{ dumps(kvm_parameter_dict.get('nbd-host', '')) }} config-nbd-host = {{ dumps(kvm_parameter_dict.get('nbd-host', '')) }}
...@@ -61,21 +61,24 @@ config-external-disk-size = {{ dumps(kvm_parameter_dict.get('external-disk-size' ...@@ -61,21 +61,24 @@ config-external-disk-size = {{ dumps(kvm_parameter_dict.get('external-disk-size'
config-external-disk-format = {{ dumps(kvm_parameter_dict.get('external-disk-format', 'qcow2')) }} config-external-disk-format = {{ dumps(kvm_parameter_dict.get('external-disk-format', 'qcow2')) }}
config-enable-http-server = {{ dumps(kvm_parameter_dict.get('enable-http-server', True)) }} config-enable-http-server = {{ dumps(kvm_parameter_dict.get('enable-http-server', True)) }}
config-httpd-port = {{ dumps(kvm_parameter_dict.get('httpd-port', 8081)) }} config-httpd-port = {{ dumps(kvm_parameter_dict.get('httpd-port', 8081)) }}
{% if kvm_parameter_dict.get('data-to-vm', '') -%}
config-data-to-vm = {{ dumps(kvm_parameter_dict.get('data-to-vm', '')) }}
{% endif -%}
# Enable simple http server on ipv6 so all VMs will access it # Enable simple http server on ipv6 so all VMs will access it
config-document-host = ${http-server:host} config-document-host = ${apache-conf:ip}
config-document-port = ${http-server:port} config-document-port = ${apache-conf:port}
config-document-path = ${http-server:path} config-document-path = ${hash-code:passwd}
return = return =
backend-url backend-url
url url
{% if use_nat -%} {% if str(use_nat).lower() -%}
{% for port in nat_rules_list -%} {% for port in nat_rules_list -%}
{{ ' ' }}nat-rule-url-{{ port }} {{ ' ' }}nat-rule-url-{{ port }}
{% endfor -%} {% endfor -%}
{% endif -%} {% endif -%}
{% if kvm_parameter_dict.get('use-tap', True) -%} {% if str(kvm_parameter_dict.get('use-tap', 'True')).lower() == 'true' -%}
{{ ' ' }}tap-ipv4 {{ ' ' }}tap-ipv4
{% do publish_dict.__setitem__('lan-' ~ instance_name, '${' ~ section ~ ':connection-tap-ipv4}') -%} {% do publish_dict.__setitem__('lan-' ~ instance_name, '${' ~ section ~ ':connection-tap-ipv4}') -%}
...@@ -83,7 +86,7 @@ return = ...@@ -83,7 +86,7 @@ return =
{% endif -%} {% endif -%}
{% do publish_dict.__setitem__(instance_name ~ '-backend-url', '${' ~ section ~ ':connection-backend-url}') -%} {% do publish_dict.__setitem__(instance_name ~ '-backend-url', '${' ~ section ~ ':connection-backend-url}') -%}
{% do publish_dict.__setitem__(instance_name ~ '-url', '${' ~ section ~ ':connection-url}') -%} {% do publish_dict.__setitem__(instance_name ~ '-url', '${' ~ section ~ ':connection-url}') -%}
{% do kvm_instance_dict.__setitem__(instance_name, (kvm_parameter_dict.get('use-nat', True), nat_rules_list)) -%} {% do kvm_instance_dict.__setitem__(instance_name, (use_nat, nat_rules_list)) -%}
{% endfor %} {% endfor %}
...@@ -132,6 +135,11 @@ sla-instance_guid = {{ slave_frontend_iguid }} ...@@ -132,6 +135,11 @@ sla-instance_guid = {{ slave_frontend_iguid }}
{% endfor %} {% endfor %}
# Enable simple http server on ipv6 so all VMs will access it # Enable simple http server on ipv6 so all VMs will access it
[hash-code]
recipe = slapos.cookbook:generate.password
storage-path = ${directory:etc}/code
bytes = 24
[directory] [directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc etc = ${buildout:directory}/etc
...@@ -141,35 +149,47 @@ var = ${buildout:directory}/var ...@@ -141,35 +149,47 @@ var = ${buildout:directory}/var
log = ${:var}/log log = ${:var}/log
scripts = ${:etc}/run scripts = ${:etc}/run
services = ${:etc}/service services = ${:etc}/service
document = ${:srv}/document webroot = ${:srv}/document
promises = ${:etc}/promise
ssl = ${:etc}/ssl ssl = ${:etc}/ssl
[http-ssl] [directory-doc]
recipe = plone.recipe.command recipe = slapos.cookbook:mkdirectory
command = "{{ openssl_executable_location }}" req -newkey rsa -batch -new -x509 -days 3650 -nodes -keyout "${:key}" -out "${:cert}" document = ${directory:webroot}/${hash-code:passwd}
key = ${directory:ssl}/key
cert = ${directory:ssl}/cert [apache-conf]
update-command = denied-root-access = true
stop-on-error = true root = ${directory:webroot}/
index = ${directory:webroot}/${hash-code:passwd}
[http-server]
recipe = slapos.cookbook:simplehttpserver
host = {{ ipv6 }}
port = 9002 port = 9002
base-path = ${directory:document}
wrapper = ${directory:services}/simple-http-server
log-file = ${directory:log}/http.log
cert-file = ${http-ssl:cert}
key-file = ${http-ssl:key}
{% if len(kvm_hostname_list) -%}
{% do part_list.append('write-vm-hostname') -%}
[write-vm-hostname] [write-vm-hostname]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
template = {{ template_content }} template = {{ template_content }}
filename = hosts filename = hosts
rendered = ${http-server:root-dir}/${:filename} rendered = ${directory:webroot}/${hash-code:passwd}/${:filename}
context = context =
raw content_list {{ kvm_hostname_list | join('#') }} raw content_list {{ kvm_hostname_list | join('#') }}
raw sep # raw sep #
{% endif -%}
{% macro writefile(section_name, file_path, content, mode='') -%}
{% do part_list.append(section_name) -%}
{% set data_list = content.split('\n') -%}
[{{ section_name }}]
recipe = collective.recipe.template
input = inline:
{{ data_list | join('\n ') }}
output = {{ file_path }}
mode = {{ mode }}
{% endmacro -%}
# write cluster-data into file public/data
{% if slapparameter_dict.get('cluster-data', '') -%}
{{ writefile('cluster-data-content', '${http-server:root-dir}/data', slapparameter_dict.get('cluster-data', ''), '700') }}
{% endif -%}
[publish] [publish]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
...@@ -177,10 +197,14 @@ recipe = slapos.cookbook:publish ...@@ -177,10 +197,14 @@ recipe = slapos.cookbook:publish
{{ name }} = {{ value }} {{ name }} = {{ value }}
{% endfor %} {% endfor %}
[buildout] [buildout]
extends =
{{ template_httpd_cfg }}
parts = parts =
http-server httpd
write-vm-hostname httpd-promise
publish publish
directory-doc
# Complete parts with sections # Complete parts with sections
{{ part_list | join('\n ') }} {{ part_list | join('\n ') }}
......
...@@ -14,33 +14,48 @@ log = ${:var}/log ...@@ -14,33 +14,48 @@ log = ${:var}/log
services = ${:etc}/service services = ${:etc}/service
promises = ${:etc}/promise promises = ${:etc}/promise
run = ${:var}/run run = ${:var}/run
document = ${:srv}/document
ssl = ${:etc}/ssl
[apache-conf] [apache-conf]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
template = {{ template_apache_conf }} template = {{ template_apache_conf }}
rendered = ${directory:etc}/apache.conf rendered = ${directory:etc}/apache.conf
#ipv6 = ${slap-network-information:global-ipv6} ip = ${slap-network-information:global-ipv6}
ipv4 = ${slap-network-information:local-ipv4} #ipv4 = ${slap-network-information:local-ipv4}
port = ${slap-parameter:httpd-port} port = ${slap-parameter:httpd-port}
error-log = ${directory:log}/apache-error.log error-log = ${directory:log}/apache-error.log
access-log = ${directory:log}/apache-access.log access-log = ${directory:log}/apache-access.log
pid-file = ${directory:run}/apache.pid pid-file = ${directory:run}/apache.pid
index = ${directory:public} index = ${directory:public}
root = {:index}
denied-root-access = false
context = context =
key port :port key port :port
key ip :ipv4 key ip :ip
key access_log :access-log key access_log :access-log
key error_log :error-log key error_log :error-log
key pid_file :pid-file key pid_file :pid-file
key index_folder :index key index_folder :index
key cert httpd-ssl:cert
key key httpd-ssl:key
key document_root :root
[httpd] [httpd]
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:services}/httpd wrapper-path = ${directory:services}/httpd
command-line = "{{ apache_location }}/bin/httpd" -f "${apache-conf:rendered}" -DFOREGROUND command-line = "{{ apache_location }}/bin/httpd" -f "${apache-conf:rendered}" -DFOREGROUND
[httpd-ssl]
recipe = plone.recipe.command
command = "{{ openssl_executable_location }}" req -newkey rsa -batch -new -x509 -days 3650 -nodes -keyout "${:key}" -out "${:cert}"
key = ${directory:ssl}/key
cert = ${directory:ssl}/cert
update-command =
stop-on-error = true
[httpd-promise] [httpd-promise]
recipe = slapos.cookbook:check_port_listening recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/apache-httpd path = ${directory:promises}/apache-httpd
hostname = ${apache-conf:ipv4} hostname = ${apache-conf:ip}
port = ${apache-conf:port} port = ${apache-conf:port}
\ No newline at end of file
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop"] "enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"]
}, },
"use-tap": { "use-tap": {
...@@ -135,9 +135,28 @@ ...@@ -135,9 +135,28 @@
"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.", "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" "type": "string"
}, },
"enable-http-server": {
"title": "Enable local http server",
"description": "Set if local http server which serve files to the vm should be deployed. If set to true, get file into the vm with URL: http://10.0.2.100/FILE.",
"type": "boolean",
"default": false
},
"httpd-port": {
"title": "Local http server port",
"description": "Port of the local http server used to share files.",
"type": "integer",
"default": 8081,
"minimum": 1,
"maximum": 65535
},
"authorized-key": { "authorized-key": {
"title": "Public keys to get from all virtual machines.", "title": "Public keys to get from all virtual machines.",
"description": "Set the public keys to add in your virtual machine. Keys are separated with '##'. The public key file will be available in the VM via url http://10.0.2.100/authorized_keys if you keep the NAT interface enabled", "description": "Set the public keys to add in your virtual machine. The public key file will be available in the VM via url http://10.0.2.100/authorized_keys if you keep the NAT interface enabled",
"type": "string"
},
"data-to-vm": {
"title": "Text content to send to this virtual machine.",
"description": "Text content which will be written in a file 'data' of http server of this virtual machine instance. The file will be available via URL: http://10.0.2.100/data in the VM.",
"type": "string" "type": "string"
}, },
"frontend-instance-guid": { "frontend-instance-guid": {
......
{% set enable_http = slapparameter_dict.get('enable-http-server', 'False') -%} {% set enable_http = slapparameter_dict.get('enable-http-server', 'False').lower() -%}
{% set use_tap = slapparameter_dict.get('use-tap', 'False').lower() -%}
{% set use_nat = slapparameter_dict.get('use-nat', 'True').lower() -%}
############################# #############################
# #
# Instanciate kvm # Instanciate kvm
...@@ -19,13 +21,19 @@ parts = ...@@ -19,13 +21,19 @@ parts =
{% if slapparameter_dict.get('document-host', '') %} {% if slapparameter_dict.get('document-host', '') %}
cluster-url-path cluster-url-path
{% endif -%} {% endif -%}
{% if slapparameter_dict.get('enable-http-server', 'False') == 'True' %} {% if enable_http == 'true' %}
httpd httpd
httpd-promise httpd-promise
publish-host-config publish-host-config
{% if slapparameter_dict.get('data-to-vm', '') %}
vm-data-content
{% endif -%}
{% if slapparameter_dict.get('authorized-key', '') %}
get-authorized-key
{% endif -%}
extends = # extends =
{{ template_httpd_cfg }} # {{ template_httpd_cfg }}
{% endif -%} {% endif -%}
eggs-directory = {{ eggs_directory }} eggs-directory = {{ eggs_directory }}
...@@ -127,7 +135,7 @@ external-disk-number = ${slap-parameter:external-disk-number} ...@@ -127,7 +135,7 @@ external-disk-number = ${slap-parameter:external-disk-number}
external-disk-size = ${slap-parameter:external-disk-size} external-disk-size = ${slap-parameter:external-disk-size}
external-disk-format = ${slap-parameter:external-disk-format} external-disk-format = ${slap-parameter:external-disk-format}
{% if slapparameter_dict.get('enable-http-server', 'False') == 'True' or ( slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') ) -%} {% if enable_http == 'true' or ( use_tap == 'true' and tap_network_dict.has_key('ipv4') ) -%}
httpd-port = ${slap-parameter:httpd-port} httpd-port = ${slap-parameter:httpd-port}
{% else -%} {% else -%}
httpd-port = 0 httpd-port = 0
...@@ -264,6 +272,23 @@ dash_path = {{ dash_executable_location }} ...@@ -264,6 +272,23 @@ dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }} curl_path = {{ curl_executable_location }}
{% if enable_http == 'true' %}
[httpd]
recipe = slapos.cookbook:simplehttpserver
host = ${slap-network-information:local-ipv4}
port = ${slap-parameter:httpd-port}
base-path = ${directory:public}
wrapper = ${directory:services}/http-server
log-file = ${directory:log}/httpd.log
use-hash-url = false
[httpd-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/httpd
hostname = ${httpd:host}
port = ${httpd:port}
{% endif %}
[publish-connection-information] [publish-connection-information]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
ipv6 = ${slap-network-information:global-ipv6} ipv6 = ${slap-network-information:global-ipv6}
...@@ -272,7 +297,7 @@ url = ${request-slave-frontend:connection-url}/vnc_auto.html?host=${request-slav ...@@ -272,7 +297,7 @@ url = ${request-slave-frontend:connection-url}/vnc_auto.html?host=${request-slav
{% set disk_number = len(storage_dict) -%} {% set disk_number = len(storage_dict) -%}
maximum-extra-disk-amount = {{ disk_number }} maximum-extra-disk-amount = {{ disk_number }}
{% set iface = 'eth0' -%} {% set iface = 'eth0' -%}
{% if slapparameter_dict.get('use-nat', 'True') == 'True' -%} {% if use_nat == 'true' -%}
{% set iface = 'eth1' -%} {% set iface = 'eth1' -%}
# Publish NAT port mapping status # Publish NAT port mapping status
# XXX: hardcoded value from [slap-parameter] # XXX: hardcoded value from [slap-parameter]
...@@ -285,27 +310,27 @@ nat-rule-url-{{port}} = [${slap-network-information:global-ipv6}]:{{external_por ...@@ -285,27 +310,27 @@ nat-rule-url-{{port}} = [${slap-network-information:global-ipv6}]:{{external_por
{% endif -%} {% endif -%}
{% endfor -%} {% endfor -%}
{% endif -%} {% endif -%}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' -%} {% if use_tap == 'true' -%}
tap-ipv4 = ${slap-network-information:tap-ipv4} tap-ipv4 = ${slap-network-information:tap-ipv4}
{% endif -%} {% endif -%}
{% set kvm_http = 'http://${slap-network-information:local-ipv4}:' ~ slapparameter_dict.get('httpd-port', 8081) -%} {% set kvm_http = 'http://${slap-network-information:local-ipv4}:' ~ slapparameter_dict.get('httpd-port', 8081) -%}
{% if enable_http == 'True' %} {% if enable_http == 'True' %}
{% if slapparameter_dict.get('use-nat', 'True') == 'True' -%} {% if use_nat == 'true' -%}
{% set kvm_http = 'http://10.0.2.100' -%} {% set kvm_http = 'http://10.0.2.100' -%}
{% endif %} {% endif %}
{% if slapparameter_dict.get('authorized-key', '') -%} {% if slapparameter_dict.get('authorized-key', '') -%}
7_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/${get-authorized-key:filename} 7_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/authorized_keys
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') -%} {% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%}
1_info = Use these configurations below to configure interface {{ iface }} in your VM. 1_info = Use these configurations below to configure interface {{ iface }} in your VM.
2_info = ${network-config:ifconfig} 2_info = ${network-config:ifconfig}
3_info = ${network-config:route-iface} 3_info = ${network-config:route-iface}
4_info = ${network-config:route-network} 4_info = ${network-config:route-network}
5_info = ${network-config:route-default} 5_info = ${network-config:route-default}
{% if enable_http == 'True' %} {% if enable_http == 'true' %}
6_info = Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh - 6_info = Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh -
{% endif %} {% endif %}
...@@ -332,20 +357,26 @@ command = ...@@ -332,20 +357,26 @@ command =
update-command = ${:command} update-command = ${:command}
{% endif -%} {% endif -%}
[get-authorized-key] {% macro writefile(section_name, file_path, content, mode='') -%}
recipe = slapos.recipe.template:jinja2 {% set data_list = content.split('\n') -%}
template = {{ template_content }} [{{ section_name }}]
filename = authorized_keys recipe = collective.recipe.template
rendered = ${directory:public}/${:filename} input = inline:
public-key = {{ slapparameter_dict.get('authorized-key', '') }} {{ data_list | join('\n ') }}
context = output = {{ file_path }}
key content_list :public-key mode = {{ mode }}
raw sep ## {% endmacro -%}
# write vm-data into file public/data
{{ writefile('vm-data-content', '${directory:public}/data', slapparameter_dict.get('data-to-vm', ''), '700') }}
# write public key for vms to public/authorized_keys
{{ writefile('get-authorized-key', '${directory:public}/authorized_keys', slapparameter_dict.get('authorized-key', ''), '700') }}
[publish-host-config] [publish-host-config]
recipe = plone.recipe.command recipe = plone.recipe.command
name = {{ slapparameter_dict.get('name', 'localhost') }} name = {{ slapparameter_dict.get('name', 'localhost') }}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') -%} {% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%}
local-ipv4 = ${slap-network-information:tap-ipv4} local-ipv4 = ${slap-network-information:tap-ipv4}
{% else -%} {% else -%}
local-ipv4 = 127.0.0.1 local-ipv4 = 127.0.0.1
...@@ -419,3 +450,6 @@ enable-http-server = False ...@@ -419,3 +450,6 @@ enable-http-server = False
httpd-port = 8081 httpd-port = 8081
# for auto config, the public key file will be available in the VM via url http://10.0.2.100/authorized_key if use-nat = True # for auto config, the public key file will be available in the VM via url http://10.0.2.100/authorized_key if use-nat = True
authorized-key = authorized-key =
# send some content which will be accessible to the vm through static url: http://10.0.2.100/data
data-to-vm =
...@@ -67,6 +67,7 @@ filename = template-kvm-cluster.cfg ...@@ -67,6 +67,7 @@ filename = template-kvm-cluster.cfg
extra-context = extra-context =
section parameter_dict dynamic-template-kvm-cluster-parameters section parameter_dict dynamic-template-kvm-cluster-parameters
raw template_content ${template-content:location}/${template-content:filename} raw template_content ${template-content:location}/${template-content:filename}
raw template_httpd_cfg ${template-httpd:rendered}
[dynamic-template-kvm] [dynamic-template-kvm]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
...@@ -27,6 +27,17 @@ ServerTokens Prod ...@@ -27,6 +27,17 @@ ServerTokens Prod
ServerSignature Off ServerSignature Off
TraceEnable Off TraceEnable Off
SSLEngine on
SSLCertificateFile {{ cert }}
SSLCertificateKeyFile {{ key }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLProtocol All -SSLv2
SSLProxyEngine On
DocumentRoot {{ document_root }}
ErrorLog "{{ error_log }}" ErrorLog "{{ error_log }}"
# Default apache log format with request time in microsecond at the end # Default apache log format with request time in microsecond at the end
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined
...@@ -40,10 +51,11 @@ SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded ...@@ -40,10 +51,11 @@ SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
Require all denied Require all denied
</Directory> </Directory>
DocumentRoot {{ index_folder }}
<Directory {{ index_folder }}> <Directory {{ index_folder }}>
Options Indexes FollowSymLinks Options Indexes FollowSymLinks
Require ip {{ ip }} # Require ip {{ ip }}
# Require env forwarded '{{ ip }}' # Require env forwarded '{{ ip }}'
Require all denied # Require all denied
AllowOverride None
Require all granted
</Directory> </Directory>
\ No newline at end of file
{% if not sep -%}
{{ content_list }}
{% else -%}
{% for content in content_list.split(sep) -%} {% for content in content_list.split(sep) -%}
{{ content }} {{ content }}
{% endfor -%} {% endfor -%}
{% endif -%}
\ No newline at end of file
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