{%- if instance_parameter_dict['slap-software-type'] == software_type -%} {% import "caucase" as caucase with context %} # KeDiFa instance profile [buildout] extends = {{ software_parameter_dict['profile_common'] }} {{ software_parameter_dict['profile_monitor'] }} {{ software_parameter_dict['profile_logrotate_base'] }} parts = monitor-base directory kedifa logrotate-entry-kedifa promise-kedifa-http-reply slave-kedifa-information caucased caucased-promise caucase-updater expose-csr_id promise-expose-csr_id-ip-port promise-logrotate-setup [monitor-instance-parameter] # Note: Workaround for monitor stack, which uses monitor-httpd-port parameter # directly, and in our case it can come from the network, thus resulting # with need to strip !py!'u' monitor-httpd-port = {{ instance_parameter_dict['configuration.monitor-httpd-port'] | int }} password = {{ instance_parameter_dict['configuration.monitor-password'] | string }} [caucased] hash-existing-files = ${buildout:directory}/software_release/buildout.cfg {% set caucase_host = '[' ~ instance_parameter_dict['ipv6-random'] ~ ']' %} {% set caucase_netloc = caucase_host ~ ':' ~ instance_parameter_dict['configuration.caucase_port'] -%} {% set caucase_url = 'http://' ~ caucase_netloc -%} {{ caucase.caucased( prefix='caucased', buildout_bin_directory=software_parameter_dict['bin_directory'], caucased_path='${directory:service}/caucased', backup_dir='${directory:backup-caucased}', data_dir='${directory:caucased}', netloc=caucase_netloc, tmp='${directory:tmp}', service_auto_approve_count=0, user_auto_approve_count=1, key_len=2048 )}} # Create all needed directories [directory] recipe = slapos.cookbook:mkdirectory bin = ${buildout:directory}/bin/ etc = ${buildout:directory}/etc/ srv = ${buildout:directory}/srv/ var = ${buildout:directory}/var/ tmp = ${buildout:directory}/tmp/ backup = ${:srv}/backup log = ${:var}/log run = ${:var}/run service = ${:etc}/service etc-run = ${:etc}/run # KeDiFa directories kedifa = ${:srv}/kedifa etc-kedifa = ${:etc}/kedifa # CAUCASE directories caucased = ${:srv}/caucased backup-caucased = ${:backup}/caucased # reservation reservation = ${:srv}/reservation # csr_id publication csr_id = ${:srv}/csr_id certificate-csr_id = ${:var}/certificate-csr_id expose-csr_id-var = ${:var}/expose-csr_id [kedifa-csr] recipe = plone.recipe.command organization = {{ slapparameter_dict['cluster-identification'] }} organizational_unit = Kedifa Partition command = if [ ! -f ${:template-csr} ] && [ ! -f ${:key} ] ; then /bin/bash -c '{{ software_parameter_dict['openssl'] }} req -new -sha256 \ -newkey rsa:2048 -nodes -keyout ${:key} \ -subj "/O=${:organization}/OU=${:organizational_unit}" \ -reqexts SAN \ -config <(cat {{ software_parameter_dict['openssl_cnf'] }} \ <(printf "\n[SAN]\nsubjectAltName=IP:${kedifa-config:ip}")) \ -out ${:template-csr}' fi update-command = ${:command} template-csr = ${kedifa-config:template-csr} key = ${kedifa-config:key} {#- Can be stopped on error, as does not rely on self provided service #} stop-on-error = True {{ caucase.updater( prefix='caucase-updater', buildout_bin_directory=software_parameter_dict['bin_directory'], updater_path='${directory:service}/caucase-updater', url=caucase_url, data_dir='${directory:srv}/caucase-updater', crt_path='${kedifa-config:certificate}', ca_path='${kedifa-config:ca-certificate}', crl_path='${kedifa-config:crl}', key_path='${kedifa-csr:key}', on_renew='${kedifa-reloader:rendered}', template_csr='${kedifa-csr:template-csr}' )}} [store-csr_id] recipe = plone.recipe.command csr_id_path = ${directory:csr_id}/csr_id.txt csr_work_path = ${directory:tmp}/${:_buildout_section_name_} stop-on-error = False update-command = ${:command} command = {{ software_parameter_dict['bin_directory'] }}/caucase \ --ca-url {{ caucase_url }} \ --ca-crt ${kedifa-config:ca-certificate} \ --crl ${kedifa-config:crl} \ --mode service \ {#- XXX: Need to use caucase-updater-csr:csr, as there is no way to obatin csr_id from caucase-updater -#} {#- XXX: nor directly path to the generated CSR #} --send-csr ${caucase-updater-csr:csr} > ${:csr_work_path} && \ cut -d ' ' -f 1 ${:csr_work_path} > ${:csr_id_path} [certificate-csr_id] recipe = plone.recipe.command certificate = ${directory:certificate-csr_id}/certificate.pem key = ${directory:certificate-csr_id}/key.pem {#- Can be stopped on error, as does not rely on self provided service #} stop-on-error = True update-command = ${:command} command = if ! [ -f ${:key} ] && ! [ -f ${:certificate} ] ; then {{ software_parameter_dict['openssl'] }} req -new -newkey rsa:2048 -sha256 -subj \ "/O=${kedifa-csr:organization}/OU=${kedifa-csr:organizational_unit}/CN={{ instance_parameter_dict['ipv6-random'] }}" \ -days 5 -nodes -x509 -keyout ${:key} -out ${:certificate} fi [expose-csr_id-configuration] ip = {{ instance_parameter_dict['ipv6-random'] }} port = 17000 key = ${certificate-csr_id:key} certificate = ${certificate-csr_id:certificate} error-log = ${directory:log}/expose-csr_id.log [expose-csr_id-template] recipe = slapos.recipe.template:jinja2 var = ${directory:expose-csr_id-var} pid = ${directory:var}/nginx-expose-csr_id.pid rendered = ${directory:etc}/nginx-expose-csr_id.conf template = inline: daemon off; pid ${:pid}; error_log ${expose-csr_id-configuration:error-log}; events { } http { include {{ software_parameter_dict['nginx_mime'] }}; server { server_name_in_redirect off; port_in_redirect off; error_log ${expose-csr_id-configuration:error-log}; access_log /dev/null; listen [${expose-csr_id-configuration:ip}]:${expose-csr_id-configuration:port} ssl; ssl_certificate ${expose-csr_id-configuration:certificate}; ssl_certificate_key ${expose-csr_id-configuration:key}; default_type application/octet-stream; client_body_temp_path ${:var} 1 2; proxy_temp_path ${:var} 1 2; fastcgi_temp_path ${:var} 1 2; uwsgi_temp_path ${:var} 1 2; scgi_temp_path ${:var} 1 2; location / { alias ${directory:csr_id}/; autoindex off; sendfile on; sendfile_max_chunk 1m; } } } [promise-expose-csr_id-ip-port] <= monitor-promise-base module = check_socket_listening name = expose-csr_id-ip-port-listening.py config-host = ${expose-csr_id-configuration:ip} config-port = ${expose-csr_id-configuration:port} [expose-csr_id] depends = ${store-csr_id:command} recipe = slapos.cookbook:wrapper command-line = {{ software_parameter_dict['nginx'] }} -c ${expose-csr_id-template:rendered} wrapper-path = ${directory:service}/expose-csr_id hash-existing-files = ${buildout:directory}/software_release/buildout.cfg [get-csr_id-certificate] recipe = collective.recipe.shelloutput commands = certificate = cat ${certificate-csr_id:certificate} [jinja2-template-base] recipe = slapos.recipe.template:jinja2 rendered = ${buildout:directory}/${:filename} extra-context = slapparameter_dict = {{ dumps(slapparameter_dict) }} slap_software_type = {{ dumps(instance_parameter_dict['slap-software-type']) }} context = import json_module json raw profile_common {{ software_parameter_dict['profile_common'] }} key slap_software_type :slap_software_type key slapparameter_dict :slapparameter_dict section directory directory ${:extra-context} [kedifa-config] ip = {{ instance_parameter_dict['ipv6-random'] }} port = {{ instance_parameter_dict['configuration.kedifa_port'] }} db = ${directory:kedifa}/kedifa.sqlite certificate = ${directory:etc-kedifa}/certificate.pem key = ${:certificate} ca-certificate = ${directory:etc-kedifa}/ca-certificate.pem crl = ${directory:etc-kedifa}/crl.pem template-csr = ${directory:etc-kedifa}/template-csr.pem pidfile = ${directory:run}/kedifa.pid logfile = ${directory:log}/kedifa.log [kedifa-reloader] <= jinja2-template-base template = {{ software_parameter_dict['template_wrapper'] }} rendered = ${directory:etc-run}/kedifa-reloader command = kill -HUP `cat ${kedifa-config:pidfile}` mode = 0700 extra-context = key content :command [promise-kedifa-http-reply] <= monitor-promise-base module = check_url_available name = kedifa-http-reply.py # Kedifa replies 400 on /, so use it to be sure that Kedifa replied config-http_code = 400 config-url = https://[${kedifa-config:ip}]:${kedifa-config:port} config-ca-cert-file = ${kedifa-config:ca-certificate} [logrotate-entry-kedifa] <= logrotate-entry-base name = kedifa log = ${kedifa-config:logfile} rotate-num = {{ instance_parameter_dict['configuration.rotate-num'] | int }} delaycompress = [kedifa] recipe = slapos.cookbook:wrapper command-line = {{ software_parameter_dict['kedifa'] }} --ip ${kedifa-config:ip} --port ${kedifa-config:port} --db ${kedifa-config:db} --certificate ${kedifa-config:certificate} --ca-certificate ${kedifa-config:ca-certificate} --crl ${kedifa-config:crl} --pidfile ${kedifa-config:pidfile} --logfile ${kedifa-config:logfile} wrapper-path = ${directory:service}/kedifa hash-existing-files = ${buildout:directory}/software_release/buildout.cfg # Publish KeDiFa configuration for upload and download for each slave {%- set slave_kedifa_information = {} -%} {%- for slave in slapparameter_dict['slave-list'] -%} {%- set slave_reference = slave['slave_reference'] -%} {%- set slave_dict = {} -%} {%- do slave_dict.__setitem__('key-generate-auth-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}/generateauth' % (slave_reference,)) -%} {%- do slave_dict.__setitem__('key-upload-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}?auth=' % (slave_reference,)) -%} {%- do slave_dict.__setitem__('key-download-url', 'https://[${kedifa-config:ip}]:${kedifa-config:port}/${%s-auth-random:passwd}' % (slave_reference,)) -%} {%- do slave_dict.__setitem__('kedifa-caucase-url', caucase_url ) -%} {%- do slave_kedifa_information.__setitem__(slave_reference, slave_dict) %} [{{ slave_reference }}-auth-random-generate] recipe = plone.recipe.command file = ${directory:reservation}/${:_buildout_section_name_} command = [ ! -f ${:file} ] && {{ software_parameter_dict['curl'] }}/bin/curl -s -g -X POST https://[${kedifa-config:ip}]:${kedifa-config:port}/reserve-id --cert ${kedifa-config:certificate} --cacert ${kedifa-config:ca-certificate} > ${:file}.tmp && mv ${:file}.tmp ${:file} update-command = ${:command} [{{ slave_reference }}-auth-random] recipe = collective.recipe.shelloutput file = {{ '${' + slave_reference }}-auth-random-generate:file} commands = passwd = cat ${:file} 2>/dev/null || echo "NotReadyYet" {% endfor %} [master-auth-random-generate] recipe = plone.recipe.command file = ${directory:reservation}/${:_buildout_section_name_} command = [ ! -f ${:file} ] && {{ software_parameter_dict['curl'] }}/bin/curl -s -g -X POST https://[${kedifa-config:ip}]:${kedifa-config:port}/reserve-id --cert ${kedifa-config:certificate} --cacert ${kedifa-config:ca-certificate} > ${:file}.tmp && mv ${:file}.tmp ${:file} update-command = ${:command} [master-auth-random] recipe = collective.recipe.shelloutput file = ${master-auth-random-generate:file} commands = passwd = cat ${:file} 2>/dev/null || echo "NotReadyYet" [slave-kedifa-information] recipe = slapos.cookbook:publish.serialised {# sort_keys are important in order to avoid shuffling parameters on each run #} slave-kedifa-information = {{ json_module.dumps(slave_kedifa_information, sort_keys=True) }} caucase-url = {{ caucase_url }} master-key-generate-auth-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd}/generateauth master-key-upload-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd}?auth= master-key-download-url = https://[${kedifa-config:ip}]:${kedifa-config:port}/${master-auth-random:passwd} csr_id-url = https://[${expose-csr_id-configuration:ip}]:${expose-csr_id-configuration:port}/csr_id.txt csr_id-certificate = ${get-csr_id-certificate:certificate} monitor-base-url = ${monitor-instance-parameter:monitor-base-url} [promise-logrotate-setup] <= monitor-promise-base module = check_command_execute name = ${:_buildout_section_name_}.py config-command = ${logrotate:wrapper-path} -d {%- endif -%} {# if instance_parameter_dict['slap-software-type'] == software_type #}