Commit 4ea4d3ab by Thomas Gambier

Pure-FTPd SR

This SR has been developed for a demo. The purpose is to have a running pureftpd server which will call a script "/opt/pureftpd/upload_script" each time a file is uploaded. Pureftpd is used because it is already used in the current working environment of our partner and they don't want to change for now.

The script /opt/pureftpd/upload_script" is left out of the SR on purpose because it will be written by people outside Nexedi at first and contains sensitive information. Also, it is on purpose in /opt directory of the machine because this SR will be deployed on only one machine for now and the script will be shared by all pureftpd instances.

/reviewed-on !503
1 parent 39abfcb5
......@@ -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"'
Pureftpd with upload script
https://www.pureftpd.org/project/pure-ftpd
# Features
* After each upload, call the script /opt/pureftpd/upload_script
# 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
{
"$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"
}
}
}
{
"$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"
}
[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]"
[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
{
"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
}
}
}
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!