{% 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() -%} {% set name = slapparameter_dict.get('name', 'localhost') -%} {% set monitor = slapparameter_dict.get('enable-monitor', 'True').lower() -%} {% set disable_ansible_promise = slapparameter_dict.get('disable-ansible-promise', 'False').lower() -%} {% set frontend_software_type = 'default' -%} {% set extends_list = [] -%} {% set part_list = [] -%} {% if monitor -%} {% do extends_list.append(template_monitor) -%} {% endif -%} {% do extends_list.append(logrotate_cfg) -%} [directory] recipe = slapos.cookbook:mkdirectory etc = ${buildout:directory}/etc bin = ${buildout:directory}/bin srv = ${buildout:directory}/srv var = ${buildout:directory}/var log = ${:var}/log scripts = ${:etc}/run services = ${:etc}/service promises = ${:etc}/promise novnc-conf = ${:etc}/novnc run = ${:var}/run ca-dir = ${:srv}/ssl public = ${:srv}/public/ cron-entries = ${:etc}/cron.d crontabs = ${:etc}/crontabs cronstamps = ${:etc}/cronstamps [create-mac] recipe = slapos.cookbook:generate.mac storage-path = ${directory:srv}/mac [create-tap-mac] recipe = slapos.cookbook:generate.mac storage-path = ${directory:srv}/tap_mac [gen-passwd] recipe = slapos.cookbook:generate.password storage-path = ${directory:srv}/passwd bytes = 8 [kvm-controller-parameter-dict] python-path = {{ python_executable }} vnc-passwd = ${gen-passwd:passwd} socket-path = ${directory:var}/qmp_socket [kvm-parameter-dict] python-path = {{ python_executable }} ipv4 = ${slap-network-information:local-ipv4} ipv6 = ${slap-network-information:global-ipv6} vnc-ip = ${:ipv4} vnc-port = 5901 default-cdrom-iso = {{ debian_amd64_netinst_location }} nbd-host = ${slap-parameter:nbd-host} nbd-port = ${slap-parameter:nbd-port} nbd2-host = ${slap-parameter:nbd2-host} nbd2-port = ${slap-parameter:nbd2-port} tap-interface = ${slap-network-information:network-interface} disk-path = ${directory:srv}/virtual.qcow2 disk-size = ${slap-parameter:disk-size} disk-type = ${slap-parameter:disk-type} pid-file-path = ${directory:run}/pid_file socket-path = ${kvm-controller-parameter-dict:socket-path} 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} use-tap = ${slap-parameter:use-tap} use-nat = ${slap-parameter:use-nat} nat-rules = ${slap-parameter:nat-rules} enable-vhost = ${slap-parameter:enable-vhost} virtual-hard-drive-url = ${slap-parameter:virtual-hard-drive-url} virtual-hard-drive-md5sum = ${slap-parameter:virtual-hard-drive-md5sum} virtual-hard-drive-gzipped = ${slap-parameter:virtual-hard-drive-gzipped} hard-drive-url-check-certificate = ${slap-parameter:hard-drive-url-check-certificate} shell-path = {{ dash_executable_location }} qemu-path = {{ qemu_executable_location }} qemu-img-path = {{ qemu_img_executable_location }} etc-directory = ${directory:etc} disk-storage-list = {% for key, path in storage_dict.items() -%} {{ ' ' ~ key ~ ' ' ~ path }} {% 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} {% if enable_http == 'true' or ( use_tap == 'true' and tap_network_dict.has_key('ipv4') ) -%} httpd-port = ${slap-parameter:httpd-port} {% else -%} httpd-port = 0 {% endif -%} # Main instance document server info {% if slapparameter_dict.get('document-host', '') and slapparameter_dict.get('document-port', '') -%} cluster-doc-host = ${tunnel-cluster-url:ipv4} cluster-doc-port = ${tunnel-cluster-url:ipv4-port} {% else -%} cluster-doc-host = cluster-doc-port = 0 {% endif -%} netcat-binary = {{ netcat_bin }} language = ${slap-parameter:keyboard-layout-language} [kvm-run] recipe = slapos.recipe.template:jinja2 template = {{ template_kvm_run }} rendered = ${directory:bin}/kvm_raw mode = 700 context = section parameter_dict kvm-parameter-dict [kvm-contoller] recipe = slapos.recipe.template:jinja2 template = {{ template_kvm_controller_run }} rendered = ${directory:scripts}/kvm_controller mode = 700 context = section parameter_dict kvm-controller-parameter-dict [tunnel-6to4-base] recipe = slapos.cookbook:wrapper ipv4 = ${slap-network-information:local-ipv4} ipv6 = ${slap-network-information:global-ipv6} wrapper-path = ${directory:services}/6tunnel-${:ipv6-port} command-line = {{ sixtunnel_executable_location }} -6 -4 -d -l ${:ipv6} ${:ipv6-port} ${:ipv4} ${:ipv4-port} {% if use_nat == 'true' -%} {% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') %} {% for port in nat_rule_list.split(' ') -%} {% set external_port = 10000 + port|int() -%} {% set section_name = '6tunnel-' ~ external_port -%} [{{ section_name }}] <= tunnel-6to4-base ipv4-port = {{ external_port }} ipv6-port = {{ external_port }} {% do part_list.append(section_name) -%} {% endfor -%} {% endif -%} [kvm-instance] recipe = slapos.cookbook:wrapper socket-path = ${kvm-controller-parameter-dict:socket-path} wrapper-path = ${directory:services}/kvm command-line = ${kvm-run:rendered} kvm-controller = ${kvm-contoller:rendered} [kvm-vnc-promise] recipe = slapos.cookbook:check_port_listening path = ${directory:promises}/vnc_promise hostname = ${kvm-parameter-dict:vnc-ip} port = ${kvm-parameter-dict:vnc-port} [kvm-disk-image-corruption-promise] # Check that disk image is not corrupted recipe = collective.recipe.template input = inline:#!/bin/sh # Return code 0 is "OK" # Return code 3 is "found leaks, but image is OK" # http://git.qemu.org/?p=qemu.git;a=blob;f=qemu-img.c;h=4e9a7f5741c9cb863d978225829e68fefcae3947;hb=HEAD#l702 ${kvm-parameter-dict:qemu-img-path} check ${kvm-parameter-dict:disk-path} RETURN_CODE=$? if [ $RETURN_CODE -eq 0 ] || [ $RETURN_CODE -eq 3 ]; then exit 0 else exit 1 fi output = ${directory:promises}/kvm-disk-image-corruption mode = 700 [novnc-instance] recipe = slapos.cookbook:novnc path = ${ca-novnc:executable} ip = ${slap-network-information:global-ipv6} port = 6080 vnc-ip = ${kvm-parameter-dict:vnc-ip} vnc-port = ${kvm-parameter-dict:vnc-port} novnc-location = {{ novnc_location }} websockify-path = {{ websockify_executable_location }} 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_executable_location }} 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} #---------------- #-- #-- Deploy cron. [cron] recipe = slapos.cookbook:cron dcrond-binary = {{ dcron_executable_location }} cron-entries = ${directory:cron-entries} crontabs = ${directory:crontabs} cronstamps = ${directory:cronstamps} catcher = ${cron-simplelogger:wrapper} binary = ${directory:services}/crond [cron-simplelogger] recipe = slapos.cookbook:simplelogger wrapper = ${directory:bin}/cron_simplelogger log = ${directory:log}/crond.log #---------------- #-- #-- Deploy frontend. [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 = ${slap-parameter:frontend-instance-name} 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} [frontend-promise] recipe = slapos.cookbook:check_url_available path = ${directory:promises}/frontend_promise url = ${publish-connection-information:url} dash_path = {{ dash_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 %} {% if monitor == 'true' -%} [monitor-access-log] < = monitor-directory-access source = ${directory:log} [monitor-access-public] < = monitor-directory-access source = ${directory:public} [monitor-parameters] port = 8026 {% if slapparameter_dict.get('document-host', '') and slapparameter_dict.get('document-port', '') -%} # XXX - Set frontend software type to 'custom-personal' by default for cluster instance {% set frontend_software_type = 'custom-personal' -%} {% endif -%} [request-monitor-frontend] <= slap-connection recipe = slapos.cookbook:requestoptional name = Monitor {{ slapparameter_dict.get('name', '') }} 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 = ${monitor-parameters:url} software-type = {{ slapparameter_dict.get('monitor-frontend-software-type', frontend_software_type) }} return = site_url domain [monitor-frontend-promise] recipe = slapos.cookbook:check_url_available path = ${directory:promises}/monitor_frontend url = ${publish-connection-information:monitor_url} dash_path = {{ dash_executable_location }} curl_path = {{ curl_executable_location }} check-secure = 1 {% endif -%} [publish-connection-information] recipe = slapos.cookbook:publish ipv6 = ${slap-network-information:global-ipv6} backend-url = https://[${novnc-instance:ip}]:${novnc-instance:port}/vnc_auto.html?host=[${novnc-instance:ip}]&port=${novnc-instance:port}&encrypt=1&password=${kvm-controller-parameter-dict:vnc-passwd} 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}&password=${kvm-controller-parameter-dict:vnc-passwd} {% set disk_number = len(storage_dict) -%} maximum-extra-disk-amount = {{ disk_number }} {% set iface = 'eth0' -%} {% if use_nat == 'true' -%} {% set iface = 'eth1' -%} # Publish NAT port mapping status # XXX: hardcoded value from [slap-parameter] {% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') %} {% for port in nat_rule_list.split(' ') -%} {% set external_port = 10000 + port|int() -%} nat-rule-port-{{port}} = ${slap-network-information:global-ipv6} : ${6tunnel-{{external_port}}:ipv6-port} {% if slapparameter_dict.get('publish-nat-url', False) -%} nat-rule-url-{{port}} = [${slap-network-information:global-ipv6}]:${6tunnel-{{external_port}}:ipv6-port} {% endif -%} {% endfor -%} {% endif -%} {% if use_tap == 'true' -%} tap-ipv4 = ${slap-network-information:tap-ipv4} {% endif -%} {% set kvm_http = 'http://${slap-network-information:local-ipv4}:' ~ slapparameter_dict.get('httpd-port', 8081) -%} {% if enable_http == 'true' %} {% if use_nat == 'true' -%} {% set kvm_http = 'http://10.0.2.100' -%} {% endif %} {% if slapparameter_dict.get('authorized-key', '') -%} 7_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/authorized_keys {% endif %} {% endif %} {% if monitor -%} monitor_url = ${request-monitor-frontend:connection-site_url} monitor_v6_url = ${monitor-parameters:url} {% endif -%} {% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%} 1_info = Use these configurations below to configure interface {{ iface }} in your VM. 2_info = ${network-config:ifconfig} 3_info = ${network-config:route-iface} 4_info = ${network-config:route-network} 5_info = ${network-config:route-default} {% if enable_http == 'true' %} 6_info = Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh - {% endif %} [network-config] recipe = plone.recipe.command path = ${directory:public}/netconfig.sh ifconfig = ifconfig {{ iface }} ${slap-network-information:tap-ipv4} netmask ${slap-network-information:tap-netmask} route-iface = route add ${slap-network-information:tap-gateway} dev {{ iface }} route-network = route add -net ${slap-network-information:tap-network} netmask ${slap-network-information:tap-netmask} gw ${slap-network-information:tap-gateway} {% if iface == 'eth0' -%} route-default = route add default gw ${slap-network-information:tap-gateway} {% elif global_ipv4_prefix -%} route-default = ip route add {{ global_ipv4_prefix }} via ${slap-network-information:tap-gateway} dev {{ iface }} src ${slap-network-information:tap-ipv4} {% else -%} route-default = {% endif -%} command = echo "#!/bin/sh" > ${:path} echo "" >> ${:path} echo "${:ifconfig}" >> ${:path} echo "${:route-iface}" >> ${:path} echo "${:route-network}" >> ${:path} echo "${:route-default}" >> ${:path} update-command = ${:command} {% endif -%} {% macro writefile(section_name, file_path, content, mode='') -%} {% 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 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] recipe = plone.recipe.command name = {{ slapparameter_dict.get('name', 'localhost') }} {% if use_tap == 'true' and tap_network_dict.has_key('ipv4') -%} local-ipv4 = ${slap-network-information:tap-ipv4} gateway = ${slap-network-information:tap-gateway} netmask = ${slap-network-information:tap-network} network = ${slap-network-information:tap-netmask} {% else -%} local-ipv4 = 127.0.0.1 gateway = netmask = network = {% endif -%} path-host = ${directory:public}/hostname path-ip = ${directory:public}/ipv4 path-gateway = ${directory:public}/gateway path-network = ${directory:public}/network path-netmask = ${directory:public}/netmask command = rm -f ${:path-host} rm -f ${:path-ip} rm -f ${:path-gateway} rm -f ${:path-network} rm -f ${:path-netmask} echo "${:name}" > ${:path-host} echo "${:local-ipv4}" > ${:path-ip} echo "${:gateway}" > ${:path-gateway} echo "${:network}" > ${:path-network} echo "${:netmask}" > ${:path-netmask} update-command = ${:command} # To access documents of main instance (in case of kvm-cluster) through http [cluster-url-path] recipe = slapos.recipe.template:jinja2 template = {{ template_content }} filename = cluster.hash rendered = ${directory:public}/${:filename} hash-url = https://10.0.2.101:443/{{ slapparameter_dict.get('document-path', '') }} context = key content_list :hash-url raw sep # # This 6to4 tunnel help to access document url in ipv4 [tunnel-cluster-url] recipe = slapos.cookbook:ipv4toipv6 ipv6 = {{ slapparameter_dict.get('document-host', '') }} ipv4 = ${slap-network-information:local-ipv4} ipv6-port = {{ slapparameter_dict.get('document-port', '') }} ipv4-port = 16936 shell-path = {{ dash_executable_location }} 6tunnel-path = {{ sixtunnel_executable_location }} runner-path = ${directory:services}/6tunnel-cluster [ansible-vm-promise] recipe = slapos.recipe.template:jinja2 template = {{ ansible_promise_tpl }} rendered = ${directory:promises}/ansible_{{ name }} extensions = jinja2.ext.do context = key host slap-network-information:tap-ipv4 raw logs ${directory:public}/ansible raw name {{ name }} [logrotate-vm-bootstrap] < = logrotate-entry-base name = vm-bootstrap log = ${directory:public}/ansible/vm-bootstrap.log [logrotate-entry-base] recipe = slapos.cookbook:logrotate.d logrotate-entries = ${logrotate:logrotate-entries} backup = ${logrotate:backup} [slap-parameter] # Default values if not specified frontend-software-type = frontend frontend-software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg frontend-instance-guid = frontend-instance-name = VNC Frontend nbd-port = 1024 nbd-host = nbd2-port = 1024 nbd2-host = ram-size = 1024 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 use-tap = False enable-vhost = False virtual-hard-drive-url = virtual-hard-drive-md5sum = virtual-hard-drive-gzipped = False # if virtual-hard-drive-url use https, then specify if https certificate should be checked or not hard-drive-url-check-certificate = True external-disk-number = 0 external-disk-size = 20 external-disk-format = qcow2 # Help to get some configuration files into the vm from http enable-http-server = False 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 authorized-key = # send some content which will be accessible to the vm through static url: http://10.0.2.100/data data-to-vm = # Change keyboard layout language keyboard-layout-language = ############################# # # Instanciate kvm (Buildout Section) # ############################# # Set Additionals parts {% if slapparameter_dict.get('document-host', '') %} {% do part_list.append('cluster-url-path') -%} {% endif -%} {% if enable_http == 'true' %} {% do part_list.extend(['httpd', 'httpd-promise', 'publish-host-config']) -%} {% if slapparameter_dict.get('data-to-vm', '') %} {% do part_list.append('vm-data-content') -%} {% endif -%} {% if use_tap == 'true' and tap_network_dict.has_key('ipv4') and disable_ansible_promise == 'false' %} {% do part_list.extend(['ansible-vm-promise', 'logrotate-vm-bootstrap']) -%} {% endif -%} {% if slapparameter_dict.get('authorized-key', '') %} {% do part_list.append('get-authorized-key') -%} {% endif -%} {% endif -%} [buildout] parts = certificate-authority publish-connection-information kvm-instance kvm-contoller kvm-vnc-promise kvm-disk-image-corruption-promise websockify-sighandler novnc-promise # kvm-monitor cron # cron-entry-monitor frontend-promise {% if monitor -%} # monitor parts cron-entry-monitor cron-entry-rss deploy-index deploy-status-history-cgi deploy-status-cgi # deploy-logfile-cgi # deploy-resource-consumption-monitoring-cgi setup-static-files public-symlink cgi-httpd-wrapper cgi-httpd-graceful-wrapper monitor-promise monitor-instance-log-access monitor-access-log monitor-access-public # monitor-frontend-promise {% endif -%} # Complete parts with sections {{ part_list | join('\n ') }} extends = # Add extends list {{ extends_list | join('\n ') }} # {{ template_httpd_cfg }} eggs-directory = {{ eggs_directory }} develop-eggs-directory = {{ develop_eggs_directory }} offline = true