Commit efd9ed30 authored by Kristopher Ruzic's avatar Kristopher Ruzic

starts merge of kvm and packer by defining packer as software_type

modifies the kvm recipe to take packer specific parameters, this is done so the json file packer relies on can be generated at runtime
parent 13ed0f14
......@@ -14,8 +14,52 @@ from random import shuffle
import glob
import re
if '%{is-packer}s':
packer_dict = {}
packer_dict["disk_size"] = '%(disk-size)s'
packer_dict["type"] = 'qemu'
packer_dict["headless"] = True
# iso url and md5 are hardcoded for now
packer_dict["iso_url"] = "http://cdimage.debian.org/debian-cd/8.1.0/amd64/iso-cd/debian-8.1.0-amd64-netinst.iso"
packer_dict["iso_checksum"] = "1a311f9afb68d6365211b13b4342c40b"
packer_dict["iso_checksum_type"] = "md5"
# set basic params
packer_dict["name"] = '%(packer-name)s'
packer_dict["accelerator"] = "kvm" # explicitly set
packer_dict["http_directory"] = "http"
# ssh params (will create account on install)
packer_dict["ssh_username"] = '%(packer-username)s'
packer_dict["ssh_password"] = '%(packer-password)s'
# boot parameters
packer_dict["boot_wait"] = "2s" # warm up
# runs through install
packer_dict["boot_command"] = [
"<esc><wait><wait>",
"install auto ",
"debian-installer=en_US locale=en_US keymap=us ",
"netcfg/get_hostname=%(packer-hostname)s",
"netcfg/get_domain=%(packer-domain)s",
"fb=false debconf/frontend=noninteractive ",
"passwd/user-fullname=%(packer-username)s",
"passwd/user-password=%(packer-password)s",
"passwd/user-password-again=%(packer-password)s",
"passwd/username=%(packer-username)s",
"<enter>"
]
# XXX: give all of this through parameter, don't use this as template, but as module
# use_tap and use_nat set as Bool as per http://stackoverflow.com/a/922374
software_type = '%(kvm-software-type)s'
qemu_img_path = '%(qemu-img-path)s'
qemu_path = '%(qemu-path)s'
disk_size = '%(disk-size)s'
......@@ -28,8 +72,8 @@ virtual_hard_drive_url = '%(virtual-hard-drive-url)s'.strip()
virtual_hard_drive_md5sum = '%(virtual-hard-drive-md5sum)s'.strip()
virtual_hard_drive_gzipped = '%(virtual-hard-drive-gzipped)s'.strip()
nat_rules = '%(nat-rules)s'.strip()
use_tap = literal_eval('%(use-tap)s')
use_nat = literal_eval('%(use-nat)s')
use_tap = ast.literal_eval('%(use-tap)s')
use_nat = ast.literal_eval('%(use-nat)s')
tap_interface = '%(tap-interface)s'
listen_ip = '%(ipv4)s'
mac_address = '%(mac-address)s'
......@@ -51,7 +95,21 @@ netcat_bin = '%(netcat-binary)s'.strip()
cluster_doc_host = '%(cluster-doc-host)s'
cluster_doc_port = %(cluster-doc-port)s
def gen_packer_json(build):
import json
packer_json = {"builders": [build]}
with open(instance_dir + "/packer.json", 'w') as outfile:
json.dump(packer_json, outfile)
# takes a list and turns it 2D
# needed as kvm is using a flat args list
# but packer needs 2D
# ['-m', '1024', '-vga', 'std']
# goes to:
# [['-m', '1024'], ['-vga', 'std']]
def widen(l):
return zip(l[::2], l[1::2])
def md5Checksum(file_path):
with open(file_path, 'rb') as fh:
m = hashlib.md5()
......@@ -269,5 +327,15 @@ else:
'-drive', 'file=%%s,media=cdrom' %% default_disk_image
])
print 'Starting KVM: \n %%s' %% ' '.join(kvm_argument_list)
os.execv(qemu_path, kvm_argument_list)
# if the software release type was defined as packer
# we need to do a bit more work
if '%{is-packer}s':
packer_dict["qemuargs"] = filter(None, widen(kvm_argument_list))
print 'Generating Packer json with qemu args: '
print packer_dict["qemuargs"]
gen_packer_json(packer_dict)
else:
print 'Starting KVM: \n %%s' %% ' '.join(kvm_argument_list)
os.execv(qemu_path, kvm_argument_list)
......@@ -123,6 +123,14 @@ mode = 0644
download-only = true
on-update = true
[template-kvm-packer]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/instance-kvm-packer.cfg.jinja2
#md5sum = 3e3354844b2052609e3c49eca03b607e
mode = 0644
download-only = true
on-update = true
[template-kvm-import]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-kvm-import.cfg.in
......
{% set enable_http = slapparameter_dict.get('enable-http-server', 'False') -%}
#############################
#
# Instanciate kvm packer
#
#############################
[buildout]
parts =
certificate-authority
publish-connection-information
# kvm-vnc-promise
kvm-disk-image-corruption-promise
websockify-sighandler
novnc-promise
# kvm-monitor
cron
# cron-entry-monitor
frontend-promise
{% if slapparameter_dict.get('document-host', '') %}
cluster-url-path
{% endif -%}
{% if slapparameter_dict.get('enable-http-server', 'False') == 'True' %}
httpd
httpd-promise
publish-host-config
packer-build-template
extends =
{{ template_httpd_cfg }}
{% endif -%}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[directory]
recipe = slapos.cookbook:mkdirectory
etc = ${buildout:directory}/etc
bin = ${buildout:directory}/bin
srv = ${buildout:directory}/srv
var = ${buildout:directory}/var
log = ${:var}/log
scripts = ${:etc}/run
services = ${:etc}/service
promises = ${:etc}/promise
novnc-conf = ${:etc}/novnc
run = ${:var}/run
ca-dir = ${:srv}/ssl
public = ${:srv}/public/
cron-entries = ${:etc}/cron.d
crontabs = ${:etc}/crontabs
cronstamps = ${:etc}/cronstamps
[create-mac]
recipe = slapos.cookbook:generate.mac
storage-path = ${directory:srv}/mac
[create-tap-mac]
recipe = slapos.cookbook:generate.mac
storage-path = ${directory:srv}/tap_mac
[gen-passwd]
recipe = slapos.cookbook:generate.password
storage-path = ${directory:srv}/passwd
bytes = 8
[kvm-instance]
# XXX-Cedric: change "KVM" recipe to simple "create wrappers". No need for this
# Specific code. It needs Jinja.
recipe = slapos.cookbook:kvm
is-packer = True
vnc-passwd = ''
ipv4 = ${slap-network-information:local-ipv4}
ipv6 = ${slap-network-information:global-ipv6}
vnc-ip = ${:ipv4}
vnc-port = 5901
# XXX-Cedric: should be named "default-cdrom-iso"
default-disk-image = {{ debian_amd64_netinst_location }}
nbd-host = ${slap-parameter:nbd-host}
nbd-port = ${slap-parameter:nbd-port}
nbd2-host = ${slap-parameter:nbd2-host}
nbd2-port = ${slap-parameter:nbd2-port}
tap-interface = ${slap-network-information:network-interface}
disk-path = ${directory:srv}/virtual.qcow2
disk-size = ${slap-parameter:disk-size}
disk-type = ${slap-parameter:disk-type}
socket-path = ${directory:var}/qmp_socket
pid-file-path = ${directory:run}/pid_file
smp-count = ${slap-parameter:cpu-count}
smp-options = ${slap-parameter:cpu-options}
ram-size = ${slap-parameter:ram-size}
numa = ${slap-parameter:numa}
mac-address = ${create-mac:mac-address}
tap-mac-address = ${create-tap-mac:mac-address}
# XXX-Cedric: should be named runner-wrapper-path and controller-wrapper-path
runner-path = ${directory:services}/kvm
controller-path = ${directory:scripts}/kvm_controller
use-tap = ${slap-parameter:use-tap}
use-nat = ${slap-parameter:use-nat}
nat-rules = ${slap-parameter:nat-rules}
6tunnel-wrapper-path = ${directory:services}/6tunnel
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}
shell-path = {{ dash_executable_location }}
qemu-path = {{ qemu_executable_location }}
qemu-img-path = {{ qemu_img_executable_location }}
6tunnel-path = {{ sixtunnel_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 slapparameter_dict.get('enable-http-server', 'False') == 'True' or ( slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') ) -%}
httpd-port = ${slap-parameter:httpd-port}
{% else -%}
httpd-port = 0
{% endif -%}
# Main instance document server info
{% if slapparameter_dict.get('document-host', '') and slapparameter_dict.get('document-port', '') -%}
cluster-doc-host = ${tunnel-cluster-url:ipv4}
cluster-doc-port = ${tunnel-cluster-url:ipv4-port}
{% else -%}
cluster-doc-host =
cluster-doc-port = 0
{% endif -%}
netcat-binary = {{ netcat_bin }}
# packer specifics
packer-name = ${slap-parameter:packer-name}
packer-domain = ${slap-parameter:packer-domain}
packer-hostname = ${slap-parameter:packer-hostname}
packer-username = ${slap-parameter:packer-username}
#XXX: change to use password gen
packer-password = ${gen-passwd:passwd}
[kvm-vnc-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/vnc_promise
hostname = ${kvm-instance:vnc-ip}
port = ${kvm-instance:vnc-port}
[kvm-disk-image-corruption-promise]
# Check that disk image is not corrupted
recipe = collective.recipe.template
input = inline:#!/bin/sh
# Return code 0 is "OK"
# Return code 3 is "found leaks, but image is OK"
# http://git.qemu.org/?p=qemu.git;a=blob;f=qemu-img.c;h=4e9a7f5741c9cb863d978225829e68fefcae3947;hb=HEAD#l702
${kvm-instance:qemu-img-path} check ${kvm-instance:disk-path}
RETURN_CODE=$?
if [ $RETURN_CODE -eq 0 ] || [ $RETURN_CODE -eq 3 ]; then
exit 0
else
exit 1
fi
output = ${directory:promises}/kvm-disk-image-corruption
mode = 700
[novnc-instance]
recipe = slapos.cookbook:novnc
path = ${ca-novnc:executable}
ip = ${slap-network-information:global-ipv6}
port = 6080
vnc-ip = ${kvm-instance:vnc-ip}
vnc-port = ${kvm-instance:vnc-port}
novnc-location = {{ novnc_location }}
websockify-path = {{ websockify_executable_location }}
ssl-key-path = ${ca-novnc:key-file}
ssl-cert-path = ${ca-novnc:cert-file}
[websockify-sighandler]
recipe = slapos.cookbook:signalwrapper
wrapper-path = ${directory:services}/websockify
wrapped-path = ${novnc-instance:path}
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = {{ openssl_executable_location }}
ca-dir = ${directory:ca-dir}
requests-directory = ${cadirectory:requests}
wrapper = ${directory:services}/certificate_authority
ca-private = ${cadirectory:private}
ca-certs = ${cadirectory:certs}
ca-newcerts = ${cadirectory:newcerts}
ca-crl = ${cadirectory:crl}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = ${directory:ca-dir}/requests/
private = ${directory:ca-dir}/private/
certs = ${directory:ca-dir}/certs/
newcerts = ${directory:ca-dir}/newcerts/
crl = ${directory:ca-dir}/crl/
[ca-novnc]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = ${directory:novnc-conf}/novnc.key
cert-file = ${directory:novnc-conf}/novnc.crt
executable = ${directory:bin}/novnc
wrapper = ${directory:bin}/websockify
[novnc-promise]
recipe = slapos.cookbook:check_port_listening
path = ${directory:promises}/novnc_promise
hostname = ${novnc-instance:ip}
port = ${novnc-instance:port}
#----------------
#--
#-- Deploy cron.
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = {{ dcron_executable_location }}
cron-entries = ${directory:cron-entries}
crontabs = ${directory:crontabs}
cronstamps = ${directory:cronstamps}
catcher = ${cron-simplelogger:wrapper}
binary = ${directory:services}/crond
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = ${directory:bin}/cron_simplelogger
log = ${directory:log}/crond.log
#----------------
#--
#-- Deploy frontend.
[request-slave-frontend]
recipe = slapos.cookbook:requestoptional
software-url = ${slap-parameter:frontend-software-url}
server-url = ${slap-connection:server-url}
key-file = ${slap-connection:key-file}
cert-file = ${slap-connection:cert-file}
computer-id = ${slap-connection:computer-id}
partition-id = ${slap-connection:partition-id}
name = ${slap-parameter:frontend-instance-name}
software-type = ${slap-parameter:frontend-software-type}
slave = true
config-host = ${novnc-instance:ip}
config-port = ${novnc-instance:port}
return = url resource port domainname
sla-instance_guid = ${slap-parameter:frontend-instance-guid}
[frontend-promise]
recipe = slapos.cookbook:check_url_available
path = ${directory:promises}/frontend_promise
url = ${publish-connection-information:url}
dash_path = {{ dash_executable_location }}
curl_path = {{ curl_executable_location }}
[publish-connection-information]
# XXX: publish something related to the packer build state
recipe = slapos.cookbook:publish
ipv6 = ${slap-network-information:global-ipv6}
backend-url = https://[${novnc-instance:ip}]:${novnc-instance:port}/vnc_auto.html?host=[${novnc-instance:ip}]&port=${novnc-instance:port}&encrypt=1&password=${kvm-instance:vnc-passwd}
url = ${request-slave-frontend:connection-url}/vnc_auto.html?host=${request-slave-frontend:connection-domainname}&port=${request-slave-frontend:connection-port}&encrypt=1&path=${request-slave-frontend:connection-resource}&password=${kvm-instance:vnc-passwd}
{% set disk_number = len(storage_dict) -%}
maximum-extra-disk-amount = {{ disk_number }}
{% set iface = 'eth0' -%}
{% if slapparameter_dict.get('use-nat', 'True') == 'True' -%}
{% set iface = 'eth1' -%}
# Publish NAT port mapping status
# XXX: hardcoded value from [slap-parameter]
{% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') %}
{% for port in nat_rule_list.split(' ') -%}
{% set external_port = 10000 + port|int() -%}
nat-rule-port-{{port}} = ${slap-network-information:global-ipv6} : {{external_port}}
{% if slapparameter_dict.get('publish-nat-url', False) -%}
nat-rule-url-{{port}} = [${slap-network-information:global-ipv6}]:{{external_port}}
{% endif -%}
{% endfor -%}
{% endif -%}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' -%}
tap-ipv4 = ${slap-network-information:tap-ipv4}
{% endif -%}
{% set kvm_http = 'http://${slap-network-information:local-ipv4}:' ~ slapparameter_dict.get('httpd-port', 8081) -%}
{% if enable_http == 'True' %}
{% if slapparameter_dict.get('use-nat', 'True') == 'True' -%}
{% set kvm_http = 'http://10.0.2.100' -%}
{% endif %}
{% if slapparameter_dict.get('authorized-key', '') -%}
7_info = Get the publick key file in your VM with the command: wget {{ kvm_http }}/${get-authorized-key:filename}
{% endif %}
{% endif %}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') -%}
1_info = Use these configurations below to configure interface {{ iface }} in your VM.
2_info = ${network-config:ifconfig}
3_info = ${network-config:route-iface}
4_info = ${network-config:route-network}
5_info = ${network-config:route-default}
{% if enable_http == 'True' %}
6_info = Or run in your VM the command: wget -O- {{ kvm_http }}/netconfig.sh | /bin/sh -
{% endif %}
[network-config]
recipe = plone.recipe.command
path = ${directory:public}/netconfig.sh
ifconfig = ifconfig {{ iface }} ${slap-network-information:tap-ipv4} netmask ${slap-network-information:tap-netmask}
route-iface = route add ${slap-network-information:tap-gateway} dev {{ iface }}
route-network = route add -net ${slap-network-information:tap-network} netmask ${slap-network-information:tap-netmask} gw ${slap-network-information:tap-gateway}
{% if iface == 'eth0' -%}
route-default = route add default gw ${slap-network-information:tap-gateway}
{% elif global_ipv4_prefix -%}
route-default = ip route add {{ global_ipv4_prefix }} via ${slap-network-information:tap-gateway} dev {{ iface }} src ${slap-network-information:tap-ipv4}
{% else -%}
route-default =
{% endif -%}
command =
echo "#!/bin/sh" > ${:path}
echo "" >> ${:path}
echo "${:ifconfig}" >> ${:path}
echo "${:route-iface}" >> ${:path}
echo "${:route-network}" >> ${:path}
echo "${:route-default}" >> ${:path}
update-command = ${:command}
{% endif -%}
[get-authorized-key]
recipe = slapos.recipe.template:jinja2
template = {{ template_content }}
filename = authorized_keys
rendered = ${directory:public}/${:filename}
public-key = {{ slapparameter_dict.get('authorized-key', '') }}
context =
key content_list :public-key
raw sep ##
[publish-host-config]
recipe = plone.recipe.command
name = {{ slapparameter_dict.get('name', 'localhost') }}
{% if slapparameter_dict.get('use-tap', 'False') == 'True' and tap_network_dict.has_key('ipv4') -%}
local-ipv4 = ${slap-network-information:tap-ipv4}
{% else -%}
local-ipv4 = 127.0.0.1
{% endif -%}
path-host = ${directory:public}/hostname
path-ip = ${directory:public}/ipv4
command =
rm -f ${:path-host}
rm -f ${:path-ip}
echo "${:name}" > ${:path-host}
echo "${:local-ipv4}" > ${:path-ip}
update-command = ${:command}
# To access documents of main instance (in case of kvm-cluster) through http
[cluster-url-path]
recipe = slapos.recipe.template:jinja2
template = {{ template_content }}
filename = cluster.hash
rendered = ${directory:public}/${:filename}
hash-url = https://10.0.2.101:443/{{ slapparameter_dict.get('document-path', '') }}
context =
key content_list :hash-url
raw sep #
# This 6to4 tunnel help to access document url in ipv4
[tunnel-cluster-url]
recipe = slapos.cookbook:ipv4toipv6
ipv6 = {{ slapparameter_dict.get('document-host', '') }}
ipv4 = ${slap-network-information:local-ipv4}
ipv6-port = {{ slapparameter_dict.get('document-port', '') }}
ipv4-port = 16936
shell-path = {{ dash_executable_location }}
6tunnel-path = {{ sixtunnel_executable_location }}
runner-path = ${directory:services}/6tunnel-cluster
[packer-build-template]
< = jinja2-template-base
template = ${packer-template-wrapper:output}
rendered = $${directory:scripts}/packer-build
mode = 0700
extra-context =
key env packer-configuration:packer-environment
key content packer-configuration:packer-build-command
key dash dash_executable_location
[packer-configuration]
packer-environment = ${buildout:parts-directory}/qemu/bin/
packer-build-command =
${buildout:parts-directory}/packer/packer build -color=false ${buildout:directory}/packer.json
[packer-template-wrapper]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/packer-wrapper.in
output = ${buildout:directory}/packer-template-wrapper.cfg
mode = 0644
[slap-parameter]
# Default values if not specified
frontend-software-type = frontend
frontend-software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg
frontend-instance-guid =
frontend-instance-name = VNC Frontend
nbd-port = 1024
nbd-host =
nbd2-port = 1024
nbd2-host =
ram-size = 1024
disk-size = 10
disk-type = virtio
cpu-count = 1
# cpu-option is a string: [cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]
cpu-options =
# list of numa options separate by space: node,nodeid=1,cpus=9-15 node,nodeid=2,cpus=1,3,7
numa =
nat-rules = 22 80 443
use-nat = True
use-tap = False
virtual-hard-drive-url =
virtual-hard-drive-md5sum =
virtual-hard-drive-gzipped = False
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 =
# packer specifics
packer-name = Nexedi Test Image
packer-domain = nexedi-domain
packer-hostname = nexedi-hostname
packer-username = nexedi
#XXX: change to use password gen
packer-password = test
......@@ -10,6 +10,8 @@ recipe = slapos.cookbook:softwaretype
default = $${:kvm}
kvm-cluster = $${dynamic-template-kvm-cluster:rendered}
kvm = $${dynamic-template-kvm:rendered}
packer = ${dynamic-template-packer:rendered}
nbd = ${template-nbd:output}
frontend = ${template-frontend:output}
......@@ -37,7 +39,6 @@ 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
......@@ -139,3 +140,35 @@ context =
key slapparameter_dict slap-configuration:configuration
raw bin_directory ${buildout:bin-directory}
mode = 0644
[dynamic-template-packer]
recipe = slapos.recipe.template:jinja2
template = ${template-kvm-packer:location}/instance-kvm-packer.cfg.jinja2
rendered = $${buildout:directory}/template-kvm-packer.cfg
extensions = jinja2.ext.do
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key global_ipv4_prefix network-information:global-ipv4-network
key slapparameter_dict slap-configuration:configuration
key storage_dict slap-configuration:storage-dict
key tap_network_dict slap-configuration:tap-network-information-dict
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 novnc_location ${noVNC:location}
raw netcat_bin ${netcat:location}/bin/netcat
raw openssl_executable_location ${openssl:location}/bin/openssl
raw qemu_executable_location ${kvm:location}/bin/qemu-system-x86_64
raw qemu_img_executable_location ${kvm:location}/bin/qemu-img
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 websockify_executable_location ${buildout:directory}/bin/websockify
template-parts-destination = ${template-parts:destination}
template-replicated-destination = ${template-replicated:destination}
import-list = file parts :template-parts-destination
file replicated :template-replicated-destination
mode = 0644
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment