[buildout]
parts =
  monitor-base
  promises
  frontend-reload
  tasks.json
  publish-connection-parameter

extends = ${monitor-template:rendered}

eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true


[frontend-instance-password]
recipe = slapos.cookbook:generate.password
username = node
bytes = 12

[frontend-instance-certificate]
recipe = plone.recipe.command
command =
  if [ ! -e $${:key-file} ]
  then
    ${openssl-output:openssl} req -x509 -nodes -days 3650 \
      -subj "/C=AA/ST=X/L=X/O=Dis/CN=$${:common-name}" \
      -newkey rsa:1024 -keyout $${:key-file} \
      -out $${:cert-file}
  fi
update-command = $${:command}
key-file = $${directory:etc}/$${:_buildout_section_name_}.key
cert-file = $${directory:etc}/$${:_buildout_section_name_}.crt
common-name = $${frontend-instance-config:ip}
location =
  $${:key-file}
  $${:cert-file}

[frontend-instance-config]
recipe = slapos.recipe.template:jinja2
rendered = $${directory:etc}/$${:_buildout_section_name_}
template = inline:
  :$${:port} {
    bind $${:ip}
    tls $${frontend-instance-certificate:cert-file} $${frontend-instance-certificate:key-file}
    log stdout
    errors stderr
    gzip
    # because caddy does not support upgrade http2 to websocket
    # https://tools.ietf.org/html/rfc8441
    tls {
      alpn http/1.1
    }
    root $${directory:frontend-static}
    browse
    proxy / $${theia-instance:base-url} {
      except public $${favicon.ico:filename}
    }
    proxy /services $${theia-instance:base-url} {
      websocket
    }
    proxy /file-upload $${theia-instance:base-url} {
      websocket
    }
    basicauth $${frontend-instance-password:username} $${frontend-instance-password:passwd} {
      realm "Theia"
      /
    }
  }
ip = $${instance-parameter:ipv6-random}
hostname = [$${:ip}]
port = 3001

[frontend-instance]
recipe = slapos.cookbook:wrapper
wrapper-path = $${directory:services}/$${:_buildout_section_name_}
command-line =
  ${caddy:output} -conf $${frontend-instance-config:rendered} -pidfile $${:pidfile}

ip = $${frontend-instance-config:ip}
hostname = $${frontend-instance-config:hostname}
port = $${frontend-instance-config:port}
pidfile = $${directory:pidfiles}/$${:_buildout_section_name_}.pid
url = https://$${:hostname}:$${:port}/

[frontend-reload]
recipe = slapos.cookbook:wrapper
wrapper-path = $${directory:services}/$${:_buildout_section_name_}
command-line =
  ${bash:location}/bin/bash -c
  "kill -s USR1 $$(${coreutils:location}/bin/cat $${frontend-instance:pidfile}) \
    && ${coreutils:location}/bin/sleep infinity"
hash-files =
  $${frontend-instance-config:rendered}
  $${frontend-instance:wrapper-path}
wait-for-files = $${frontend-instance:pidfile}

[favicon.ico]
# generate a pseudo random favicon, different for each instance name.
recipe = slapos.recipe.build
install =
  import hashlib, shutil
  buildout_offline = self.buildout['buildout']['offline']
  self.buildout['buildout']['offline'] = 'false'
  try:
    gravatar_url = "https://www.gravatar.com/avatar/" + hashlib.md5(
      '''$${slap-configuration:root-instance-title}'''
    ).hexdigest() + "?s=256&d=retro"
    shutil.copy(self.download(gravatar_url), '''$${:location}''')
  except Exception:
    # Because installation should work offline, if we can't download a favicon,
    # just ignore this step.
    self.logger.exception("Error while downloading favicon, using empty one")
    open('''$${:location}''', 'w').close()
  finally:
    self.buildout['buildout']['offline'] = buildout_offline

location = $${directory:frontend-static}/$${:filename}
filename = $${:_buildout_section_name_}

[tasks.json]
recipe = slapos.recipe.template:jinja2
rendered = $${directory:dot-theia}/tasks.json
template =
  inline:
  {
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
      {
        "label": "slapos node software",
        "detail": "Build all software supplied to the node",
        "type": "shell",
        "command": "${buildout:bin-directory}/slapos",
        "args": [
          "node",
          "software",
          // debug mode can be enabled by commenting out this line:
          // "--buildout-debug",
          "--all"
        ],
        "options": {
          "env": {
            "SLAPOS_CONFIGURATION": "$${slapos-standalone-activate:slapos-configuration}",
            "GIT_EXEC_PATH": ""
          }
        },
        "group": {
          "kind": "build",
          "isDefault": true
        },
        "problemMatcher": []
      },
      {
        "label": "slapos node instance",
        "detail": "Create all instances requested on the node",
        "type": "shell",
        "command": "${buildout:bin-directory}/slapos",
        "args": [
          "node",
          "instance",
          // debug mode can be enabled by commenting out this line:
          // "--buildout-debug",
          "--all"
        ],
        "options": {
          "env": {
            "SLAPOS_CONFIGURATION": "$${slapos-standalone-activate:slapos-configuration}",
            "GIT_EXEC_PATH": ""
          }
        },
        "problemMatcher": [],
        "group": {
          "kind": "build",
          "isDefault": true
        }
      }
    ]
  }



[user]
recipe = slapos.cookbook:userinfo

[theia-instance]
recipe = slapos.cookbook:wrapper
wrapper-path = $${directory:services}/$${:_buildout_section_name_}
command-line =
  env HOME=$${buildout:directory} LC_ALL=C.UTF-8 TMP=$${directory:tmp} THEIA_WEBVIEW_EXTERNAL_ENDPOINT='{{hostname}}' THEIA_SHELL=$${theia-shell:rendered} ${theia-wrapper:rendered} --hostname=$${:hostname} --port=$${:port} $${directory:project}

ip =  $${instance-parameter:ipv4-random}
hostname =  $${:ip}
port = 3000
base-url = http://$${:hostname}:$${:port}/
hash-existing-files =
  ${yarn.lock:output}
  ${theia-wrapper:rendered}

[theia-shell]
recipe = slapos.recipe.template:jinja2
rendered = $${directory:bin}/$${:_buildout_section_name_}
mode = 0700
template = inline:
  #!${python:location}/bin/python
  import sys
  import os
  args = sys.argv[1:]
  # when running interactively, activate slapos configuration and reset GIT_EXEC_PATH to workaround https://github.com/eclipse-theia/theia/issues/7555
  if not args: args = ["-c", ". $${slapos-standalone-activate:rendered} && exec env GIT_EXEC_PATH= ${bash:location}/bin/bash", ]
  os.execv('${bash:location}/bin/bash', ['${bash:location}/bin/bash']  + args)


[slapos-standalone-activate]
recipe = slapos.recipe.template:jinja2
rendered = $${directory:bin}/$${:_buildout_section_name_}
mode = 0700
# XXX maybe standalone slapos should provide an activate script like virtualenv is doing?
template =
  inline:#!/bin/sh
  export PATH=${buildout:bin-directory}:$PATH
  ${slapos-standalone:script-path} \
      $${directory:slapos} \
      $${:ipv4} \
      $${:ipv6} \
      $${:port} \
      $${slap-connection:server-url} \
      $${slap-connection:computer-id} \
      $${slap-connection:partition-id} \
      --key='$${slap-connection:key-file}' \
      --cert='$${slap-connection:cert-file}'
  export SLAPOS_CONFIGURATION=$${:slapos-configuration}
  export SLAPOS_CLIENT_CONFIGURATION=$SLAPOS_CONFIGURATION

ipv4 = $${instance-parameter:ipv4-random}
ipv6 = $${instance-parameter:ipv6-random}
port = 4000
slapos-configuration = $${directory:slapos}/etc/slapos.cfg

[promises]
recipe =
instance-promises =
  $${theia-listen-promise:name}
  $${frontend-listen-promise:name}
  $${apache-frontend-url-available-promise:name}

[theia-listen-promise]
<= monitor-promise-base
module = check_port_listening
name = $${:_buildout_section_name_}.py
config-hostname=  $${theia-instance:ip}
config-port = $${theia-instance:port}

[frontend-listen-promise]
<= monitor-promise-base
module = check_port_listening
name = $${:_buildout_section_name_}.py
config-hostname = $${frontend-instance:ip}
config-port = $${frontend-instance:port}

[apache-frontend-url-available-promise]
<= monitor-promise-base
module = check_url_available
name = $${:_buildout_section_name_}.py
config-url = $${apache-frontend:connection-secure_access}
config-check-secure = 1

[apache-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Theia Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config-url = $${frontend-instance:url}
config-https-only = true
config-type = websocket
config-websocket-path-list = /services /file-upload
return = domain secure_access

[publish-connection-parameter]
recipe = slapos.cookbook:publish
url = $${apache-frontend:connection-secure_access}
username = $${frontend-instance-password:username}
password = $${frontend-instance-password:passwd}

[instance-parameter]
recipe = slapos.cookbook:slapconfiguration
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}

[directory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
var = $${buildout:directory}/var
srv = $${buildout:directory}/srv
bin = $${buildout:directory}/bin
tmp = $${buildout:directory}/tmp
dot-theia = $${buildout:directory}/.theia/
pidfiles = $${:var}/run

services = $${:etc}/service
project = $${:srv}/project
slapos = $${:srv}/slapos
frontend-static = $${:srv}/frontend-static
frontend-static-public = $${:frontend-static}/public