diff --git a/component/pure-ftpd/buildout.cfg b/component/pure-ftpd/buildout.cfg index 891440658063a1dd8193b2dbb20dd2e642802e5c..0f4c1ed6d7d71837beb699a53bd16958f7ca9e4c 100644 --- a/component/pure-ftpd/buildout.cfg +++ b/component/pure-ftpd/buildout.cfg @@ -7,8 +7,11 @@ url = https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.46.tar. md5sum = efce5529c1f0a39dafdd532c619503f1 # See https://download.pureftpd.org/pub/pure-ftpd/doc/README for more configurations +# We need the trick about UPLOAD_PIPE_FILE and UPLOAD_PIPE_LOCK so that the files are created inside the $CWD/var/run +# WARNING: this means that both pure-ftpd and pure-uploadscript binaries must be launched in $HOME ! configure-options = --with-uploadscript - -#environment = -# Probably it is missing dependencies to be set here. + --with-puredb + --with-nonroot +environment= + CFLAGS=-DUPLOAD_PIPE_FILE='"/proc/self/cwd/var/run/pure-ftpd.upload.pipe"' -DUPLOAD_PIPE_LOCK='"/proc/self/cwd/var/run/pure-ftpd.upload.lock"' diff --git a/software/pureftpd/README.md b/software/pureftpd/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35651013ef549a0266efc4969440d0ee9c4acc5c --- /dev/null +++ b/software/pureftpd/README.md @@ -0,0 +1,8 @@ +Pureftpd with upload script + +https://www.pureftpd.org/project/pure-ftpd + +# Features + + * After each upload, call the script /opt/pureftpd/upload_script + diff --git a/software/pureftpd/buildout.hash.cfg b/software/pureftpd/buildout.hash.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8830bec43f2420ea713b4daad9743f7dcdb11595 --- /dev/null +++ b/software/pureftpd/buildout.hash.cfg @@ -0,0 +1,18 @@ +# 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). + +[instance-profile] +filename = instance.cfg.in +md5sum = c352c6f11b7a00dca0a544f7ecddeb52 diff --git a/software/pureftpd/instance-input-schema.json b/software/pureftpd/instance-input-schema.json new file mode 100644 index 0000000000000000000000000000000000000000..6df5507f38851d2620d049b1fd75b66750dd88c4 --- /dev/null +++ b/software/pureftpd/instance-input-schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Parameters to instantiate Pure-FTPd", + "additionalProperties": false, + "properties": { + "port": { + "title": "FTP port", + "description": "Port number to listen to - default to 8021", + "type": "number" + } + } +} diff --git a/software/pureftpd/instance-output-schema.json b/software/pureftpd/instance-output-schema.json new file mode 100644 index 0000000000000000000000000000000000000000..657398f94113371803880808ef2c29e99063a000 --- /dev/null +++ b/software/pureftpd/instance-output-schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Values returned by Pure-FTPd instantiation", + "additionalProperties": false, + "properties": { + "url": { + "description": "URL of the FTP service", + "pattern": "^ftp://", + "type": "string" + }, + "username": { + "description": "Default username", + "type": "string", + "optional": true + }, + "password": { + "description": "Password for default username", + "type": "string", + "optional": true + }, + "videos": { + "description": "Location of the videos", + "type": "string", + "optional": true + } + }, + "type": "object" +} diff --git a/software/pureftpd/instance.cfg.in b/software/pureftpd/instance.cfg.in new file mode 100644 index 0000000000000000000000000000000000000000..035f3b545477e79ec2f8715dfdb133b55b3e8dad --- /dev/null +++ b/software/pureftpd/instance.cfg.in @@ -0,0 +1,118 @@ +[buildout] +extends = + {{ monitor_rendered }} + +parts = + promises + publish-connection-parameter + monitor-base +eggs-directory = {{ buildout['eggs-directory'] }} +develop-eggs-directory = {{ buildout['develop-eggs-directory'] }} + +[slap-configuration] +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} +configuration.port = 8021 + +[directory] +recipe = slapos.cookbook:mkdirectory +home = ${buildout:directory} +etc = ${:home}/etc +var = ${:home}/var +run = ${:var}/run +log = ${:var}/log +srv = ${:home}/srv +service = ${:etc}/service +promise = ${:etc}/promise +plugin = ${:etc}/plugin +pureftpd-dir = ${:srv}/pureftpd/ + +[check-port-listening-promise] +recipe = slapos.cookbook:promise.plugin +eggs = + slapos.toolbox +output = ${directory:plugin}/${:_buildout_section_name_} +content = + from slapos.promise.plugin.check_port_listening import RunPromise + +[pureftpd-listen-promise] +<= check-port-listening-promise +config-hostname = ${pureftpd:ipv6} +config-port = ${pureftpd:ftp-port} + +[pureftpd-userinfo] +recipe = slapos.cookbook:userinfo + +[pureftpd-password] +recipe = slapos.cookbook:generate.password +username = nexedi_cdn +bytes = 12 + +[pureftpd] +ipv6 = ${slap-configuration:ipv6-random} +ipv4 = ${slap-configuration:ipv4-random} +host = ${:ipv6} +ftp-port = ${slap-configuration:configuration.port} +url = ftp://[${:host}]:${:ftp-port} +data-dir = ${directory:pureftpd-dir} +pid-file=${directory:run}/pureftpd.pid +auth-user-file=${auth-user-file:output} + +recipe =slapos.recipe.template:jinja2 +# WARNING pure-uploadscript must be launched AFTER pure-ftpd so keep them in the same wrapper +# and make sure they are both killed if one of them is killed. +template = inline: + #!{{ bash_location }}/bin/bash + {{ pureftpd_bin }} --uploadscript --customerproof --bind ${:host},${:ftp-port} --login puredb:${:auth-user-file} --pidfile ${:pid-file} & + while ! [ -p ${directory:run}/pure-ftpd.upload.pipe ] + do + sleep 1 + done + {{ pureuploadscript_bin }} -r /opt/pureftpd/upload_script & + wait -n + kill 0 +rendered = ${directory:service}/pureftpd +wrapper-path = ${:rendered} + +[pure-pw] +# command line to add a user, invoke with: +# pure-pw useradd bob +# it will prompt for password twice +recipe = slapos.cookbook:wrapper +wrapper-path =${buildout:bin-directory}/${:_buildout_section_name_} +command-line = + {{ purepw_bin }} useradd ${pureftpd-password:username} -d ${pureftpd:data-dir} -u ${pureftpd-userinfo:pw-uid} -g ${pureftpd-userinfo:gr-gid} -f ${auth-user-file:passwd-file} "$@" + + +[auth-user-file] +recipe = plone.recipe.command +passwd-file = ${directory:etc}/pureftpd.passwd +output = ${directory:etc}/pureftpd.pdb +command = + if [ -f ${:passwd-file} ] && {{ purepw_bin }} show ${pureftpd-password:username} -f ${:passwd-file} + then + ( echo ${pureftpd-password:passwd} ; echo ${pureftpd-password:passwd}) | {{ purepw_bin }} passwd ${pureftpd-password:username} -f ${:passwd-file} + else + ( echo ${pureftpd-password:passwd} ; echo ${pureftpd-password:passwd}) | ${pure-pw:wrapper-path} + fi + {{ purepw_bin }} mkdb ${:output} -f ${:passwd-file} +update-command = ${:command} + + +[promises] +recipe = +instance-promises = + ${pureftpd-listen-promise:output} + + +[publish-connection-parameter] +recipe = slapos.cookbook:publish +<= monitor-publish +url = ${pureftpd:url} +username = ${pureftpd-password:username} +password = ${pureftpd-password:passwd} +videos = To see the videos, go to http://nexedi-cdndemo-cdn-p.hexaglobe.net/ and enter the name "${pureftpd-userinfo:pw-name}-[video_name_without_extension]" diff --git a/software/pureftpd/software.cfg b/software/pureftpd/software.cfg new file mode 100644 index 0000000000000000000000000000000000000000..33b9a4eba3d52ea6ea28938b0239c658ce6a5596 --- /dev/null +++ b/software/pureftpd/software.cfg @@ -0,0 +1,37 @@ +[buildout] +extends = + ../../stack/slapos.cfg + ../../component/pure-ftpd/buildout.cfg + ../../component/bash/buildout.cfg + buildout.hash.cfg + ../../stack/monitor/buildout.cfg + +parts = + slapos-cookbook + instance-profile + + +# force to install plone.recipe.command and slapos.toolbox as it will be used during instanciation +[slapos-cookbook] +eggs += + plone.recipe.command + slapos.toolbox + + +[instance-profile] +recipe = slapos.recipe.template:jinja2 +template = ${:_profile_base_location_}/${:filename} +rendered = ${buildout:directory}/instance.cfg +mode = 0644 +extensions = jinja2.ext.do +context = + section buildout buildout + key bash_location bash:location + raw monitor_rendered ${monitor-template:rendered} + raw pureftpd_bin ${pure-ftpd:location}/sbin/pure-ftpd + raw pureuploadscript_bin ${pure-ftpd:location}/sbin/pure-uploadscript + raw purepw_bin ${pure-ftpd:location}/bin/pure-pw + + +[versions] +slapos.recipe.template = 4.3 diff --git a/software/pureftpd/software.cfg.json b/software/pureftpd/software.cfg.json new file mode 100644 index 0000000000000000000000000000000000000000..0e4f038c58ae846891c4ff17c3764cfd6e64db4e --- /dev/null +++ b/software/pureftpd/software.cfg.json @@ -0,0 +1,14 @@ +{ + "name": "Pure-FTPd", + "description": "Pure-FTPd as a FTP server with virtual users and uploadscript", + "serialisation": "json-in-xml", + "software-type": { + "default": { + "title": "Default", + "description": "Pure-FTPd, with a default user", + "request": "instance-input-schema.json", + "response": "instance-output-schema.json", + "index": 0 + } + } +}