pax_global_header 0000666 0000000 0000000 00000000064 13454062331 0014513 g ustar 00root root 0000000 0000000 52 comment=4eee4c81ac91449b1b26f13da25bb541b33eda21
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/ 0000775 0000000 0000000 00000000000 13454062331 0022550 5 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/ 0000775 0000000 0000000 00000000000 13454062331 0024402 5 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/ 0000775 0000000 0000000 00000000000 13454062331 0025177 5 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/README.rst 0000664 0000000 0000000 00000012274 13454062331 0026674 0 ustar 00root root 0000000 0000000 kvm
===
Introduction
------------
This software release is used to deploy KVM instances, NBD instances and
Frontend instances of KVM.
For extensive parameters definition, please look at parameter-input-schema.json.
Examples
--------
The following examples list how to request different possible instances of KVM
Software Release from slap console or command line.
KVM instance (1GB of RAM, 10GB of SSD, one core)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note that the KVM instance will try to request a frontend slave instance in order
to be accessible from IPv4.
::
myawesomekvm = request(
software_release=kvm,
partition_reference="My awesome KVM",
partition_parameter_kw={
"nbd-host":"ubuntu-1204.nbd.vifib.net",
}
)
See the instance-kvm-input-schema.json file for more instance parameters (cpu-count, ram-size, disk-size, etc).
KVM instance parameters:
~~~~~~~~~~~~~~~~~~~~~~~~~
- frontend-software-type (default: frontend)
- frontend-software-url (default: https://lab.nexedi.com/nexedi/slapos/raw/slapos-0.92/software/kvm/software.cfg)
- frontend-instance-guid
- frontend-instance-name (default: VNC Frontend)
- nbd-port (default: 1024)
- nbd-host
- nbd2-port (default: 1024)
- nbd2-host
- ram-size (default: 1024)
- disk-size = (default: 10)
- disk-type (default: virtio)
Disk size and Disk type are used if no virtual hard drive is specified.
- cpu-count (default: 1)
- cpu-options
cpu-option is a string: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]
- numa
list of numa options separate by space ex: node,nodeid=1,cpus=9-15 node,nodeid=2,cpus=1,3,7
- nat-rules (default: 22 80 443)
For port forwarding to IPv6 of slapos partition
- use-nat (default: True)
Add one interface using qemu User Network (NAT), this interface support nat-rules.
- use-tap (default: True)
Add one interface that uses tap interface from the host
- enable-vhost (default: False)
Increase network speed by enabling vhost on qemu. (To use if the module is loaded on host machine)
- virtual-hard-drive-url
URL of qemu image to download and use by this VM. If specified, Disk size and Disk type will be ignored.
- virtual-hard-drive-md5sum
MD5Sum of image disk to download
- virtual-hard-drive-gzipped (default: False)
Compress image to reduce size with gzip (.gz)
- hard-drive-url-check-certificate (default: True)
if virtual-hard-drive-url use self-signed https, then specify if https certificate should be verified or not
- external-disk-number (default: 0)
Number of additional disk to attach to this VM. Need slapformat to be configured for this feature.
- external-disk-size (default: 20)
- external-disk-format (default: qcow2)
additional disk format. should be in this list: ['qcow2', 'raw', 'vdi', 'vmdk', 'cloop', 'qed']
- enable-http-server (default: False)
Configure server that will help to get some files into the vm from http
require use-nat = True
All files in the document_root folder of the server will be accessible to the vm: http://10.0.2.100/PATH_TO_FILE
- httpd-port (default: 8081)
- authorized-key
the public key file will be available in the VM via url http://10.0.2.100/authorized_key
- data-to-vm
send some text content which will be accessible to the vm through the file: http://10.0.2.100/data
- keyboard-layout-language (default: fr)
Change keyboard layout language (Change to en-us if you face some bad bihaviors)
Language list: ['ar', 'da', 'de', 'de-ch', 'en-gb', 'en-us', 'es', 'et', 'fi',
'fo', 'fr', 'fr-be', 'fr-ca', 'fr-ch', 'hr', 'hu', 'is', 'it', 'ja', 'lt',
'lv', 'mk', 'nl', 'nl-be', 'no', 'pl', 'pt', 'pt-br', 'ru', 'sl', 'sv',
'th', 'tr']
Resilient KVM instance
~~~~~~~~~~~~~~~~~~~~~
Like KVM instance, but backed-up (with history) in two places.
::
kvm = 'https://lab.nexedi.com/nexedi/slapos/raw/slapos-0.188/software/kvm/software.cfg'
myresilientkvm = request(
software_release=kvm,
partition_reference="My resilient KVM",
software_type="kvm-resilient",
partition_parameter_kw={
"-sla-0-computer_guid": "COMP-1000", # Location of the main instance (KVM)
"-sla-1-computer_guid": "COMP-1001", # Location of the first clone
"-sla-2-computer_guid": "COMP-1002", # Location of the second clone
}
)
See the instance-kvm-input-schema.json AND instance-kvm-resilient-input-schema.json AND /stack/resilient/README.txt
files for more instance parameters (cpu-count, ram-size, disk-size, specific location of clones, etc).
Then, if you want one of the two clones to takeover, you need to login into
the hosting machine, go to the partition of the clone, and invoke bin/takeover.
KVM Frontend Master Instance (will host all frontend Slave Instances)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This type of instance will allow to host any frontend slave instance requested
by KVM instances. Slave instances (and thus KVM instance) will be accessible
at : https://mydomain.com/instancereference .
::
mykvmfrontend = request(
software_release=kvm,
partition_reference="mykvmfrontend",
partition_parameter_kw={
"domain":"mydomain.com"
},
software_type="frontend",
)
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/buildout.hash.cfg 0000664 0000000 0000000 00000005003 13454062331 0030427 0 ustar 00root root 0000000 0000000 # THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
# The only allowed lines here are (regexes):
# - "^#" comments, copied verbatim
# - "^[" section beginings, copied verbatim
# - lines containing an "=" sign which must fit in the following categorie.
# - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
# Copied verbatim.
# - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
# by the re-generation script.
# Re-generated.
# - other lines are copied verbatim
# Substitution (${...:...}), extension ([buildout] extends = ...) and
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[template]
filename = instance.cfg.in
md5sum = 028b6a6456d744c11b1bb2c51ecd51b2
[template-kvm]
filename = instance-kvm.cfg.jinja2
md5sum = c298aaa20a368ddc118b8bb22dc84dc3
[template-kvm-cluster]
filename = instance-kvm-cluster.cfg.jinja2.in
md5sum = 63fa784d8946d0b6e3fbd6381e1ea9f4
[template-kvm-resilient]
filename = instance-kvm-resilient.cfg.jinja2
md5sum = 6677ac6074f6be671fe8e8b8a6a4afe8
[template-kvm-import]
filename = instance-kvm-import.cfg.jinja2.in
md5sum = dc3f3ad9ebd8b3b5c3ded57b91cee9c7
[template-kvm-import-script]
filename = template/kvm-import.sh.jinja2
md5sum = cd0008f1689dfca9b77370bc4d275b70
[template-kvm-export]
filename = instance-kvm-export.cfg.jinja2
md5sum = 00ce5e6da3c833d9d9d1825311f11a81
[template-kvm-export-script]
filename = template/kvm-export.sh.jinja2
md5sum = b617d64de73de1eed518185f310bbc82
[template-nbd]
filename = instance-nbd.cfg.in
md5sum = f634a5249b773658b7a7bc9fa9bb0368
[template-frontend]
filename = instance-frontend.cfg.in
md5sum = 57a4be74e5afb00e378bc726cd7771f8
[template-ansible-promise]
filename = template/ansible-promise.in
md5sum = 2036bf145f472f62ef8dee5e729328fd
[template-kvm-run]
filename = template/template-kvm-run.in
md5sum = c8ca875bf246997137552538ab9d8b1a
[template-kvm-controller]
filename = template/kvm-controller-run.in
md5sum = b96cba47c97f277c857176d69e086a12
[template-apache-conf]
filename = template/apache.conf.in
md5sum = ac97f6a52e1c5a19a646242ef85abb8a
[template-content]
filename = template/template-content.in
md5sum = 822737e483864bf255ad1259237bef2a
[template-qemu-ready]
filename = template/qemu-is-ready.in
md5sum = b304eec8e2cb71f10ea83cac22f6db12
[file-download-script]
filename = template/download_file.in
md5sum = 599dbbbd438fe7801e3f8642ae9e9a78
[template-httpd]
filename = instance-kvm-http.cfg.in
md5sum = 26a181a48046ce88570adb32334747ef
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/development.cfg 0000664 0000000 0000000 00000000527 13454062331 0030206 0 ustar 00root root 0000000 0000000 # Development profile of slaprunner.
# Exactly the same as software.cfg, but fetch the slapos.cookbook and
# slapos.toolbox from git repository instead of fetching stable version,
# allowing to play with bleeding edge environment.
[buildout]
extends = software.cfg
../../stack/slapos-dev.cfg
parts +=
# Development eggs
${:common-parts}
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/instance-frontend.cfg.in 0000664 0000000 0000000 00000006143 13454062331 0031712 0 ustar 00root root 0000000 0000000 #############################
#
# Instanciate kvm frontend
#
#############################
[buildout]
parts =
ca-frontend
certificate-authority
frontend-promise-ipv6
frontend-promise-ipv4
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
bin = $${buildout:directory}/bin
srv = $${buildout:directory}/srv
var = $${buildout:directory}/var
[basedirectory]
recipe = slapos.cookbook:mkdirectory
services = $${rootdirectory:etc}/run
promises = $${rootdirectory:etc}/promise
nodejs-conf = $${rootdirectory:etc}/nodejs
run = $${rootdirectory:var}/run
log = $${rootdirectory:var}/log
ca-dir = $${rootdirectory:srv}/ssl
backup = $${rootdirectory:srv}/backup
[directory]
recipe = slapos.cookbook:mkdirectory
ca-dir = $${rootdirectory:srv}/ssl
[frontend-instance]
recipe = slapos.cookbook:kvm.frontend
domain = $${ca-frontend:name}
# port = $${slap-parameter:port}
ipv6 = $${slap-network-information:global-ipv6}
ipv4 = $${slap-network-information:local-ipv4}
port = $${slap-parameter:port}
http-redirection = $${slap-parameter:http-redirection}
ssl-key-path = $${ca-frontend:key-file}
ssl-cert-path = $${ca-frontend:cert-file}
slave-instance-list = $${slap-parameter:slave_instance_list}
map-path = $${basedirectory:nodejs-conf}/proxy_table.json
conf-path = $${basedirectory:nodejs-conf}/kvm-proxy.js
wrapper-path = $${rootdirectory:bin}/kvm_frontend
node-binary = ${nodejs:location}/bin/node
node-env = ${buildout:parts-directory}:${npm-modules:location}/node_modules
shell-path = ${dash:location}/bin/dash
[frontend-promise-ipv6]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/frontend_promise
hostname = $${frontend-instance:ipv6}
port = $${frontend-instance:port}
[frontend-promise-ipv4]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/frontend_promise
hostname = $${frontend-instance:ipv4}
port = $${frontend-instance:port}
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${basedirectory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${basedirectory: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 = $${basedirectory:ca-dir}/requests/
private = $${basedirectory:ca-dir}/private/
certs = $${basedirectory:ca-dir}/certs/
newcerts = $${basedirectory:ca-dir}/newcerts/
crl = $${basedirectory:ca-dir}/crl/
[ca-frontend]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${basedirectory:nodejs-conf}/nodejs.key
cert-file = $${basedirectory:nodejs-conf}/nodejs.crt
executable = $${frontend-instance:wrapper-path}
wrapper = $${basedirectory:services}/nodejs
# Put domain name
name = $${slap-parameter:domain}
[slap-parameter]
# Default value if no port is specified
port = 4443
http-redirection = 0
slave_instance_list =
instance-kvm-cluster-input-schema.json 0000664 0000000 0000000 00000053345 13454062331 0034476 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"frontend": {
"title": "KVM frontend (web socket)",
"description": "Front end used to provide VNC.",
"properties": {
"frontend-instance-guid": {
"title": "Frontend Instance ID",
"description": "Unique identifier of the frontend instance, like \"SOFTINST-11031\".",
"type": "string",
"default": ""
},
"frontend-software-type": {
"title": "Frontend Software Type",
"description": "Type of the frontend instance, like \"frontend\".",
"type": "string",
"default": "frontend"
},
"frontend-software-url": {
"title": "Frontend Software URL",
"description": "Software Release URL of the frontend instance, like \"http://example.com/path/to/software.cfg\".",
"type": "string",
"format": "uri",
"default": "https://lab.nexedi.com/nexedi/slapos/raw/slapos-0.92/software/kvm/software.cfg"
}
},
"type": "object"
},
"slave-frontend": {
"title": "Web frontend",
"description": "Front end used to provide web access for internal services at the kvm.",
"properties": {
"instance-guid": {
"title": "Main Frontend Instance ID",
"description": "Unique identifier of the frontend instance, like \"SOFTINST-11031\".",
"type": "string",
"default": ""
},
"frontend-software-type": {
"title": "Frontend Software Type",
"description": "Type of the frontend instance, like \"frontend\".",
"type": "string",
"default": "custom-personal"
},
"frontend-software-url": {
"title": "Frontend Software URL",
"description": "Software Release URL of the frontend instance, like \"http://example.com/path/to/software.cfg\".",
"type": "string",
"format": "uri",
"default": "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg"
},
"slave-frontend-dict": {
"title": "Slave Front end definition",
"description": "Slave Front end definition",
"patternProperties": {
".*": {
"properties": {
"domain": {
"title": "Name of the domain to be used",
"description": "Name of the domain to be used (example: mydomain.com). Subdomains of this domain will be used for the slave instances (example: instance12345.mydomain.com).",
"type": "string",
"default": ""
},
"url": {
"title": "URL of backend to use.",
"description": "URL of backend to use. This URL will be used to request frontend if parameter 'kvm-partition-name' is not set.",
"format": "uri",
"type": "string",
"default": ""
},
"enable-cache": {
"title": "Use cache for this slave frontend.",
"description": "Specify if slave frontend should use a squid to connect to backend.",
"type": "boolean",
"default": false
},
"type": {
"title": "Specify if slave frontend will redirect to a zope backend.",
"description": "If specified, Apache RewriteRule will use Zope's Virtual Host Daemon. Possible values: 'zope', 'default'.",
"type": "string",
"default": "default"
},
"zope-path": {
"title": "Path to the VirtualHostRoot of the zope.",
"description": "Only used if type is 'zope'. Will append the specified path to the VirtualHostRoot of the zope's VirtualHostMonster.",
"type": "string",
"default": ""
},
"https-only": {
"title": "Access website with https url only.",
"description": "Specify if website should be accessed using https only. If so, the frontend will redirect the user to https if accessed from http.",
"type": "boolean",
"default": false
},
"kvm-partition-name": {
"title": "Reference name in kvm instance definition to get url from.",
"description": "Compose url from kvm definition. Only work if 'use-nat' is true and 'service-port' is set. This will allow to get URL from defined nat-rules. Play the same as url, but help if you don't know kvm ipv6 yet.",
"type": "string",
"default": ""
},
"service-port": {
"title": "Port of service into the VM (require: kvm-name).",
"description": "This will allow to get URL from defined nat-rules. The port should exist in nat-rules of KVM you have referenced by 'kvm-partition-name'",
"type": "integer"
},
"url-scheme": {
"title": "Scheme of HTTP service into the VM (require: kvm-name).",
"description": "Say If HTTP service to run/or running into the Virtual Machine will use http or https. Possible values: http, https.",
"type": "string",
"enum": [
"http",
"https"
],
"default": "http"
}
},
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
},
"fw-restricted-access": {
"title": "Restrict all access to VM with firewall.",
"description": "When Firewall is enabled, this parameter define if only vm of this cluster and authorized sources ip should have access to cluster.",
"type": "string",
"enum": [
"on",
"off"
],
"default": "off"
},
"fw-authorized-sources": {
"title": "List of IP/Network address authorized to cluster.",
"description": "When Firewall is enabled, this contain the list of IP address to authorize for access to all VM of this cluster.",
"type": "array",
"optional": true
},
"fw-reject-sources": {
"title": "List of IP/Network address rejected, if 'Restrict all access' is off.",
"description": "When Firewall is enabled, this contain the list of IP address which should not access to all VM of this cluster.",
"type": "array",
"optional": true
},
"authorized-keys": {
"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",
"type": "array"
},
"bootstrap-script-url": {
"title": "Virtual Machines bootstrap script URL.",
"description": "If dedicaced disk image is used, this script will be downloaded and run at first boot of the virtual machine. Set md5sum to URL like: http://example.com/file#MD5SUM. Get file in vm at http://10.0.2.100/vm-bootstrap.",
"type": "string",
"format": "uri"
},
"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"
},
"monitor-interface-url": {
"title": "Monitor Web Interface URL",
"description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"type": "string",
"format": "uri",
"default": "https://monitor.app.officejs.com"
},
"monitor-cors-domains": {
"title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string",
"default": "monitor.app.officejs.com"
},
"kvm-partition-dict": {
"title": "kvm instances definition",
"description": "kvm instances definition",
"patternProperties": {
".*": {
"properties": {
"computer-guid": {
"title": "ID of the computer where to deploy this VM.",
"description": "Unique identifier of the computer, like \"COMP-1234\". By default, let Master choose a computer.",
"type": "string",
"default": ""
},
"state": {
"title": "State of this Virtual Machine",
"description": "Define if SlapOS should start or stop this VM.",
"type": "string",
"default": "started",
"enum": [
"started",
"stopped"
]
},
"enable-device-hotplug": {
"title": "Enable device hotplug mode",
"description": "If yes, this will allow to Create devices like CPU and Memory in hotplug mode without restart the VM. Operatin System should be configured to Online new created devices.",
"type": "boolean",
"default": false
},
"ram-size": {
"title": "RAM size",
"description": "RAM size, in MB.",
"type": "integer",
"default": 1024,
"minimum": 1024,
"multipleOf": 512
},
"ram-max-size": {
"title": "Maximum RAM size, in MB",
"description": "Define the maximum size of the memory. The size is in MB and should be a multiple of 512.",
"type": "integer",
"default": 51200,
"minimum": 1024,
"multipleOf": 512
},
"ram-hotplug-slot-size": {
"title": "Size of Hotpluggable RAM slot, in MB",
"description": "Define the RAM size to plug on one hotpluggable slot in MB, understand the size of one RAM bar. The RAM hotplugged on each slot will always have the same RAM size.",
"type": "integer",
"default": 512,
"minimum": 512,
"multipleOf": 512
},
"auto-ballooning": {
"title": "Enable qemu auto ballooning.",
"description": "Enable virtio balloon device to allows KVM guests to reduce/re-increase their memory size.",
"type": "boolean",
"default": true
},
"disk-size": {
"title": "Disk size",
"description": "Disk size, in GB.",
"type": "integer",
"default": 10,
"minimum": 1
},
"disk-format": {
"title": "Disk format.",
"description": "Format of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
},
"disk-type": {
"title": "Disk type",
"description": "Type of QEMU disk drive.",
"type": "string",
"default": "virtio",
"enum": [
"ide",
"scsi",
"sd",
"mtd",
"floppy",
"pflash",
"virtio"
]
},
"disk-cache": {
"title": "Cache option to use with Disk.",
"description": "Disk cache controls how the host cache is used to access block data.",
"type": "string",
"default": "writeback",
"enum": [
"none",
"writeback",
"unsafe",
"directsync",
"writethrough"
]
},
"disk-aio": {
"title": "Disk aio to use.",
"description": "Selects between pthread based disk I/O and native Linux AIO.",
"type": "string",
"default": "threads",
"enum": [
"threads",
"native"
]
},
"cpu-count": {
"title": "CPU count",
"description": "Number of CPU cores.",
"type": "integer",
"minimum": 1
},
"cpu-max-count": {
"title": "Maximum CPU amount",
"description": "Specifies the maximum number of CPUs.",
"type": "integer",
"default": 24,
"minimum": 1,
"maximum": 64
},
"numa": {
"title": "Simulate a multi node NUMA system.",
"description": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. Each numa option are separated by space: node,nodeid=4,cpus=40-49,mem=64g node,nodeid=1,cpus=10-19,mem=128g. Set this option if you know what you're doing.",
"type": "string"
},
"machine-options": {
"title": "Machine options.",
"description": "Select the emulated machine by name. Ex: pc-i440fx-2.4,accel=kvm",
"type": "string"
},
"cpu-model": {
"title": "CPU model.",
"description": "Select the emulated CPU model. Ex: SandyBridge,+erms,+smep,+smx,+vmx",
"type": "string",
"default": "host"
},
"keyboard-layout-language": {
"title": "Use keyboard layout language",
"description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display",
"type": "string",
"enum": [
"ar",
"da",
"de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr"
],
"default": "fr"
},
"nbd-host": {
"title": "NBD hostname or IP",
"description": "hostname (or IP) of the NBD server containing the boot image.",
"type": "string",
"format": "internet-address",
"default": "debian.nbd.vifib.net"
},
"nbd-port": {
"title": "NBD port",
"description": "Port of the NBD server containing the boot image.",
"type": "integer",
"default": 1024,
"minimum": 1,
"maximum": 65535
},
"virtual-hard-drive-url": {
"title": "Existing disk image URL",
"description": "If specified, will download an existing disk image (qcow2, raw, ...), and will use it as main virtual hard drive. Can be used to download and use an already installed and customized virtual hard drive.",
"format": "uri",
"type": "string"
},
"virtual-hard-drive-md5sum": {
"title": "Checksum of virtual hard drive",
"description": "MD5 checksum of virtual hard drive, used if virtual-hard-drive-url is specified.",
"type": "string"
},
"virtual-hard-drive-gzipped": {
"title": "Virtual hard drive to download is gzipped",
"description": "Define if virtual hard drive to download is gzipped using gzip. This help to reduce size of file to download.",
"type": "boolean",
"default": false
},
"hard-drive-url-check-certificate": {
"title": "Check certificate when downloading virtual hard drive from https.",
"description": "Define if certificate should be checked when downloading virtual hard drive from https url.",
"type": "boolean",
"default": true
},
"external-disk-number": {
"title": "Number of additional disk to create for virtual machine",
"description": "Specify the number of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.",
"type": "integer",
"minimum": 0,
"default": 0
},
"external-disk-size": {
"title": "Size of additional disk to create for virtual machine, in Gigabytes",
"description": "Specify the size of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.",
"type": "integer",
"minimum": 5,
"default": 20
},
"external-disk-format": {
"title": "Type of external disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
},
"wipe-disk-ondestroy": {
"title": "Wipe disks when destroy the VM",
"description": "Say if disks should be wiped by writing new data over every single bit before delete them. This option is used to securely delete VM disks",
"type": "boolean",
"default": false
},
"wipe-disk-iterations": {
"title": "Wipe disk iterations",
"description": "Number of disk overwrite iterations with random data. Default is 1. WARNING: Increase this value will slow down partition destruction and increase IO.",
"type": "integer",
"default": 1,
"minimum": 1,
"maximum": 5
},
"use-tap": {
"title": "Enable QEMU TAP network interface",
"description": "Use QEMU TAP network interface, might require a bridge on SlapOS Node.",
"type": "boolean",
"default": true
},
"use-nat": {
"title": "Enable QEMU USER Mode interface (NAT)",
"description": "Use QEMU user-mode network stack (NAT).",
"type": "boolean",
"default": true
},
"nat-rules": {
"title": "List of rules for NAT of QEMU user mode network stack.",
"description": "List of rules for NAT of QEMU user mode network stack, as comma-separated list of ports. For each port specified, it will redirect port x of the VM (example: 80) to the port x + 10000 of the public IPv6 (example: 10080). Defaults to \"22 80 443\".",
"type": "array",
"default": []
},
"nat-restrict-mode": {
"title": "Isolate the NAT Interface (No Internet access)",
"description": "If this option is enabled, the NAT interface will be isolated, i.e. it will not be able to contact the host and no guest IP packets will be routed over the host to the outside. This option does not affect any explicitly set nat rules.",
"type": "boolean",
"default": false
},
"enable-vhost": {
"title": "Use vhost-net to improve network performance of tap interface",
"description": "The vhost-net provides much improved network performance for your VM. Only work if the vhost-net kernel module is loaded and available on host machine, please keep this option off if you're not shure.",
"type": "boolean",
"default": false
},
"bootstrap-script-url": {
"title": "VM bootstrap script URL.",
"description": "If dedicaced disk image is used, this script will be downloaded and run at first boot of the virtual machine. Set md5sum to URL like: http://example.com/file#MD5SUM. Get file in vm at http://10.0.2.100/vm-bootstrap.",
"type": "string",
"format": "uri"
},
"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"
},
"disable-ansible-promise": {
"title": "Desactivate Ansible promise check",
"description": "If the VM of cluster doesn't run Ansible and report status to this SlapOS instances, then this allow to disable ansible promise so your instance will not fail to check ansible promise.",
"type": "boolean",
"default": false
}
},
"type": "object"
}
},
"type": "object"
}
}
}
instance-kvm-cluster-simplified-input-schema.json 0000664 0000000 0000000 00000004557 13454062331 0036622 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"kvm-partition-dict": {
"title": "kvm instances definition",
"description": "kvm instances definition",
"patternProperties": {
".*": {
"properties": {
"state": {
"title": "State of this Virtual Machine",
"description": "Define if SlapOS should start or stop this VM.",
"type": "string",
"default": "started",
"enum": [
"started",
"stopped"
]
},
"keyboard-layout-language": {
"title": "Use keyboard layout language",
"description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display",
"type": "string",
"enum": [
"ar",
"da",
"de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr"
],
"default": "fr"
},
"nbd-host": {
"title": "NBD hostname or IP",
"description": "hostname (or IP) of the NBD server containing the boot image.",
"type": "string",
"format": "internet-address",
"default": "debian.nbd.vifib.net"
},
"nbd-port": {
"title": "NBD port",
"description": "Port of the NBD server containing the boot image.",
"type": "integer",
"default": 1024,
"minimum": 1,
"maximum": 65535
}
},
"type": "object"
}
},
"type": "object"
}
}
}
instance-kvm-cluster.cfg.jinja2.in 0000664 0000000 0000000 00000032667 13454062331 0033456 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {% set publish_dict = {} -%}
{% set part_list = [] -%}
{% set ipv6 = (ipv6 | list)[0] -%}
{% set frontend_dict = slapparameter_dict.get('frontend', {}) -%}
{% set slave_frontend_dict = slapparameter_dict.get('slave-frontend', {}) -%}
{% set slave_frontend_sr = slave_frontend_dict.get('software-url', 'http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg') -%}
{% set slave_frontend_stype = slave_frontend_dict.get('software-type', 'custom-personal') -%}
{% set slave_frontend_iguid = slave_frontend_dict.get('instance-guid', '') -%}
{% set kvm_instance_dict = {} -%}
{% set kvm_hostname_list = [] -%}
{% set monitor_base_url_dict = {} -%}
{% macro setconfig(name, value) -%}
{# will set a config-name = value if value is not empty -#}
{% if value and value != '' -%}
config-{{ name }} = {{ dumps(value) }}
{% endif -%}
{% endmacro -%}
[request-common]
recipe = slapos.cookbook:request
software-url = ${slap-connection:software-release-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}
config-use-ipv6 = {{ dumps(slapparameter_dict.get('use-ipv6', False)) }}
# Request kvm instances
{% for instance_name, kvm_parameter_dict in slapparameter_dict.get('kvm-partition-dict', {'kvm-default': {}}).items() -%}
{% set section = 'request-' ~ instance_name -%}
{% set use_nat = kvm_parameter_dict.get('use-nat', 'True') -%}
[{{ section }}]
<= request-common
software-type = kvm
name = {{ instance_name }}
{% if kvm_parameter_dict.get('sticky-computer', '') -%}
sla-computer_guid = ${slap-connection:computer-id}
{% else -%}
sla-computer_guid = {{ dumps(kvm_parameter_dict.get('computer-guid', '')) }}
{% endif -%}
sla-network_guid = {{ dumps(kvm_parameter_dict.get('network-guid', '')) }}
sla-project_guid = {{ dumps(kvm_parameter_dict.get('project-guid', '')) }}
{% if kvm_parameter_dict.get('state', '') == 'stopped' -%}
state = stopped
{% endif -%}
config-frontend-instance-name = {{ instance_name ~ ' VNC Frontend' }}
config-frontend-software-type = {{ dumps(frontend_dict.get('software-type', 'frontend')) }}
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')) }}
{{ setconfig('frontend-instance-guid', kvm_parameter_dict.get('instance-guid', '')) }}
config-name = {{ instance_name }}
{% if slapparameter_dict.get('authorized-keys', []) -%}
config-authorized-key = {{ dumps(slapparameter_dict.get('authorized-keys') | join('\n')) }}
{% endif -%}
config-nbd-port = {{ dumps(kvm_parameter_dict.get('nbd-port', 1024)) }}
config-nbd2-port = {{ dumps(kvm_parameter_dict.get('nbd-port2', 1024)) }}
config-ram-size = {{ dumps(kvm_parameter_dict.get('ram-size', 1024)) }}
config-ram-max-size = {{ dumps(kvm_parameter_dict.get('ram-max-size', '51200')) }}
config-enable-device-hotplug = {{ dumps(kvm_parameter_dict.get('enable-device-hotplug', False)) }}
config-ram-hotplug-slot-size = {{ dumps(kvm_parameter_dict.get('ram-hotplug-slot-size', 512)) }}
config-disk-size = {{ dumps(kvm_parameter_dict.get('disk-size', 10)) }}
config-disk-type = {{ dumps(kvm_parameter_dict.get('disk-type', 'virtio')) }}
config-disk-format = {{ dumps(kvm_parameter_dict.get('disk-format', 'qcow2')) }}
config-cpu-count = {{ dumps(kvm_parameter_dict.get('cpu-count', 1)) }}
config-cpu-max-count = {{ dumps(kvm_parameter_dict.get('cpu-max-count', 24)) }}
{{ setconfig('numa', kvm_parameter_dict.get('numa', '')) }}
{{ setconfig('machine-options', kvm_parameter_dict.get('machine-options', '')) }}
{{ setconfig('nbd-host', kvm_parameter_dict.get('nbd-host', '')) }}
{{ setconfig('host2', kvm_parameter_dict.get('host2', '')) }}
config-auto-ballooning = {{ dumps(kvm_parameter_dict.get('auto-ballooning', True)) }}
{{ setconfig('disk-cache', kvm_parameter_dict.get('disk-cache', '')) }}
{{ setconfig('disk-aio', kvm_parameter_dict.get('disk-aio', '')) }}
{{ setconfig('cpu-model', kvm_parameter_dict.get('cpu-model', 'host')) }}
{{ setconfig('disk-cache', kvm_parameter_dict.get('disk-cache', '')) }}
{{ setconfig('disk-device-path', kvm_parameter_dict.get('disk-device-path', '')) }}
{% set nat_rules_list = kvm_parameter_dict.get('nat-rules', []) -%}
{{ setconfig('nat-rules', nat_rules_list | join(' ')) }}
config-publish-nat-url = True
config-use-nat = {{ use_nat }}
config-use-tap = {{ dumps(kvm_parameter_dict.get('use-tap', True)) }}
config-nat-restrict-mode = {{ dumps(kvm_parameter_dict.get('nat-restrict-mode', False)) }}
config-enable-vhost = {{ dumps(kvm_parameter_dict.get('enable-vhost', False)) }}
{{ setconfig('virtual-hard-drive-url', kvm_parameter_dict.get('virtual-hard-drive-url', '')) }}
{{ setconfig('virtual-hard-drive-md5sum', kvm_parameter_dict.get('virtual-hard-drive-md5sum', '')) }}
config-virtual-hard-drive-gzipped = {{ dumps(kvm_parameter_dict.get('virtual-hard-drive-gzipped', False)) }}
config-hard-drive-url-check-certificate = {{ dumps(kvm_parameter_dict.get('hard-drive-url-check-certificate', True)) }}
config-external-disk-number = {{ dumps(kvm_parameter_dict.get('external-disk-number', 0)) }}
config-external-disk-size = {{ dumps(kvm_parameter_dict.get('external-disk-size', 20)) }}
config-external-disk-format = {{ dumps(kvm_parameter_dict.get('external-disk-format', 'qcow2')) }}
config-enable-http-server = {{ dumps(kvm_parameter_dict.get('enable-http-server', True)) }}
config-httpd-port = {{ dumps(kvm_parameter_dict.get('httpd-port', 8081)) }}
{{ setconfig('data-to-vm', kvm_parameter_dict.get('data-to-vm', '')) }}
config-disable-ansible-promise = {{ dumps(kvm_parameter_dict.get('disable-ansible-promise', False)) }}
config-monitor-cors-domains = {{ slapparameter_dict.get('monitor-cors-domains', 'monitor.app.officejs.com') }}
config-monitor-username = ${monitor-instance-parameter:username}
config-monitor-password = ${publish-early:monitor-password}
# Enable disk wipe options
{% if kvm_parameter_dict.get('wipe-disk-ondestroy', False) -%}
config-wipe-disk-ondestroy = True
config-wipe-disk-iterations = {{ dumps(kvm_parameter_dict.get('wipe-disk-iterations', 1)) }}
{% endif -%}
# Enable simple http server on ipv6 so all VMs will access it
config-document-host = ${apache-conf:ip}
config-document-port = ${apache-conf:port}
config-document-path = ${hash-code:passwd}
config-keyboard-layout-language = {{ dumps(kvm_parameter_dict.get('keyboard-layout-language', 'fr')) }}
config-type = cluster
{% set bootstrap_script_url = slapparameter_dict.get('bootstrap-script-url', kvm_parameter_dict.get('bootstrap-script-url', '')) -%}
{% if bootstrap_script_url -%}
config-bootstrap-script-url = {{ bootstrap_script_url }}
{% endif -%}
{% set authorized_source_list = slapparameter_dict.get('fw-authorized-sources', []) -%}
{% set rejected_source_list = slapparameter_dict.get('fw-reject-sources', []) -%}
sla-fw_authorized_sources = {{ authorized_source_list | join(' ') }}
sla-fw_rejected_sources = {{ rejected_source_list | join(' ') }}
sla-fw_restricted_access = {{ dumps(slapparameter_dict.get('fw-restricted-access', 'off')) }}
return =
url
backend-url
{% if str(use_nat).lower() == 'true' -%}
{% for port in nat_rules_list -%}
{{ ' ' }}nat-rule-url-{{ port }}
{% endfor -%}
{% endif -%}
{{ ' ' }}monitor-base-url
{% if str(kvm_parameter_dict.get('use-tap', 'True')).lower() == 'true' -%}
{{ ' ' }}tap-ipv4
{{ ' ' }}tap-ipv6
{{ ' ' }}ipv6-network-info
{% do publish_dict.__setitem__(instance_name ~ '-ipv4', '${' ~ section ~ ':connection-tap-ipv4}') -%}
{% do publish_dict.__setitem__(instance_name ~ '-ipv6', '${' ~ section ~ ':connection-tap-ipv6}') -%}
{% do publish_dict.__setitem__(instance_name ~ '-ipv6-info', '${' ~ section ~ ':connection-ipv6-network-info}') -%}
{% do kvm_hostname_list.append(instance_name ~ ' ' ~ '${' ~ section ~ ':connection-tap-ipv4}') -%}
{% endif -%}
{% do monitor_base_url_dict.__setitem__(instance_name, '${' ~ section ~ ':connection-monitor-base-url}') -%}
{% do publish_dict.__setitem__(instance_name ~ '-backend-url', '${' ~ section ~ ':connection-backend-url}') -%}
{% do publish_dict.__setitem__(instance_name ~ '-url', '${' ~ section ~ ':connection-url}') -%}
{% do kvm_instance_dict.__setitem__(instance_name, (use_nat, nat_rules_list)) -%}
{% endfor %}
#request custom kvm frontend
{% for frontend_name, frontend_parameter_dict in slave_frontend_dict.get('slave-frontend-dict', {}).items() -%}
{% set name = frontend_name -%}
{% set url = frontend_parameter_dict.get('url', '') -%}
{% set error = '' -%}
{% if frontend_parameter_dict.get('kvm-partition-name', '') != '' -%}
{% set kvm_name = frontend_parameter_dict['kvm-partition-name'] -%}
{% set service_port = str(frontend_parameter_dict['service-port']) -%}
{% if kvm_name in kvm_instance_dict.keys() and not kvm_instance_dict[kvm_name][0] -%}
{% set error = "You should set parameter use-nat to 'true' for '" ~ kvm_name ~ "', or provide url to use for frontend." -%}
{% elif kvm_name in kvm_instance_dict.keys() and service_port in kvm_instance_dict[kvm_name][1] -%}
{% set url = '${request-' ~ kvm_name ~ ':connection-nat-rule-url-' ~ service_port ~ '}' -%}
{% set url = frontend_parameter_dict.get('url-scheme', 'http') ~ '://' ~ url -%}
{% else -%}
{% set error = kvm_name ~ " and/or port " ~ service_port ~ " doesn't match any KVM name and/or related nat-rules in your request parameters." -%}
{% endif -%}
{% endif -%}
{% set section = 'request-' ~ name ~ '-slave-frontend' -%}
[{{ section }}]
<= request-common
recipe = slapos.cookbook:request
software-url = {{ slave_frontend_sr }}
name = Frontend {{ name }}
software-type = {{ slave_frontend_stype }}
slave = true
config-url = {{ url }}
{{ setconfig('custom_domain', kvm_parameter_dict.get('domain', '')) }}
config-enable_cache = {{ dumps(frontend_parameter_dict.get('enable-cache', False)) }}
config-https-only = {{ dumps(frontend_parameter_dict.get('https-only', False)) }}
{% if frontend_parameter_dict.get('type', '') -%}
config-type = {{ dumps(frontend_parameter_dict['type']) }}
{% if frontend_parameter_dict.get('path', '') -%}
config-path = {{ dumps(frontend_parameter_dict['path']) }}
{% endif -%}
{% endif -%}
return =
site_url
sla-instance_guid = {{ slave_frontend_iguid }}
{% do publish_dict.__setitem__(name ~ '-url', '${' ~ section ~ ':connection-site_url}') -%}
{% if error != '' -%}
{% do publish_dict.__setitem__('1_error', error) -%}
{% endif -%}
{% endfor %}
# 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]
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
webroot = ${:srv}/document
promises = ${:etc}/promise
ssl = ${:etc}/ssl
[directory-doc]
recipe = slapos.cookbook:mkdirectory
document = ${directory:webroot}/${hash-code:passwd}
[apache-conf]
denied-root-access = true
root = ${directory:webroot}/
index = ${directory:webroot}/${hash-code:passwd}
port = 9002
{% if len(kvm_hostname_list) -%}
{% do part_list.append('write-vm-hostname') -%}
[write-vm-hostname]
recipe = slapos.recipe.template:jinja2
template = {{ template_content }}
filename = hosts
rendered = ${directory:webroot}/${hash-code:passwd}/${:filename}
context =
raw content_list {{ kvm_hostname_list | join('#') }}
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', '${directory:webroot}/${hash-code:passwd}/data', slapparameter_dict.get('cluster-data', ''), '700') }}
{% endif -%}
[publish-early]
recipe = slapos.cookbook:publish-early
-init =
monitor-password monitor-htpasswd:passwd
[monitor-instance-parameter]
monitor-httpd-port = 8060
cors-domains = {{ slapparameter_dict.get('monitor-cors-domains', 'monitor.app.officejs.com') }}
username = admin
password = ${monitor-htpasswd:passwd}
[monitor-base-url-dict]
{% for key, value in monitor_base_url_dict.items() -%}
{{ key }} = {{ value }}
{% endfor %}
[monitor-conf-parameters]
private-path-list +=
${directory:webroot}/
[publish-connection-information]
recipe = slapos.cookbook:publish
{% for name, value in publish_dict.items() -%}
{{ name }} = {{ value }}
{% endfor %}
{% set monitor_interface_url = slapparameter_dict.get('monitor-interface-url', 'https://monitor.app.officejs.com') -%}
monitor-setup-url = {{ monitor_interface_url }}/#page=settings_configurator&url=${monitor-publish-parameters:monitor-url}&username=${monitor-publish-parameters:monitor-user}&password=${monitor-publish-parameters:monitor-password}
monitor-password = ${publish-early:monitor-password}
monitor-user = ${monitor-publish-parameters:monitor-user}
{% do part_list.append('monitor-base') -%}
[buildout]
extends =
{{ template_httpd_cfg }}
{{ ' ' ~ template_monitor }}
parts =
httpd
httpd-graceful
httpd-promise
publish-connection-information
directory-doc
# Complete parts with sections
{{ part_list | join('\n ') }}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
instance-kvm-export.cfg.jinja2 0000664 0000000 0000000 00000003032 13454062331 0032671 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm [buildout]
extends =
{{ kvm_template }}
{{ pbsready_export_template }}
parts +=
cron-entry-backup
certificate-authority
certificate-authority-service
publish-connection-information
kvm-vnc-promise
kvm-disk-image-corruption-promise
websockify-sighandler
websockify-sighandler-service
novnc-promise
cron
cron-service
frontend-promise
# monitor parts
monitor-base
# Create the exporter executable, which is a simple shell script
[exporter]
recipe = slapos.recipe.template:jinja2
template = {{ template_kvm_export }}
rendered = ${directory:bin}/${slap-parameter:namebase}-exporter
# Resilient stack wants a "wrapper" parameter
wrapper = ${:rendered}
mode = 0700
context =
section directory directory
section buildout buildout
key socket_path kvm-instance:socket-path
raw gzip_binary {{ gzip_binary }}
# Extends publish section with resilient parameters
[publish-connection-information]
<= resilient-publish-connection-parameter
monitor-base-url = ${monitor-publish:monitor-base-url}
monitor-setup-url = ${monitor-publish:monitor-setup-url}
[monitor-instance-parameter]
monitor-httpd-port = 8026
monitor-title = {{ slapparameter_dict.get('name', 'KVM Standalone') }}
cors-domains = {{ slapparameter_dict.get('monitor-cors-domains', 'monitor.app.officejs.com') }}
{% if slapparameter_dict.get('monitor-username', '') -%}
username = {{ slapparameter_dict['monitor-username'] }}
{% endif -%}
{% if slapparameter_dict.get('monitor-password', '') -%}
password = {{ slapparameter_dict['monitor-password'] }}
{% endif -%}
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/instance-kvm-http.cfg.in 0000664 0000000 0000000 00000003520 13454062331 0031641 0 ustar 00root root 0000000 0000000 [buildout]
parts =
httpd
httpd-graceful
httpd-promise
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
bin = ${buildout:directory}/bin
srv = ${buildout:directory}/srv
public = ${:srv}/public/
log = ${:var}/log
services = ${:etc}/service
scripts = ${:etc}/run
promises = ${:etc}/promise
run = ${:var}/run
document = ${:srv}/document
ssl = ${:etc}/ssl
[apache-conf]
recipe = slapos.recipe.template:jinja2
template = {{ template_apache_conf }}
rendered = ${directory:etc}/apache.conf
ip = ${slap-network-information:global-ipv6}
#ipv4 = ${slap-network-information:local-ipv4}
port = ${slap-parameter:httpd-port}
error-log = ${directory:log}/apache-error.log
access-log = ${directory:log}/apache-access.log
pid-file = ${directory:run}/apache.pid
index = ${directory:public}
root = {:index}
denied-root-access = false
context =
key port :port
key ip :ip
key access_log :access-log
key error_log :error-log
key pid_file :pid-file
key index_folder :index
key cert httpd-ssl:cert
key key httpd-ssl:key
key document_root :root
[httpd]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:services}/httpd
command-line = "{{ apache_location }}/bin/httpd" -f "${apache-conf:rendered}" -DFOREGROUND
[httpd-graceful]
recipe = collective.recipe.template
input = inline:
#!/bin/sh
exec kill -USR1 $(cat ${apache-conf:pid-file})
output = ${directory:scripts}/httpd-graceful
mode = 700
[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]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/apache-httpd
hostname = ${apache-conf:ip}
port = ${apache-conf:port} instance-kvm-import.cfg.jinja2.in 0000664 0000000 0000000 00000004762 13454062331 0033302 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm [buildout]
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
parts +=
kvm-disk-image-corruption-promise
# Here, we don't need KVM to run to import data, so we don't
# even extend the kvm instance profile.
extends =
{{ pbsready_import_template }}
[resilient-publish-connection-parameter]
monitor-base-url = ${monitor-publish-parameters:monitor-base-url}
monitor-url = ${monitor-publish-parameters:monitor-url}
monitor-user = ${monitor-publish-parameters:monitor-user}
monitor-password = ${monitor-publish-parameters:monitor-password}
[monitor-instance-parameter]
monitor-httpd-port = 8276
monitor-title = {{ slapparameter_dict.get('name', 'Kvm Resilient clone') }}
cors-domains = {{ slapparameter_dict.get('monitor-cors-domains', '') }}
{% if slapparameter_dict.get('monitor-username', '') -%}
username = {{ slapparameter_dict['monitor-username'] }}
{% endif -%}
{% if slapparameter_dict.get('monitor-password', '') -%}
password = {{ slapparameter_dict['monitor-password'] }}
{% endif -%}
instance-configuration =
raw takeover-url ${resilient-publish-connection-parameter:takeover-url}
raw takeover-password ${resilient-publish-connection-parameter:takeover-password}
[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
cron-entries = ${:etc}/cron.d
crontabs = ${:etc}/crontabs
cronstamps = ${:etc}/cronstamps
[importer]
recipe = slapos.recipe.template:jinja2
template = {{ template_kvm_import }}
rendered = ${directory:bin}/${slap-parameter:namebase}-importer
mode = 0700
# Resilient stack wants a "wrapper" parameter
wrapper = ${:rendered}
context =
section directory directory
raw zcat_binary {{ zcat_binary }}
raw gzip_binary {{ gzip_binary }}
backup-disk-path = ${directory:backup}/virtual.qcow2
[kvm-disk-image-corruption-promise]
# Check that disk image is not corrupted
recipe = collective.recipe.template
input = inline:#!/bin/sh
QEMU_IMAGE="${directory:srv}/virtual.qcow2"
if [ ! -s "$QEMU_IMAGE" ]; then
exit 0
fi
{{ qemu_location }}/bin/qemu-img check $QEMU_IMAGE
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 instance-kvm-input-schema.json 0000664 0000000 0000000 00000031440 13454062331 0033007 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"enable-device-hotplug": {
"title": "Enable device hotplug mode",
"description": "If yes, this will allow to Create devices like CPU and Memory in hotplug mode without restart the VM. Operatin System should be configured to Online new created devices.",
"type": "boolean",
"default": false
},
"ram-size": {
"title": "RAM size",
"description": "RAM size, in MB.",
"type": "integer",
"default": 1024,
"minimum": 1024,
"multipleOf": 512
},
"ram-max-size": {
"title": "Maximum RAM size, in MB",
"description": "Define the maximum size of the memory. The size is in MB and should be a multiple of 512.",
"type": "integer",
"default": 51200,
"minimum": 1024,
"multipleOf": 512
},
"ram-hotplug-slot-size": {
"title": "Size of Hotpluggable RAM slot, in MB",
"description": "Define the RAM size to plug on one hotpluggable slot in MB, understand the size of one RAM bar. The RAM hotplugged on each slot will always have the same RAM size.",
"type": "integer",
"default": 512,
"minimum": 512,
"multipleOf": 512
},
"auto-ballooning": {
"title": "Enable qemu auto ballooning.",
"description": "Enable virtio balloon device to allows KVM guests to reduce/re-increase their memory size.",
"type": "boolean",
"default": true
},
"disk-size": {
"title": "Disk size",
"description": "Disk size, in GB.",
"type": "integer",
"default": 10,
"minimum": 1,
"maximum": 1000
},
"disk-type": {
"title": "Disk type",
"description": "Type of QEMU disk drive.",
"type": "string",
"default": "virtio",
"enum": [
"ide",
"scsi",
"sd",
"mtd",
"floppy",
"pflash",
"virtio"
]
},
"disk-format": {
"title": "Type of disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
},
"disk-cache": {
"title": "Cache option to use with Disk.",
"description": "Disk cache controls how the host cache is used to access block data.",
"type": "string",
"default": "writeback",
"enum": [
"none",
"writeback",
"unsafe",
"directsync",
"writethrough"
]
},
"disk-aio": {
"title": "Disk aio to use.",
"description": "Selects between pthread based disk I/O and native Linux AIO.",
"type": "string",
"default": "threads",
"enum": [
"threads",
"native"
]
},
"cpu-count": {
"title": "CPU count",
"description": "Number of CPU cores.",
"type": "integer",
"minimum": 1
},
"cpu-max-count": {
"title": "Maximum CPU amount",
"description": "Specifies the maximum number of CPUs.",
"type": "integer",
"default": 24,
"minimum": 1,
"maximum": 64
},
"numa": {
"title": "Simulate a multi node NUMA system.",
"description": "Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. Each numa option are separated by space: node,nodeid=4,cpus=40-49,mem=64g node,nodeid=1,cpus=10-19,mem=128g. Set this option if you know what you're doing.",
"type": "string"
},
"machine-options": {
"title": "Machine options.",
"description": "Select the emulated machine by name. Ex: pc-i440fx-2.4,accel=kvm",
"type": "string"
},
"cpu-model": {
"title": "CPU model.",
"description": "Select the emulated CPU model. Ex: SandyBridge,+erms,+smep,+smx,+vmx",
"type": "string",
"default": "host"
},
"keyboard-layout-language": {
"title": "Use keyboard layout language",
"description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display",
"type": "string",
"enum": [
"ar",
"da",
"de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr"
],
"default": "fr"
},
"nbd-host": {
"title": "NBD hostname",
"description": "hostname (or IP) of the NBD server containing the boot image.",
"type": "string",
"format": "internet-address",
"default": "debian.nbd.vifib.net"
},
"nbd-port": {
"title": "NBD port",
"description": "Port of the NBD server containing the boot image.",
"type": "integer",
"default": 1024,
"minimum": 1,
"maximum": 65535
},
"nbd2-host": {
"title": "Second NBD hostname",
"description": "hostname (or IP) of the second NBD server (containing drivers for example).",
"type": "string",
"format": "internet-address"
},
"nbd2-port": {
"title": "Second NBD port",
"description": "Port of the second NBD server containing the boot image.",
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"virtual-hard-drive-url": {
"title": "Existing disk image URL",
"description": "If specified, will download an existing disk image (qcow2, raw, ...), and will use it as main virtual hard drive. Can be used to download and use an already installed and customized virtual hard drive.",
"format": "uri",
"type": "string"
},
"virtual-hard-drive-md5sum": {
"title": "Checksum of virtual hard drive",
"description": "MD5 checksum of virtual hard drive, used if virtual-hard-drive-url is specified.",
"type": "string"
},
"virtual-hard-drive-gzipped": {
"title": "Define if virtual hard drive to download is gzipped",
"description": "Define if virtual hard drive to download is gzipped using gzip. This help to reduce size of file to download.",
"type": "boolean",
"default": false
},
"hard-drive-url-check-certificate": {
"title": "Check certificate when downloading virtual hard drive from https.",
"description": "Define if certificate should be checked when downloading virtual hard drive from https url.",
"type": "boolean",
"default": true
},
"external-disk-number": {
"title": "Number of additional disk to create for virtual machine",
"description": "Specify the number of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.",
"type": "integer",
"minimum": 0,
"default": 0
},
"external-disk-size": {
"title": "Size of additional disk to create for virtual machine, in Gigabytes",
"description": "Specify the size of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.",
"type": "integer",
"minimum": 10,
"maximum": 1000,
"default": 20
},
"external-disk-format": {
"title": "Type of external disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.",
"type": "string",
"default": "qcow2",
"enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
},
"wipe-disk-ondestroy": {
"title": "Wipe disks when destroy the VM",
"description": "Say if disks should be wiped by writing new data over every single bit before delete them. This option is used to securely delete VM disks",
"type": "boolean",
"default": false
},
"wipe-disk-iterations": {
"title": "Wipe disk iterations",
"description": "Number of disk overwrite iterations with random data. Default is 1. WARNING: Increase this value will slow down partition destruction and increase IO.",
"type": "integer",
"default": 1,
"minimum": 1,
"maximum": 5
},
"use-tap": {
"title": "Use QEMU TAP network interface",
"description": "Use QEMU TAP network interface, requires taps creation on SlapOS Node.",
"type": "boolean",
"default": true
},
"use-nat": {
"title": "Use QEMU USER Mode interface (NAT)",
"description": "Use QEMU user-mode network stack (NAT).",
"type": "boolean",
"default": true
},
"nat-rules": {
"title": "List of rules for NAT of QEMU user mode network stack.",
"description": "List of rules for NAT of QEMU user mode network stack, as space-separated list of ports (with optional protocol). For each port specified, it will redirect port x of the VM (example: \"80 udp:53\") to the port x + 10000 of the public IPv6 of the host (example: \"10080 udp:10053\").",
"type": "string",
"default": "22 80 443"
},
"nat-restrict-mode": {
"title": "Isolate the NAT Interface (No Internet access)",
"description": "If this option is enabled, the NAT interface will be isolated, i.e. it will not be able to contact the host and no guest IP packets will be routed over the host to the outside. This option does not affect any explicitly set nat rules.",
"type": "boolean",
"default": false
},
"enable-vhost": {
"title": "Use vhost-net to improve network performance of tap interface",
"description": "The vhost-net provides much improved network performance for your VM. Only work if the vhost-net kernel module is loaded and available on host machine, please keep this option off if you're not shure.",
"type": "boolean",
"default": false
},
"monitor-interface-url": {
"title": "Monitor Web Interface URL",
"description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"type": "string",
"format": "uri",
"default": "https://monitor.app.officejs.com"
},
"monitor-cors-domains": {
"title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string",
"default": "monitor.app.officejs.com"
},
"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": {
"title": "Public keys to get from all virtual machines.",
"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"
},
"bootstrap-script-url": {
"title": "VM bootstrap script URL.",
"description": "If dedicaced disk image is used, this script will be downloaded and run at first boot of the virtual machine. Set md5sum to URL like: http://example.com/file#MD5SUM. Get file in vm at http://10.0.2.100/vm-bootstrap.",
"type": "string",
"format": "uri"
},
"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"
},
"frontend-instance-guid": {
"title": "Frontend Instance ID",
"description": "Unique identifier of the frontend instance, like \"SOFTINST-11031\".",
"type": "string",
"default": "SOFTINST-11031"
},
"frontend-software-type": {
"title": "Frontend Software Type",
"description": "Type of the frontend instance, like \"frontend\".",
"type": "string",
"default": "frontend"
},
"frontend-software-url": {
"title": "Frontend Software URL",
"description": "Software Release URL of the frontend instance, like \"http://example.com/path/to/software.cfg\".",
"type": "string",
"format": "uri",
"default": "https://lab.nexedi.com/nexedi/slapos/raw/slapos-0.92/software/kvm/software.cfg"
}
}
}
instance-kvm-output-schema.json 0000664 0000000 0000000 00000000704 13454062331 0033207 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {
"name": "Output Parameters",
"properties": {
"backend-url": {
"title": "Backend URL",
"description": "URL used to connect directly to backend without frontend. Requires IPv6.",
"type": "string",
"format": "uri",
"require": true
},
"url": {
"title": "URL",
"description": "URL used to connect to the service.",
"type": "string",
"format": "uri",
"require": false
}
}
}
instance-kvm-resilient-input-schema.json 0000664 0000000 0000000 00000004671 13454062331 0035011 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm {
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"allOf": [
{
"$ref": "instance-kvm-input-schema.json#/"
},
{
"properties": {
"resilient-clone-number": {
"title": "Amount of backup(s) to create",
"description": "Amount of backup(s) to create. Each backup consists of a Pull Backup Server and a clone.",
"type": "integer",
"default": 1,
"optional": true
},
"-sla-0-computer_guid": {
"title": "Target computer for main instance",
"description": "Target computer GUID for main instance.",
"type": "string",
"optional": true
},
"-sla-1-computer_guid": {
"title": "Target computer for first clone",
"description": "Target computer for first clone and PBS.",
"type": "string",
"optional": true
},
"-sla-pbs1-computer_guid": {
"title": "Target computer for first PBS",
"description": "Target computer for first PBS instance.",
"type": "string",
"optional": true
},
"-sla-2-computer_guid": {
"title": "Target computer for second clone",
"description": "Target computer for second clone and PBS.",
"type": "string",
"optional": true
},
"-sla-pbs2-computer_guid": {
"title": "Target computer for second PBS",
"description": "Target computer for second PBS instance.",
"type": "string",
"optional": true
},
"resiliency-backup-periodicity": {
"title": "Periodicity of backup",
"description": "Periodicity of backup, in cron format.",
"type": "string",
"optional": true
},
"remove-backup-older-than": {
"title": "Remove backups older than...",
"description": "Remove all the backups in PBS that are older than specified value. It should be rdiff-backup-compatible.",
"type": "string",
"default": "2W",
"optional": true
},
"ignore-known-hosts-file": {
"title": "Ignore known_hosts file",
"description": "Set either to fill known_hosts file for ssh or not. Useful if main instance and PBS are using the same IP (slapos proxy, webrunner).",
"type": "boolean",
"default": false,
"optional": true
}
}
}
]
}
instance-kvm-resilient.cfg.jinja2 0000664 0000000 0000000 00000007225 13454062331 0033356 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm # vim: set ft=cfg:
{% import 'parts' as parts %}
{% import 'replicated' as replicated with context %}
{% set backup_amount = slapparameter_dict.pop('resilient-clone-number', "1")|int + 1 -%}
{% set monitor_dict = {} -%}
{% set monitor_return = [] -%}
{% if slapparameter_dict.get('enable-monitor', True) == True -%}
{% set monitor_return = ['monitor-base-url'] -%}
{% set monitor_parameter = {'monitor-cors-domains': slapparameter_dict.pop('monitor-cors-domains', "monitor.app.officejs.com")} -%}
{% set monitor_dict = {'parameter': monitor_parameter, 'return': monitor_return} -%}
{% endif -%}
{% set monitor_interface_url = slapparameter_dict.pop('monitor-interface-url', 'https://monitor.app.officejs.com') -%}
[buildout]
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
# += because we need to take up parts (like instance-custom, slapmonitor etc) from the profile we extended
parts +=
publish-early
{{ parts.replicate("kvm", backup_amount) }}
publish-connection-information
kvm-frontend-url-promise
kvm-backend-url-promise
{% if monitor_dict -%}
extends = {{ template_monitor }}
[monitor-htpasswd]
recipe = slapos.cookbook:generate.password
storage-path = ${directory:etc}/.monitor_user
bytes = 8
username = admin
[publish-early]
recipe = slapos.cookbook:publish-early
-init =
monitor-password monitor-htpasswd:passwd
# XXX Monitoring Main Instane
[monitor-instance-parameter]
monitor-httpd-port = 8160
password = ${publish-early:monitor-password}
cors-domains = {{ monitor_parameter.get('monitor-cors-domains', '') }}
{% do monitor_parameter.__setitem__('monitor-username', slapparameter_dict.get('monitor-username', 'admin'))%}
{% do monitor_parameter.__setitem__('monitor-password', slapparameter_dict.get('monitor-password', '${publish-early:monitor-password}'))%}
{% endif -%}
{{ replicated.replicate("kvm", backup_amount, "kvm-export", "kvm-import", slapparameter_dict=slapparameter_dict, monitor_parameter_dict=monitor_dict) }}
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
promises = ${:etc}/promise
# Bubble down the parameters of the requested instance to the user
[request-kvm]
# Note: += doesn't work.
return =
# Resilient related parameters
url ssh-public-key ssh-url notification-id ip {{ monitor_return | join(' ') }}
# KVM related parameters
# XXX: return ALL parameters (like nat rules), through jinja
backend-url url ip
{{ ' ' }}ipv6-network-info
[publish-connection-information]
recipe = slapos.cookbook:publish
backend-url = ${request-kvm:connection-backend-url}
url = ${request-kvm:connection-url}
ipv6 = ${request-kvm:connection-ip}
ipv6-network-info = ${request-kvm:connection-ipv6-network-info}
monitor-password = ${publish-early:monitor-password}
monitor-user = ${monitor-publish-parameters:monitor-user}
{% if monitor_dict -%}
monitor-base-url = ${monitor-publish-parameters:monitor-base-url}
monitor-setup-url = {{ monitor_interface_url }}/#page=settings_configurator&url=${monitor-publish-parameters:monitor-url}&username=${monitor-publish-parameters:monitor-user}&password=${publish-early:monitor-password}
{% endif -%}
[kvm-frontend-url-promise]
# Check that url parameter is complete
recipe = collective.recipe.template
input = inline:#!/bin/sh
URL="${request-kvm:connection-url}"
if [[ ! "$URL" == https://* ]]; then
exit 1
fi
output = ${resilient-directory:promise}/kvm-frontend-url
mode = 700
[kvm-backend-url-promise]
# Check that backend url is reachable
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/frontend_promise
url = ${publish-connection-information:url}
dash_path = /bin/sh
curl_path = {{ curl_executable_location }}
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/instance-kvm.cfg.jinja2 0000664 0000000 0000000 00000064726 13454062331 0031452 0 ustar 00root root 0000000 0000000 {% set enable_http = slapparameter_dict.get('enable-http-server', 'False').lower() -%}
{% set use_tap = slapparameter_dict.get('use-tap', 'True').lower() -%}
{% set use_nat = slapparameter_dict.get('use-nat', 'True').lower() -%}
{% set wipe_disk = slapparameter_dict.get('wipe-disk-ondestroy', 'False').lower() -%}
{% set nat_restrict = slapparameter_dict.get('nat-restrict-mode', 'False').lower() -%}
{% set name = slapparameter_dict.get('name', 'localhost') -%}
{% set disable_ansible_promise = slapparameter_dict.get('disable-ansible-promise', 'True').lower() -%}
{% set enable_device_hotplug = slapparameter_dict.get('enable-device-hotplug', 'false').lower() -%}
{% set instance_type = slapparameter_dict.get('type', 'standalone') -%}
{% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') -%}
{% set frontend_software_type = 'default' -%}
{% set disk_device_path = slapparameter_dict.get('disk-device-path', None) -%}
{% set extends_list = [] -%}
{% set part_list = [] -%}
{% set bootstrap_url = '' -%}
{% set bootstrap_url_md5sum = '' -%}
{% if slapparameter_dict.get('bootstrap-script-url', '') -%}
{% set url_info_list = slapparameter_dict['bootstrap-script-url'].split('#') -%}
{% set bootstrap_url = url_info_list[0] -%}
{% set bootstrap_url_md5sum = url_info_list[1] -%}
{% endif -%}
{% if instance_type == 'cluster' -%}
{% set nat_rule_list = slapparameter_dict.get('nat-rules', '') %}
{% endif -%}
{% if not nat_rule_list or not nat_rule_list.strip() -%}
{% set nat_rule_list = '' %}
{% endif -%}
{% do extends_list.append(template_monitor) -%}
{% 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
prerm = ${:etc}/prerm
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_eggs_executable }}
vnc-passwd = ${gen-passwd:passwd}
socket-path = ${directory:var}/qmp_socket
pid-file = ${directory:run}/pid_file
kvm-status-path = ${directory:var}/qemu-vm-is-ready
cpu-count = ${slap-parameter:cpu-count}
cpu-model = ${slap-parameter:cpu-model}
ram-hotplug-slot-size = ${slap-parameter:ram-hotplug-slot-size}
ram-size = ${slap-parameter:ram-size}
enable-device-hotplug = ${slap-parameter:enable-device-hotplug}
[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_configuration.get('tap-name', '') }}
disk-size = ${slap-parameter:disk-size}
disk-type = ${slap-parameter:disk-type}
disk-format = ${slap-parameter:disk-format}
disk-device-path = ${slap-parameter:disk-device-path}
disk-path = ${directory:srv}/virtual.${slap-parameter:disk-format}
pid-file-path = ${kvm-controller-parameter-dict:pid-file}
socket-path = ${kvm-controller-parameter-dict:socket-path}
enable-device-hotplug = ${kvm-controller-parameter-dict:enable-device-hotplug}
smp-count = ${kvm-controller-parameter-dict:cpu-count}
smp-max-count = ${slap-parameter:cpu-max-count}
ram-size = ${kvm-controller-parameter-dict:ram-size}
ram-max-size = ${slap-parameter:ram-max-size}
init-ram-size = 1024
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 = {{ nat_rule_list }}
nat-restrict= {{ nat_restrict }}
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' -%}
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}
name = {{ slapparameter_dict.get('name', 'Single KVM') }}
disk-cache = ${slap-parameter:disk-cache}
disk-aio = ${slap-parameter:disk-aio}
auto-ballooning = ${slap-parameter:auto-ballooning}
machine-options = ${slap-parameter:machine-options}
cpu-model = ${slap-parameter:cpu-model}
log-file = ${directory:log}/qemu.log
[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-controller]
recipe = slapos.recipe.template:jinja2
template = {{ template_kvm_controller_run }}
rendered = ${directory:bin}/kvm_controller_raw
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}
hash-files = ${buildout:directory}/software_release/buildout.cfg
{% if use_nat == 'true' and nat_rule_list -%}
{% for port in nat_rule_list.split(' ') -%}
{% if ':' in port -%}
{% set proto, port = port.split(':') -%}
{% else -%}
{% set proto, port = 'tcp', port -%}
{% endif -%}
{% set external_port = 10000 + port|int() -%}
{% set section_name = '6tunnel-' ~ proto ~ '-' ~ 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-controller-wrapper:wrapper-path}
hash-files = ${buildout:directory}/software_release/buildout.cfg
[kvm-controller-wrapper]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:scripts}/kvm_controller
command-line = ${kvm-controller: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
if [ "${slap-parameter:disk-device-path}" != "" ]; then
# disk device option is used, skip qemu img check
exit 0
fi
${kvm-parameter-dict:qemu-img-path} check -U ${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
{% if wipe_disk == 'true' -%}
{% do part_list.append('wipe-disk-wrapper') -%}
{% set wipe_file_list = '${kvm-parameter-dict:disk-path}' -%}
{% if storage_dict -%}
{% set wipe_file_list = '${kvm-parameter-dict:disk-path}' ~ ' ' ~ '/* '.join(storage_dict.values()) ~ '/*' -%}
{% endif -%}
[wipe-disk-wrapper]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:prerm}/slapos_wipe_qemu_disk
command-line =
{{ wipe_disk_wrapper }} -n {{ slapparameter_dict.get('wipe-disk-iterations', 1) }} -suz --check-pid-file ${kvm-parameter-dict:pid-file-path} --file {{ wipe_file_list }}
{% endif -%}
[kvm-started-promise]
recipe = slapos.recipe.template:jinja2
template = {{ qemu_start_promise_tpl }}
rendered = ${directory:promises}/qemu-virtual-machine-is-ready
mode = 700
context =
raw dash {{ dash_executable_location }}
raw qemu_ready_path ${kvm-controller-parameter-dict:kvm-status-path}
raw qemu_service_log_file ${buildout:directory}/.${slap-connection:partition-id}_kvm.log
[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:bin}/websockify-sighandler
wrapped-path = ${novnc-instance:path}
[websockify-sighandler-service]
recipe = slapos.cookbook:wrapper
command-line = ${websockify-sighandler:wrapper-path}
wrapper-path = ${directory:services}/websockify
hash-files = ${buildout:directory}/software_release/buildout.cfg
wait-for-files =
${ca-novnc:key-file}
${ca-novnc:cert-file}
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = {{ openssl_executable_location }}
ca-dir = ${directory:ca-dir}
requests-directory = ${cadirectory:requests}
wrapper = ${directory:bin}/certificate_authority
ca-private = ${cadirectory:private}
ca-certs = ${cadirectory:certs}
ca-newcerts = ${cadirectory:newcerts}
ca-crl = ${cadirectory:crl}
[certificate-authority-service]
recipe = slapos.cookbook:wrapper
command-line = ${certificate-authority:wrapper}
wrapper-path = ${directory:services}/certificate_authority
hash-files = ${buildout:directory}/software_release/buildout.cfg
[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:bin}/crond_raw
[cron-service]
recipe = slapos.cookbook:wrapper
command-line = ${cron:binary}
wrapper-path = ${directory:services}/crond
hash-files = ${buildout:directory}/software_release/buildout.cfg
[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:bin}/http-server
log-file = ${directory:log}/httpd.log
use-hash-url = false
[httpd-service]
recipe = slapos.cookbook:wrapper
command-line = ${httpd:wrapper}
wrapper-path = ${directory:services}/http-server
hash-files = ${buildout:directory}/software_release/buildout.cfg
[httpd-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/httpd
hostname = ${httpd:host}
port = ${httpd:port}
{% endif %}
[monitor-instance-parameter]
monitor-httpd-port = 8026
monitor-title = {{ slapparameter_dict.get('name', 'KVM Standalone') }}
cors-domains = {{ slapparameter_dict.get('monitor-cors-domains', 'monitor.app.officejs.com') }}
{% if slapparameter_dict.get('monitor-username', '') -%}
username = {{ slapparameter_dict['monitor-username'] }}
{% endif -%}
{% if slapparameter_dict.get('monitor-password', '') -%}
password = {{ slapparameter_dict['monitor-password'] }}
{% endif -%}
interface-url = {{ slapparameter_dict.get('monitor-interface-url', 'https://monitor.app.officejs.com') }}
# this helper just gives a blank line to insert in multiline values
[helper]
blank-line =
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish
ipv6 = ${slap-network-information:global-ipv6}
backend-url = https://[${novnc-instance:ip}]:${novnc-instance:port}/vnc.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.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 = 'ens3' -%}
{% if use_nat == 'true' -%}
{% set iface = 'ens4' -%}
{% if nat_rule_list -%}
# Publish NAT port mapping status
{% for port in nat_rule_list.split(' ') -%}
{% if ':' in port -%}
{% set proto, port = port.split(':') -%}
{% else -%}
{% set proto, port = 'tcp', port -%}
{% endif -%}
{% set external_port = 10000 + port|int() -%}
nat-rule-port-{{proto}}-{{port}} = ${slap-network-information:global-ipv6} : ${6tunnel-{{proto}}-{{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 -%}
{% endif -%}
{% if use_tap == 'true' -%}
tap-ipv4 = {{ slap_configuration.get('tap-ipv4-addr', '') }}
tap-ipv6 = {{ slap_configuration.get('tap-ipv6-addr', '') }}
{% 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', '') and slapparameter_dict.get('type', '') == 'cluster' -%}
key_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/authorized_keys
{% endif %}
{% endif %}
{% if use_tap == 'true' and slap_configuration.get('tap-ipv4-addr') -%}
ipv4-network-info =
Use this configuration in /etc/network/interfaces to configure IPv4 on interface {{ iface }} in your VM.
auto {{ iface }}
iface {{ iface }} inet static
address {{ slap_configuration.get('tap-ipv4-addr') }}
netmask {{ slap_configuration.get('tap-ipv4-netmask') }}
gateway {{ slap_configuration.get('tap-ipv4-gateway') }}
{% if enable_http == 'true' %}
${helper:blank-line}
Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh -
{% endif %}
{% endif %}
ipv6-network-info =
{% if use_tap == 'true' and slap_configuration.get('tap-ipv6-addr') %}
Use this configuration in /etc/network/interfaces to configure IPv6 on interface {{ iface }} in your VM.
auto {{ iface }}
iface {{ iface }} inet6 static
address {{ slap_configuration.get('tap-ipv6-gateway') }}
netmask {{ slap_configuration.get('tap-ipv6-network').split('/')[1] }}
gateway {{ slap_configuration.get('tap-ipv6-addr') }}
{% if enable_http == 'true' %}
${helper:blank-line}
Or run in your VM the command: wget -O- {{ kvm_http }}/${network-config-ipv6:filename} | /bin/sh -
{% endif %}
{% endif %}
{% if use_tap == 'true' and slap_configuration.get('tap-ipv4-addr') -%}
[network-config-ipv4]
recipe = plone.recipe.command
path = ${directory:public}/netconfig.sh
ifconfig = ifconfig \$IFACE {{ slap_configuration.get('tap-ipv4-addr') }} netmask {{ slap_configuration.get('tap-ipv4-netmask') }}
route-iface = route add {{ slap_configuration.get('tap-ipv4-gateway') }} dev \$IFACE
route-network = route add -net {{ slap_configuration.get('tap-ipv4-network') }} netmask {{ slap_configuration.get('tap-ipv4-netmask') }} gw {{ slap_configuration.get('tap-ipv4-gateway') }}
{% if nat_restrict == 'true' -%}
route-default = route add default gw {{ slap_configuration.get('tap-ipv4-gateway') }} dev \$IFACE
{% elif global_ipv4_prefix -%}
route-default = ip route add {{ global_ipv4_prefix }} via {{ slap_configuration.get('tap-ipv4-gateway') }} dev \$IFACE src {{ slap_configuration.get('tap-ipv4-addr') }}
{% else -%}
route-default =
{% endif -%}
command =
cat > ${:path} << EOF
#!/bin/sh
IFACE={{ iface }}
#try to be compatible with OS with old names
ip a | grep eth0: && [ \$IFACE = ens3 ] && IFACE=eth0
ip a | grep eth1: && [ \$IFACE = ens4 ] && IFACE=eth1
${:ifconfig}
${:route-iface}
${:route-network}
${:route-default}
EOF
update-command = ${:command}
{% endif -%}
{% if use_tap == 'true' and slap_configuration.get('tap-ipv6-addr') -%}
[network-config-ipv6]
recipe = plone.recipe.command
filename = ipv6_config.sh
path = ${directory:public}/${:filename}
ipv6-add-address = ip -6 address add {{ slap_configuration.get('tap-ipv6-gateway') }}/{{ slap_configuration.get('tap-ipv6-network').split('/')[1] }} dev \$IFACE
ipv6-add-default-route =
ip -6 route del default ; ip -6 route add default dev \$IFACE via {{ slap_configuration.get('tap-ipv6-addr') }}
ipv6-set-link-up = ip link set dev \$IFACE up
command =
cat > ${:path} << EOF
#!/bin/sh
IFACE={{ iface }}
${:ipv6-add-address}
${:ipv6-add-default-route}
${:ipv6-set-link-up}
EOF
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') }}
{% if slapparameter_dict.get('authorized-key', '') -%}
# write public key for vms to public/authorized_keys
{{ writefile('get-authorized-key', '${directory:public}/authorized_keys', slapparameter_dict.get('authorized-key', ''), '700') }}
{% endif -%}
{% if use_tap == 'true' and nat_restrict == 'true' -%}
# Ask to set default to tap interface in the vm
{{ writefile('set-default-interface', '${directory:public}/delDefaultIface', iface, '600') }}
{% do part_list.append('set-default-interface') -%}
{% endif -%}
[publish-host-config]
recipe = plone.recipe.command
name = {{ slapparameter_dict.get('name', 'localhost') }}
{% if use_tap == 'true' and slap_configuration.get('tap-ipv4-addr') -%}
local-ipv4 = {{ slap_configuration['tap-ipv4-addr'] }}
gateway = {{ slap_configuration.get('tap-ipv4-gateway') }}
netmask = {{ slap_configuration.get('tap-ipv4-network') }}
network = {{ slap_configuration.get('tap-ipv4-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:bin}/6tunnel-cluster
[tunnel-cluster-service]
recipe = slapos.cookbook:wrapper
command-line = ${tunnel-cluster-url:runner-path}
wrapper-path = ${directory:services}/6tunnel-cluster
hash-files = ${buildout:directory}/software_release/buildout.cfg
[ansible-vm-promise]
recipe = slapos.recipe.template:jinja2
template = {{ ansible_promise_tpl }}
rendered = ${directory:promises}/ansible_{{ name }}
extensions = jinja2.ext.do
context =
raw logs ${directory:public}/ansible
raw name {{ name }}
[download-bootstrap-script]
recipe = plone.recipe.command
file-location = ${directory:public}/vm-bootstrap
command = {{ python_executable }} {{ file_download_script }} {{ bootstrap_url }} {{ bootstrap_url_md5sum }} ${:file-location}
update-command =
stop-on-error = true
[logrotate-vm-bootstrap]
< = logrotate-entry-base
name = vm-bootstrap
log = ${directory:public}/ansible/vm-bootstrap.log
[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 =
enable-device-hotplug = False
ram-size = 1024
ram-max-size = 51200
ram-hotplug-slot-size = 512
disk-size = 10
disk-type = virtio
disk-format = qcow2
disk-device-path =
cpu-count = 1
cpu-max-count = 24
disk-cache = writeback
disk-aio = native
auto-ballooning = True
machine-options =
cpu-model = host
nat-rules = 22 80 443
use-nat = True
use-tap = True
nat-restrict-mode = 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 (Change to en-us if you face some bad bihaviors)
keyboard-layout-language = fr
#############################
#
# Instanciate kvm (Buildout Section)
#
#############################
{% if slapparameter_dict.get('document-host', '') %}
# Set Additionals parts
{% do part_list.append('cluster-url-path') -%}
{% endif -%}
{% if enable_http == 'true' %}
{% do part_list.extend(['httpd', 'httpd-service', 'httpd-promise', 'publish-host-config']) -%}
{% if slapparameter_dict.get('data-to-vm', '') %}
{% do part_list.append('vm-data-content') -%}
{% endif -%}
{% if disable_ansible_promise == 'false' %}
{% do part_list.extend(['ansible-vm-promise', 'logrotate-vm-bootstrap']) -%}
{% endif -%}
{% if slapparameter_dict.get('authorized-key', '') and slapparameter_dict.get('type', '') == 'cluster' %}
{% do part_list.append('get-authorized-key') -%}
{% endif -%}
{% if slapparameter_dict.get('bootstrap-script-url', '') -%}
{% do part_list.append('download-bootstrap-script') -%}
{% endif -%}
{% if slapparameter_dict.get('document-port', '') -%}
{% do part_list.append('tunnel-cluster-service') -%}
{% endif -%}
{% endif -%}
{% if disk_device_path %}
{% do part_list.append('disk-device-permission') -%}
[disk-device-permission]
recipe = slapos.recipe.template:jinja2
template = inline:
{%- raw %}
[{"disk": "{{disk_device_path}}"}]
{% endraw -%}
rendered = ${buildout:directory}/.slapos-disk-permission
context =
raw disk_device_path {{disk_device_path}}
{% endif -%}
[buildout]
parts =
certificate-authority
certificate-authority-service
publish-connection-information
kvm-instance
kvm-controller-wrapper
kvm-vnc-promise
kvm-disk-image-corruption-promise
websockify-sighandler
websockify-sighandler-service
novnc-promise
kvm-started-promise
cron
cron-service
cron-entry-logrotate
frontend-promise
# monitor parts
monitor-base
# 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
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/instance-nbd.cfg.in 0000664 0000000 0000000 00000004110 13454062331 0030626 0 ustar 00root root 0000000 0000000 #############################
#
# Instanciate nbdserver
#
#############################
[buildout]
parts =
nbd-promise
onetimeupload-promise
publish-connection-information
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
srv = $${buildout:directory}/srv
log = $${buildout:directory}/log
[basedirectory]
recipe = slapos.cookbook:mkdirectory
services = $${rootdirectory:etc}/run
watched-services = $${rootdirectory:etc}/service
promises = $${rootdirectory:etc}/promise
[nbd-instance]
recipe = slapos.cookbook:nbdserver
ip = $${slap-network-information:global-ipv6}
port = 1024
image-path = $${onetimeupload-instance:image-path}
qemu-path = ${kvm:location}/bin/qemu-nbd
shell-path = ${dash:location}/bin/dash
# XXX TODO: Wait for the iso to be uploaded (execute_wait)
path = $${basedirectory:services}/nbdserver
[nbd-promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/nbd_promise
hostname = $${nbd-instance:ip}
port = $${nbd-instance:port}
[gen-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:srv}/passwd
bytes = 24
[onetimeupload-instance]
recipe = slapos.cookbook:onetimeupload
ip = $${slap-network-information:global-ipv6}
port = 8080
image-path = $${rootdirectory:srv}/cdrom.iso
log-path = $${rootdirectory:log}/onetimeupload.log
shell-path = ${dash:location}/bin/dash
onetimeupload-path = ${buildout:bin-directory}/onetimeupload
path = $${basedirectory:watched-services}/onetimeupload
key = $${gen-passwd:passwd}
[onetimeupload-promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/onetimeupload_promise
hostname = $${onetimeupload-instance:ip}
port = $${onetimeupload-instance:port}
[publish-connection-information]
recipe = slapos.cookbook:publish
nbd_url = nbd://[$${nbd-instance:ip}]:$${nbd-instance:port}
upload_url = http://[$${onetimeupload-instance:ip}]:$${onetimeupload-instance:port}/
upload_key = $${onetimeupload-instance:key}
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/instance.cfg.in 0000664 0000000 0000000 00000014634 13454062331 0030101 0 ustar 00root root 0000000 0000000 [buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
extends = ${template-resilient-templates:output}
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = $${:kvm}
kvm-cluster = $${dynamic-template-kvm-cluster:rendered}
kvm = $${dynamic-template-kvm:rendered}
nbd = ${template-nbd:output}
frontend = ${template-frontend:output}
kvm-resilient = $${dynamic-template-kvm-resilient:rendered}
kvm-import = $${dynamic-template-kvm-import:rendered}
kvm-export = $${dynamic-template-kvm-export:rendered}
frozen = ${instance-frozen:output}
pull-backup = ${template-pull-backup:output}
# XXX - If this configuration is not generated by slapgrid, use empty values
[storage-configuration]
storage-home =
[network-information]
global-ipv4-network =
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = $${slap-connection:computer-id}
partition = $${slap-connection:partition-id}
url = $${slap-connection:server-url}
key = $${slap-connection:key-file}
cert = $${slap-connection:cert-file}
storage-home = $${storage-configuration:storage-home}
[jinja2-template-base]
recipe = slapos.recipe.template:jinja2
rendered = $${buildout:directory}/$${:filename}
extensions = jinja2.ext.do
mode = 0644
extra-context =
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key ipv4 slap-configuration:ipv4
key ipv6 slap-configuration:ipv6
key global_ipv4_prefix network-information:global-ipv4-network
key storage_dict slap-configuration:storage-dict
key slapparameter_dict slap-configuration:configuration
key computer_id slap-configuration:computer
raw openssl_executable_location ${openssl:location}/bin/openssl
$${:extra-context}
[dynamic-template-kvm-cluster-parameters]
[dynamic-template-kvm-cluster]
<= jinja2-template-base
template = ${template-kvm-cluster:location}/instance-kvm-cluster.cfg.jinja2.in
filename = template-kvm-cluster.cfg
extra-context =
section parameter_dict dynamic-template-kvm-cluster-parameters
raw logrotate_cfg ${template-logrotate-base:rendered}
raw template_content ${template-content:location}/${template-content:filename}
raw template_httpd_cfg ${template-httpd:rendered}
raw template_monitor ${monitor2-template:rendered}
[dynamic-template-kvm]
<= jinja2-template-base
template = ${template-kvm:location}/instance-kvm.cfg.jinja2
filename = template-kvm.cfg
extra-context =
section slap_configuration slap-configuration
raw ansible_promise_tpl ${template-ansible-promise:location}/${template-ansible-promise:filename}
raw curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw dcron_executable_location ${dcron:location}/sbin/crond
raw debian_amd64_netinst_location ${debian-amd64-netinst.iso:location}/${debian-amd64-netinst.iso:filename}
raw file_download_script ${file-download-script:location}/${file-download-script:filename}
raw logrotate_cfg ${template-logrotate-base:rendered}
raw novnc_location ${noVNC:location}
raw netcat_bin ${netcat:location}/bin/netcat
raw python_executable ${buildout:executable}
raw python_eggs_executable ${buildout:bin-directory}/${eggs:interpreter}
raw qemu_executable_location ${kvm:location}/bin/qemu-system-x86_64
raw qemu_img_executable_location ${kvm:location}/bin/qemu-img
raw qemu_start_promise_tpl ${template-qemu-ready:location}/${template-qemu-ready:filename}
raw sixtunnel_executable_location ${6tunnel:location}/bin/6tunnel
raw template_httpd_cfg ${template-httpd:rendered}
raw template_content ${template-content:location}/${template-content:filename}
raw template_kvm_controller_run ${template-kvm-controller:location}/${template-kvm-controller:filename}
raw template_kvm_run ${template-kvm-run:location}/${template-kvm-run:filename}
raw template_monitor ${monitor2-template:rendered}
raw websockify_executable_location ${buildout:directory}/bin/websockify
raw wipe_disk_wrapper ${buildout:directory}/bin/securedelete
template-parts-destination = ${template-parts:target}
template-replicated-destination = ${template-replicated:target}
import-list = file parts :template-parts-destination
file replicated :template-replicated-destination
[dynamic-template-kvm-resilient]
recipe = slapos.recipe.template:jinja2
template = ${template-kvm-resilient:location}/instance-kvm-resilient.cfg.jinja2
rendered = $${buildout:directory}/template-kvm-resilient.cfg
extensions = jinja2.ext.do
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key slapparameter_dict slap-configuration:configuration
raw curl_executable_location ${curl:location}/bin/curl
raw template_monitor ${monitor2-template:rendered}
template-parts-destination = ${template-parts:target}
template-replicated-destination = ${template-replicated:target}
import-list = file parts :template-parts-destination
file replicated :template-replicated-destination
mode = 0644
[dynamic-template-kvm-export]
recipe = slapos.recipe.template:jinja2
template = ${template-kvm-export:location}/instance-kvm-export.cfg.jinja2
rendered = $${buildout:directory}/template-kvm-export.cfg
extensions = jinja2.ext.do
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
raw kvm_template $${dynamic-template-kvm:rendered}
raw template_kvm_export ${template-kvm-export-script:location}/${template-kvm-export-script:filename}
key pbsready_export_template template-pbsready-export:rendered
raw gzip_binary ${gzip:location}/bin/gzip
key slapparameter_dict slap-configuration:configuration
mode = 0644
[dynamic-template-kvm-import]
recipe = slapos.recipe.template:jinja2
template = ${template-kvm-import:location}/instance-kvm-import.cfg.jinja2.in
rendered = $${buildout:directory}/template-kvm-import.cfg
extensions = jinja2.ext.do
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
raw qemu_location ${kvm:location}
raw template_kvm_import ${template-kvm-import-script:location}/${template-kvm-import-script:filename}
raw pbsready_import_template ${pbsready-import:output}
key slapparameter_dict slap-configuration:configuration
raw zcat_binary ${gzip:location}/bin/zcat
raw gzip_binary ${gzip:location}/bin/gzip
mode = 0644
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/monitor/ 0000775 0000000 0000000 00000000000 13454062331 0026666 5 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/monitor/ansibleReport.py 0000664 0000000 0000000 00000014730 13454062331 0032056 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
# Parse Ansible result log file and and generate a report
import os, time
import json
import sqlite3
from datetime import datetime, timedelta
import sys
FIELDS = ['cmd', 'command', 'start', 'end', 'delta', 'msg', 'stdout', 'stderr',
'response', 'status_code', 'url', 'dest']
class ansibleReport(object):
def __init__(self, db_path,
ansible_log_dir,
name):
self.db_path = db_path
self.ansible_log_dir = ansible_log_dir
self.name = name
self.result_OK = '127.0.0.1_OK'
self.result_failed = '127.0.0.1_FAILED'
self.result_failed_ignore = '127.0.0.1_FAILED_INGORED' # tipo in ansible log upload pluging
self.date_format = '%Y-%m-%d %H:%M:%S'
self.day_format = '%Y-%m-%d'
self._init_db()
def _init_db(self):
db = sqlite3.connect(self.db_path)
c = db.cursor()
c.executescript("""
CREATE TABLE IF NOT EXISTS ansible_report (
name VARCHAR(40),
reportdate VARCHAR(15),
createdate VARCHAR(15),
status VARCHAR(20),
success_count INTEGER,
ignored_count INTEGER,
failed_count INTEGER,
ignored TEXT,
failed TEXT,
success TEXT);
""")
db.commit()
db.close()
def connect_db(self):
db = sqlite3.connect(self.db_path)
return db
def insertEntryDb(self, table_name, data_dict):
db = self.connect_db()
columns = data_dict.keys()
entries = ', '.join(columns)
values = '?' + ', ?' * (len(columns)-1)
sql_string = "insert into %s(%s) values (%s)" % (
table_name, entries, values)
tuple_data = ()
for key in columns:
tuple_data += (data_dict[key],)
db.execute(sql_string, tuple_data)
db.commit()
db.close()
def selectEntriesDb(self, fields=[], start_date=None, limit=0, success=None, order='DESC', where=""):
db = self.connect_db()
entries = ', '.join(fields) if fields else '*'
query = "select %s from ansible_report " % entries
where = " and %s" % where if where else ""
if not start_date:
start_date = datetime.utcnow().strftime(self.day_format)
tuple_values = (start_date,)
if success is not None:
status = 'OK' if success else 'FAILLED'
query += "where createdate>=? and status=? %s order by createdate %s" % (where, order)
tuple_values += (status,)
else:
query += "where createdate>=? %s order by createdate %s" % (where, order)
if limit:
query += " limit ?"
tuple_values += (limit,)
rows = db.cursor().execute(query, tuple_values)
#db.close()
if rows:
return [list(row) for row in rows]
return []
def truncateEntriesDb(self, table_name, on_field, to_value, operator='<'):
db = self.connect_db()
query = "delete from %s where %s%s?" % (table_name, on_field,
operator)
db.execute(query, (to_value,))
db.commit()
db.close()
def getLogString(self, res, head=False):
log = ""
if type(res) == type(dict()):
log = '%s, args [%s]\n' % (res['invocation']['module_name'],
res['invocation']['module_args'])
if head:
return log
for field in FIELDS:
if field in res.keys():
# use default encoding, check out sys.setdefaultencoding
log += '\n{0}:\n{1}'.format(field, res[field])
return log
def _read_file(self, filepath):
content = '[]'
with open(filepath, 'r') as f:
content = f.read()
return content
def saveResult(self):
date = datetime.utcnow().strftime(self.date_format)
files_list = os.listdir(self.ansible_log_dir)
if not len(files_list):
return
to_date = (datetime.now() - timedelta(days=2)).strftime(self.date_format)
cmp_file = os.path.join(self.ansible_log_dir, files_list.pop())
modification_date = datetime.fromtimestamp(
os.path.getmtime(cmp_file)
).strftime(self.date_format)
# Get the latest insert date
result = self.selectEntriesDb(['reportdate'], start_date=to_date, limit=1)
if len(result):
latest_date = result[0][0]
if latest_date >= modification_date:
return
file_map = dict(
success_file=os.path.join(self.ansible_log_dir, self.result_OK),
failed_file=os.path.join(self.ansible_log_dir, self.result_failed),
ignored_file=os.path.join(self.ansible_log_dir, self.result_failed_ignore))
data = dict(name=self.name, status='FAILED',
reportdate=modification_date, createdate=date,
success_count=0, ignored_count=0,
failed_count=0, success="",
failed="", ignored="")
for category in ('failed', 'success', 'ignored'):
file_category = file_map['%s_file' % category]
if os.path.exists(file_category):
text_content = self._read_file(file_category)
count = len(json.loads(text_content))
if count > 0:
data['%s_count' % category] = count
data[category] = text_content
if data['failed_count'] == 0:
data['status'] = 'OK'
self.insertEntryDb('ansible_report', data)
def getAnsibleReport(self, start_date=None, limit=0, success=None, order='DESC', category=None, head=False, only_state=True):
"""Get one or many entries from the ansible report table.
"""
where = ""
get_content = category is not None
fields = ['name', 'reportdate', 'createdate', 'status', 'success_count',
'ignored_count', 'failed_count']
if category:
where = " %s_count>0" % category
if not only_state:
fields.append(category)
rows = self.selectEntriesDb(fields=fields, start_date=start_date,
limit=limit, success=success, order=order,
where=where)
result_dict = {}
if category and not only_state:
last_pos = len(fields) -1
for i in range (0, len(rows)):
message = ""
message_list = json.loads(rows[i][last_pos])
for msg in message_list:
message += '%s\n\n' % self.getLogString(msg, head=head)
rows[i][last_pos] = message
else:
return {}
return rows
if __name__ == "__main__":
json = """{
"status": "OK",
"message": "kvm-1: OK(114) FAILED(0) IGNORED(2)",
"description": "Ansible playbook report in kvm-1. Execution date is: 2015-08-28 17:42:01."
}"""
parameter_dict = json.loads(sys.argv[1])
with open(parameter_dict['status_path'], 'w') as status_file:
status_file.write(json)
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/software.cfg 0000664 0000000 0000000 00000013206 13454062331 0027514 0 ustar 00root root 0000000 0000000 [buildout]
extends =
../../component/6tunnel/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/qemu-kvm/buildout.cfg
../../component/noVNC/buildout.cfg
../../component/openssl/buildout.cfg
../../component/netcat/buildout.cfg
../../component/pycurl/buildout.cfg
../../component/gzip/buildout.cfg
../../stack/slapos.cfg
../../component/nodejs/buildout.cfg
../../stack/resilient/buildout.cfg
buildout.hash.cfg
# stacks are listed from most generic to most specific,
# to avoid versioning issues
common-parts =
template
eggs
# XXX: we have to manually add this for resilience
rdiff-backup
pbs-recipe-egg
parts = ${:common-parts}
#XXX-Cedric : Currently, one can only access to KVM using noVNC.
# Ideally one should be able to access KVM by using either NoVNC or VNC.
# Problem is : no native crypto support in web browsers. So we have to disable ssl
# In qemu builtin vnc server, and make it available only for localhost
# so that only novnc can listen to it.
#XXX-Cedric: Check status of https://github.com/kanaka/noVNC/issues/13 to see
# When qemu has builtin support for websockets in vnc server to get rid of
# Websockify (socket <-> websocket proxy server) when it is ready.
# May solve previous XXX depending on the implementation.
#XXX-Cedric : add list of keyboard layouts (azerty/us querty/...) parameter to qemu
[eggs]
recipe = zc.recipe.egg
interpreter = python.eggs
eggs =
${python-cffi:egg}
${python-cryptography:egg}
${lxml-python:egg}
websockify
slapos.cookbook
slapos.toolbox
erp5.util
cns.recipe.symlink
collective.recipe.template
plone.recipe.command
${pycurl:egg}
[http-proxy]
# https://github.com/nodejitsu/node-http-proxy
recipe = slapos.recipe.build:download-unpacked
#XXX-Cedric : use upstream when merged
url = https://nodeload.github.com/desaintmartin/node-http-proxy/zipball/20120621
md5sum = 20204d0b29c2cef26e1c91e99eedca6b
[proxy-by-url]
# https://github.com/dominictarr/proxy-by-url
recipe = slapos.recipe.build:download-unpacked
#XXX-Cedric : use upstream when merged
url = https://nodeload.github.com/desaintmartin/proxy-by-url/zipball/20120621
md5sum = c2609948aa708581f93b981b23880314
[npm-modules]
recipe = plone.recipe.command
destination = ${buildout:parts-directory}/${:_buildout_section_name_}
location = ${buildout:parts-directory}/${:_buildout_section_name_}
command =
export HOME=${:location};
rm -fr ${:destination} &&
mkdir -p ${:destination} &&
cd ${:destination} &&
${nodejs:location}/bin/node ${nodejs:location}/bin/npm install colors@0.6.0-1 &&
${nodejs:location}/bin/node ${nodejs:location}/bin/npm install socket.io@0.8.7 &&
${nodejs:location}/bin/node ${nodejs:location}/bin/npm install socket.io-client@0.8.7 &&
${nodejs:location}/bin/node ${nodejs:location}/bin/npm install optimist@0.3.1 &&
${nodejs:location}/bin/node ${nodejs:location}/bin/npm install pkginfo@0.2.3
# Create all templates that will be used to deploy instances
[download-base]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[download-file-base]
<= download-base
ignore-existing = true
download-only = true
[download-template-base]
<= download-file-base
url = ${:_profile_base_location_}/template/${:path}
path = ${:filename}
[template-file-base]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[template]
<= template-file-base
output = ${buildout:directory}/template.cfg
[template-kvm]
<= download-file-base
on-update = true
[template-kvm-cluster]
<= download-file-base
on-update = true
[template-kvm-resilient]
<= download-file-base
on-update = true
[template-kvm-import]
<= download-file-base
on-update = true
[template-kvm-import-script]
<= download-template-base
filename = kvm-import.sh.jinja2
mode = 0755
[template-kvm-export]
<= download-file-base
on-update = true
[template-kvm-export-script]
<= download-template-base
filename = kvm-export.sh.jinja2
mode = 0755
[template-nbd]
<= template-file-base
output = ${buildout:directory}/template-nbd.cfg
[template-frontend]
<= template-file-base
output = ${buildout:directory}/template-frontend.cfg
[template-ansible-promise]
<= download-template-base
filename = ansible-promise.in
[template-kvm-run]
<= download-template-base
filename = template-kvm-run.in
on-update = true
[template-kvm-controller]
<= download-template-base
filename = kvm-controller-run.in
on-update = true
[template-apache-conf]
<= download-template-base
filename = apache.conf.in
on-update = true
[template-content]
<= download-template-base
filename = template-content.in
on-update = true
[template-qemu-ready]
<= download-template-base
filename = qemu-is-ready.in
on-update = true
[file-download-script]
<= download-template-base
path = download_file.in
filename = download_file
on-update = true
[template-httpd]
recipe = slapos.recipe.template:jinja2
filename = template-httpd.cfg
template = ${:_profile_base_location_}/instance-kvm-http.cfg.in
rendered = ${buildout:parts-directory}/${:_buildout_section_name_}/instance-kvm-http.cfg
md5sum = 26a181a48046ce88570adb32334747ef
context =
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}
[versions]
# XXX - use websockify = 0.5.1 for compatibility with kvm frontend
websockify = 0.5.1
erp5.util = 0.4.51
collective.recipe.environment = 0.2.0
gitdb = 0.6.4
pycurl = 7.43.0
slapos.recipe.template = 4.3
smmap = 0.9.0
# websockify = 0.8.0
# Required by:
# websockify==0.8.0
numpy = 1.11.2rc1
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/software.cfg.json 0000664 0000000 0000000 00000002156 13454062331 0030466 0 ustar 00root root 0000000 0000000 {
"name": "KVM",
"description": "KVM",
"serialisation": "xml",
"software-type": {
"default": {
"title": "Default",
"description": "Standalone KVM",
"request": "instance-kvm-input-schema.json",
"response": "instance-kvm-output-schema.json",
"index": 0
},
"kvm-resilient": {
"title": "Resilient",
"description": "Resilient KVM",
"request": "instance-kvm-resilient-input-schema.json",
"response": "instance-kvm-output-schema.json",
"index": 1
},
"kvm-cluster": {
"title": "Cluster",
"description": "Cluster KVM",
"serialisation": "json-in-xml",
"request": "instance-kvm-cluster-input-schema.json",
"response": "instance-kvm-output-schema.json",
"index": 2
},
"kvm-cluster-simplified": {
"title": "Basic Cluster",
"description": "Simplified Schema for Cluster KVM",
"software-type": "kvm-cluster",
"serialisation": "json-in-xml",
"request": "instance-kvm-cluster-simplified-input-schema.json",
"response": "instance-kvm-output-schema.json",
"index": 3
}
}
}
slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/template/ 0000775 0000000 0000000 00000000000 13454062331 0027012 5 ustar 00root root 0000000 0000000 ansible-promise.in 0000664 0000000 0000000 00000003557 13454062331 0032366 0 ustar 00root root 0000000 0000000 slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/template #!/usr/bin/env python
# Parse Ansible result log file and define if execution succeed or not
import os
import json
FIELDS = ['cmd', 'command', 'start', 'end', 'delta', 'msg', 'stdout', 'stderr',
'response', 'status_code', 'url', 'dest']
ansible_log_dir = '{{ logs }}'
vm_name = '{{ name }}'
result_OK = '127.0.0.1_OK'
result_failed = '127.0.0.1_FAILED'
result_failed_ignore = '127.0.0.1_FAILED_IGNORED'
def get_log(res):
log = ""
if type(res) == type(dict()):
log = '>> Running task: %s, args [%s]\n' % (res['invocation']['module_name'],
res['invocation']['module_args'])
for field in FIELDS:
if field in res.keys():
# use default encoding, check out sys.setdefaultencoding
log += '\n{0}:\n{1}'.format(field, res[field])
return log
def file_to_dict(filepath):
content = '{}'
with open(filepath, 'r') as f:
content = f.read()
return json.loads(content)
def check_result():
success_file = os.path.join(ansible_log_dir, result_OK)
error_file = os.path.join(ansible_log_dir, result_failed)
if not os.path.exists(ansible_log_dir):
return (0, "File %s doesn't exist.\nThis mean that ansible report log is not uploaded yet!!!" % ansible_log_dir)
if not len(os.listdir(ansible_log_dir)):
return (0, 'No Ansible promise uploaded!')
if os.path.exists(error_file):
result = file_to_dict(error_file)
if len(result) > 0:
#there is more that one failed task in the report
message = ''
for res in result:
message += '%s\n\n' % get_log(res)
return (0, message)
elif not os.path.exists(success_file):
return (0, 'All Ansible tasks failed to run')
return (1, '')
if __name__ == "__main__":
result = check_result()
if not result[0]:
raise Exception('Failed to run Ansible in %s, result is: \n%s' % (vm_name,
result[1])) slapos-4eee4c81ac91449b1b26f13da25bb541b33eda21-software-kvm/software/kvm/template/apache.conf.in 0000664 0000000 0000000 00000003525 13454062331 0031514 0 ustar 00root root 0000000 0000000 ServerLimit 16
StartServers 1
MaxClients 7
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule mime_module modules/mod_mime.so
LoadModule headers_module modules/mod_headers.so
LoadModule autoindex_module modules/mod_autoindex.so
Listen {{ ip }}:{{ port }}
PidFile "{{ pid_file }}"
ServerAdmin admin@
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
ServerTokens Prod
ServerSignature Off
TraceEnable Off
SSLEngine on
SSLCertificateFile {{ cert }}
SSLCertificateKeyFile {{ key }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:HIGH:!aNULL:!MD5
SSLHonorCipherOrder on
SSLProxyEngine On
DocumentRoot {{ document_root }}
ErrorLog "{{ error_log }}"
# 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
CustomLog "{{ access_log }}" combined
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
# Directory protection
Options FollowSymLinks
AllowOverride None
Require all denied
Options Indexes FollowSymLinks
# Require ip {{ ip }}
# Require env forwarded '{{ ip }}'
# Require all denied
AllowOverride None
Require all granted