Mobrovac has uploaded a new change for review.
https://gerrit.wikimedia.org/r/205863
Change subject: Update to service-template-node 0.1.3
......................................................................
Update to service-template-node 0.1.3
Changes:
- send CORS and CSP headers
- update dependencies
- use app.loger when req.logger is not available
- various small fixes and updates
Please test this release, mainly due to rather restrictive CSP headers.
Change-Id: Ibbe14ffec488b5791ab3ea4ff5923aee9e2c0ae1
---
M .gitignore
M .jshintignore
D Dockerfile
M app.js
M config.prod.yaml
A dist/init-scripts/systemd.erb
A dist/init-scripts/sysvinit.erb
A dist/init-scripts/upstart.erb
M doc/README.md
M doc/commands.md
A doc/deployment.md
M doc/template.md
M lib/util.js
M package.json
D scripts/docker.js
A scripts/gen-init-scripts.rb
A targets.yaml
M test/features/app/app.js
18 files changed, 551 insertions(+), 205 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/mobileapps
refs/changes/63/205863/1
diff --git a/.gitignore b/.gitignore
index 5b6fe76..bc02473 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+Dockerfile
coverage
config.yaml
node_modules
diff --git a/.jshintignore b/.jshintignore
index 1c69eee..c052634 100644
--- a/.jshintignore
+++ b/.jshintignore
@@ -1,3 +1,5 @@
coverage
node_modules
test
+www
+static
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index f8f2496..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM buildpack-deps:jessie
-
-# install node && npm
-RUN apt-get update && apt-get install -y nodejs npm && rm -rf
/var/lib/apt/lists/*
-# link /usr/bin/node to /usr/bin/nodejs
-RUN ln -s /usr/bin/nodejs /usr/bin/node
-
-# copy the repo files over
-RUN mkdir -p /opt/service
-ADD . /opt/service
-# install the dependencies
-WORKDIR /opt/service
-RUN npm install
-
-# start the server
-CMD ["/usr/bin/npm", "start"]
-
diff --git a/app.js b/app.js
index 88943b1..5f9e033 100644
--- a/app.js
+++ b/app.js
@@ -31,6 +31,31 @@
if(!app.conf.port) { app.conf.port = 8888; }
if(!app.conf.interface) { app.conf.interface = '0.0.0.0'; }
if(!app.conf.compression_level) { app.conf.compression_level = 3; }
+ if(app.conf.cors === undefined) { app.conf.cors = '*'; }
+ if(!app.conf.csp) {
+ app.conf.csp =
+ "default-src 'self'; object-src 'none'; media-src *; img-src *;
style-src *; frame-ancestors 'self'";
+ }
+
+ // set outgoing proxy
+ if(app.conf.proxy) {
+ process.env.HTTP_PROXY = app.conf.proxy;
+ }
+
+ // set the CORS and CSP headers
+ app.all('*', function(req, res, next) {
+ if(app.conf.cors !== false) {
+ res.header('Access-Control-Allow-Origin', app.conf.cors);
+ res.header('Access-Control-Allow-Headers', 'Accept,
X-Requested-With, Content-Type');
+ }
+ res.header('X-XSS-Protection', '1; mode=block');
+ res.header('X-Content-Type-Options', 'nosniff');
+ res.header('X-Frame-Options', 'SAMEORIGIN');
+ res.header('Content-Security-Policy', app.conf.csp);
+ res.header('X-Content-Security-Policy', app.conf.csp);
+ res.header('X-WebKit-CSP', app.conf.csp);
+ next();
+ });
// disable the X-Powered-By header
app.set('x-powered-by', false);
diff --git a/config.prod.yaml b/config.prod.yaml
index aad96fd..0b2e676 100644
--- a/config.prod.yaml
+++ b/config.prod.yaml
@@ -18,7 +18,7 @@
# Statsd metrics reporter
metrics:
- type: txstatsd
+ type: statsd
host: statsd.eqiad.wmnet
port: 8125
diff --git a/dist/init-scripts/systemd.erb b/dist/init-scripts/systemd.erb
new file mode 100644
index 0000000..78b5be3
--- /dev/null
+++ b/dist/init-scripts/systemd.erb
@@ -0,0 +1,25 @@
+[Unit]
+Description=<%= @description ? @service_name + ' - ' + @description :
@service_name %>
+Documentation=<%= @homepage %>
+After=network.target local-fs.target
+
+[Service]
+Type=simple
+LimitNOFILE=<%= @no_file %>
+PIDFile=%t/<%= @service_name %>.pid
+User=<%= @service_name %>
+Group=<%= @service_name %>
+WorkingDirectory=/srv/deployment/<%= @service_name %>/deploy
+Environment="NODE_PATH='/srv/deployment/<%= @service_name
%>/deploy/node_modules'" "<%= @service_name.gsub(/[^a-z0-9_]/, '_').upcase
%>_PORT=<%= @port %>"
+ExecStart=/usr/bin/nodejs src/server.js -c /etc/<%= @service_name
%>/config.yaml
+Restart=always
+RestartSec=5
+StandardOutput=syslog
+StandardError=syslog
+SyslogIdentifier=<%= @service_name %>
+TimeoutStartSec=5
+TimeoutStopSec=60
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/dist/init-scripts/sysvinit.erb b/dist/init-scripts/sysvinit.erb
new file mode 100644
index 0000000..f889596
--- /dev/null
+++ b/dist/init-scripts/sysvinit.erb
@@ -0,0 +1,172 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: <%= @service_name %>
+# Required-Start: $local_fs $network $remote_fs $syslog
+# Required-Stop: $local_fs $network $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: <%= @description || @service_name %>
+# Description: <%= @description ? @service_name + ' - ' + @description :
@service_name %>
+### END INIT INFO
+
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="<%= @service_name %> service"
+NAME=<%= @service_name %>
+SCRIPT_PATH=/srv/deployment/$NAME/deploy/src/server.js
+DAEMON="/usr/bin/nodejs $SCRIPT_PATH"
+DAEMON_ARGS="-c /etc/$NAME/config.yaml"
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -e "$SCRIPT_PATH" ] || exit 0
+
+# Read configuration variable file if it is present
+# NOTE: only the DAEMON_ARGS var should be set in the file if present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# export some variables into the process' environment
+export PORT
+export INTERFACE
+export NODE_PATH=/srv/deployment/$NAME/deploy/node_modules
+export <%= @service_name.gsub(/[^a-z0-9_]/, '_').upcase %>_PORT=<%= @port %>
+
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # up the number of fds [sockets] from 1024
+ ulimit -n <%= @no_file %>
+
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+
+ start-stop-daemon --start --quiet --pidfile $PIDFILE -bm \
+ -c $NAME:$NAME --test \
+ --exec /bin/sh -- \
+ -c "$DAEMON $DAEMON_ARGS 2>&1 | logger -i -t $NAME" \
+ || return 1
+ start-stop-daemon --start --quiet --pidfile $PIDFILE -bm \
+ -c <%= @service_name %>:<%= @service_name %> \
+ --exec /bin/sh -- \
+ -c "$DAEMON $DAEMON_ARGS 2>&1 | logger -i -t $NAME" \
+ || return 2
+ echo "Started <%= @service_name %> service on port <%= @port %>"
+
+
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+ sleep 5
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/60/KILL/5 --pidfile
$PIDFILE --name $NAME
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/5/KILL/5 --exec
$DAEMON
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ #
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ #
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name
$NAME
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ #reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ #log_daemon_msg "Reloading $DESC" "$NAME"
+ #do_reload
+ #log_end_msg $?
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
diff --git a/dist/init-scripts/upstart.erb b/dist/init-scripts/upstart.erb
new file mode 100644
index 0000000..4cffcb5
--- /dev/null
+++ b/dist/init-scripts/upstart.erb
@@ -0,0 +1,24 @@
+# Upstart job for <%= @service_name %>
+
+description "<%= @description ? @service_name + ' - ' + @description :
@service_name %>"
+
+start on (local-filesystems and net-device-up IFACE!=lo)
+stop on runlevel [!2345]
+
+# up ulimit -n a bit
+limit nofile <%= @no_file %> <%= @no_file %>
+
+setuid "<%= @service_name %>"
+setgid "<%= @service_name %>"
+
+env NODE_PATH="/srv/deployment/<%= @service_name %>/deploy/node_modules"
+env <%= @service_name.gsub(/[^a-zA-Z0-9_]/, '_').upcase %>_PORT="<%= @port %>"
+
+respawn
+
+# wait 60 seconds for a graceful restart before killing the master
+kill timeout 60
+
+chdir /srv/deployment/<%= @service_name %>/deploy
+exec /usr/bin/nodejs src/server.js -c /etc/<%= @service_name %>/config.yaml >>
/var/log/<%= @service_name %>/main.log 2>&1
+
diff --git a/doc/README.md b/doc/README.md
index 26adc44..d837f0a 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -8,6 +8,7 @@
3. [Configuration](config.md)
4. [Useful Commands](commands.md)
5. [Coding Guide](coding.md)
+6. [Deployment](deployment.md)
Have fun while creating RESTful API services!
diff --git a/doc/commands.md b/doc/commands.md
index e1bc803..01b6c5a 100644
--- a/doc/commands.md
+++ b/doc/commands.md
@@ -95,3 +95,7 @@
After you log out completely and log back in, you should be able to run the
above scripts without resorting to `sudo`.
+## Deployment
+
+See [this document](deployment.md) for how to get ready to deploy your service.
+
diff --git a/doc/deployment.md b/doc/deployment.md
new file mode 100644
index 0000000..bb93f7d
--- /dev/null
+++ b/doc/deployment.md
@@ -0,0 +1,164 @@
+# Deployment
+
+Getting your service ready to be deployed on WMF production machines involves
+several tasks. This document explains the steps needed to get started and how
to
+keep your deployable copy up-to-date.
+
+## Repositories
+
+Because Node.js services use npm dependencies which can be binary, these need
to
+be pre-built. Therefore, two repositories are needed; one for the source code
of
+your service, and the other, so-called *deploy* repository. Both should be
+available as WM's Gerrit repositories with the paths
+*mediawiki/services/your-service-name* and
+*mediawiki/services/your-service-name/deploy*. When [requesting
+them](https://www.mediawiki.org/wiki/Git/New_repositories/Requests) ask for the
+former to be a clone of [the service
+template](https://github.com/wikimedia/service-template-node) and the latter to
+be empty.
+
+It is important to note that the deploy repository is only to be updated
+directly before (re-)deploying the service, and not on each patch merge
entering
+the *master* branch of the regular repository. In other words, **the deploy
+repository mirrors the code deployed in production at all times**.
+
+The remainder of the document assumes these two repositories have been created
+and that you have cloned them using your Gerrit account, i.e. not anonymously,
+with the following outline:
+
+```
+~/code/
+ |- your-service
+ -- deploy
+```
+
+Furthermore, it is assumed that you have initialised the deploy repository:
+
+```bash
+$ cd ~/code/deploy
+$ git review -s
+$ touch README.md
+$ git add README.md
+$ git commit -m "Initial commit"
+$ git push -u origin master # or git review -R if this fails
+# go to Gerrit and +2 your change, if needed and then:
+$ git pull
+```
+
+Finally, if you haven't yet done so, do [basic service
+configuration](config.md).
+
+The remainder of the document refers to these two repositories as the *source
+repository* and the *deploy repository*, respectively.
+
+## Configuration
+
+The service template includes an automation script which updates the deploy
+repository, but it needs to be configured properly in order to work.
+
+### package.json
+
+The first part of the configuration involves keeping your source repository's
+`package.json` updated. Look for its [deploy stanza](../package.json#L49).
+Depending on the exact machine on which your service will be deployed, you may
+need to set `target` to either `ubuntu` or `debian`.
+
+The important thing is keeping the `dependencies` field up to date at all
times.
+There you should list all of the extra packages that are needed in order to
+build the npm module dependencies. The `_all` field denotes packages which
+should be installed regardless of the target distribution, but you can add
+other, distribution-specific package lists, e.g.:
+
+```javascript
+"deploy": {
+ "target": "ubuntu",
+ "dependencies": {
+ "ubuntu": ["pkg1", "pkg2"],
+ "debian": ["pkgA", "pkgB"],
+ "_all": ["pkgOne", "pkgTwo"]
+ }
+}
+```
+
+In this example, with the current configuration, packages *pkg1*, *pkg2*,
+*pkgOne* and *pkgTwo* are going to be installed before building the
+dependencies. If, instead, the target is changed to `debian`, then *pkgA*,
+*pkgB*, *pkgOne* and *pkgTwo* are selected.
+
+As a rule of thumb, **whenever you need to install extra packages into your
+development environment for satisfying node module dependencies, add them to
+*deploy.dependencies* to ensure the successful build and update of the deploy
+repository**.
+
+### Local git
+
+The script needs to know where to find your local copy of the deploy
repository.
+To that end, when in your source repository, run:
+
+```
+git config deploy.dir /absolute/path/to/deploy/repo
+```
+
+Using the aforementioned local outline, you would type:
+
+```
+git config deploy.dir /home/YOU/code/deploy
+```
+
+The source repository is itself a submodule of the deploy repository. If its
+name as specified in `package.json`'s `name` field does not match the actual
+repository's name in Gerrit, run:
+
+```
+git config deploy.name name_in_gerrit
+```
+
+That will make the system look for the repository
+`mediawiki/services/name_in_gerrit` when checking it out in the deploy
+repository.
+
+## Testing
+
+Before updating the deploy repository you need to make sure your configuration
+works as expected. To do that, in your source repository run:
+
+```
+./server.js docker-test
+```
+
+The script will build a new Docker image, install the needed packages and npm
+dependencies and run the test suite. Tweak your code and configuration until
+everything works as expected (and commit those changes).
+
+## Update
+
+The final step is updating the deploy repository. From the source repository
+run:
+
+```
+./server.js build --deploy-repo
+```
+
+The script will:
+- create the proper deploy repository outline
+- fetch the updates
+- ensure the submodule is present
+- update the submodule
+- build the npm dependencies
+- commit the changes with a pretty-formatted message
+
+There is also a handy shortcut for sending the patch to Gerrit immediately. To
+do so, add the `--review` argument to the call:
+
+```
+./server.js build --deploy-repo --review
+```
+
+Note that if no changes were made to the source repository, the script aborts
+its execution. If, nevertheless, you need to rebuild the dependencies, you can
+do so using:
+
+```
+./server.js build --deploy-repo --force
+```
+
diff --git a/doc/template.md b/doc/template.md
index b8c9af9..f9d28ad 100644
--- a/doc/template.md
+++ b/doc/template.md
@@ -41,7 +41,7 @@
The WMF is in the process of switching its production servers to Debian Jessie.
As people developing services might use different platforms, the template
provides also a Dockerfile, with which one can execute their service inside a
-container running Debian Jessie.
+container running the production OS.
## Repository Outline
@@ -62,6 +62,6 @@
client-side JS, etc.)
- [`test`](../test/) - contains the test files for the example routes in the
template; you should add your own here
-- [`scripts/docker.js`](../scripts/docker.js) - a utility script building the
- service's docker image and starting the container
+- docker script - a utility script building the service's docker image and
+ starting the container, now part of
[service-runner](wikimedia/service-runner)
diff --git a/lib/util.js b/lib/util.js
index 58ed1e3..9db1055 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -190,8 +190,8 @@
level = 'info';
}
// log the error
- req.logger.log(level +
- (errObj.component ? '/' + errObj.component : '/' +
errObj.status),
+ (req.logger || app.logger).log(level + '/' +
+ (errObj.component ? errObj.component : errObj.status),
errForLog(errObj));
// let through only non-sensitive info
var respBody = {
diff --git a/package.json b/package.json
index 4223f67..3c69df8 100644
--- a/package.json
+++ b/package.json
@@ -6,9 +6,8 @@
"scripts": {
"start": "service-runner",
"test": "mocha",
- "docker-start": "./scripts/docker.js",
- "docker-test": "./scripts/docker.js --test",
- "docker-cover": "./scripts/docker.js --cover",
+ "docker-start": "service-runner docker-start",
+ "docker-test": "service-runner docker-test",
"coverage": "istanbul cover _mocha -- -R spec"
},
"repository": {
@@ -27,26 +26,32 @@
"contributors": [],
"license": "Apache2",
"bugs": {
- "url": "https://phabricator.wikimedia.org/tag/services/"
+ "url": "https://phabricator.wikimedia.org/tag/service-template-node/"
},
"homepage": "https://github.com/wikimedia/service-mobileapp-node",
"dependencies": {
- "bluebird": "^2.9.14",
- "body-parser": "^1.12.1",
- "bunyan": "^1.3.4",
+ "bluebird": "^2.9.24",
+ "body-parser": "^1.12.3",
+ "bunyan": "^1.3.5",
"compression": "^1.4.3",
"domino": "^1.0.18",
- "express": "^4.12.2",
+ "express": "^4.12.3",
"js-yaml": "^3.2.7",
"node-uuid": "^1.4.3",
- "preq": "^0.3.12",
- "service-runner": "^0.1.5"
+ "preq": "^0.3.13",
+ "service-runner": "^0.1.8"
},
"devDependencies": {
"assert": "^1.3.0",
- "istanbul": "^0.3.8",
- "mocha": "^2.2.1",
+ "istanbul": "^0.3.13",
+ "mocha": "^2.2.4",
"mocha-jshint": "0.0.9",
"mocha-lcov-reporter": "0.0.1"
+ },
+ "deploy": {
+ "target": "ubuntu",
+ "dependencies": {
+ "_all": []
+ }
}
}
diff --git a/scripts/docker.js b/scripts/docker.js
deleted file mode 100755
index 0b4b433..0000000
--- a/scripts/docker.js
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/usr/bin/env node
-
-
-'use strict';
-
-var fs = require('fs');
-var spawn = require('child_process').spawn;
-var P = require('bluebird');
-
-
-// load info from the package definition
-var pkg = require('../package.json');
-// load info from the service-runner config file
-var config = require('js-yaml').safeLoad(fs.readFileSync(__dirname +
'/../config.yaml'));
-
-// use the package's name as the image name
-var img_name = pkg.name;
-// the container's name
-var name = pkg.name + '-' + Date.now() + '-' + Math.floor(Math.random() *
1000);
-
-// holds the curently running process
-var child;
-
-
-/**
- * Wraps a child process spawn in a promise which resolves
- * when the child process exists.
- *
- * @param {Array} args the command and its arguments to run (uses /usr/bin/env)
- * @return {Promise} the promise which is fulfilled once the child exists
- */
-function promised_spawn(args) {
-
- return new P(function(resolve, reject) {
- child = spawn('/usr/bin/env', args, {stdio: 'inherit'});
- child.on('exit', resolve);
- });
-
-}
-
-
-/**
- * Spawns a docker process which (re)builds the image
- *
- * @return {Promise} the promise starting the build
- */
-function build_img() {
-
- return promised_spawn(['docker', 'build', '-t', img_name, '.']);
-
-}
-
-
-/**
- * Starts the container either using the default script
- * (npm start) or the test script (npm test) if do_tests is set
- *
- * @param {Object} options additional options
- * @prop {Boolean} tests whether to start the tests instead of the service
- * @prop {Boolean} coverage whether to start the tests and coverage instead
of the service
- * @return {Promise} the promise starting the container
- */
-function start_container(options) {
-
- var cmd = ['docker', 'run', '--name', name];
-
- // list all of the ports defined in the config file
- config.services.forEach(function(srv) {
- srv.conf = srv.conf || {};
- srv.conf.port = srv.conf.port || 8888;
- cmd.push('-p', srv.conf.port + ':' + srv.conf.port);
- });
-
- // append the image name to create a container from
- cmd.push(img_name);
-
- // use a different command to run inside if
- // we have to run the tests or coverage
- if(options.tests) {
- cmd.push('/usr/bin/npm', 'test');
- } else if(options.coverage) {
- cmd.push('/usr/bin/npm', 'run-script', 'coverage');
- }
-
- // ok, start the container
- return promised_spawn(cmd);
-
-}
-
-
-/**
- * Deletes the container
- *
- * @return {Promise} the promise removing the container
- */
-function remove_container() {
-
- return promised_spawn(['docker', 'rm', name]);
-
-}
-
-
-/**
- * Main process signal handler
- */
-function sig_handle() {
- if(child) {
- child.kill('SIGINT');
- }
-}
-
-
-function main(options) {
-
- // trap exit signals
- process.on('SIGINT', sig_handle);
- process.on('SIGTERM', sig_handle);
-
- // change the dir
- process.chdir(__dirname + '/..');
-
- // start the process
- return build_img()
- .then(function() {
- return start_container(options);
- })
- .then(remove_container);
-
-}
-
-
-if(module.parent === null) {
-
- var opts = {
- tests: false,
- coverage: false
- };
-
- // check for command-line args
- var args = process.argv.slice(2);
- var arg;
- while((arg = args.shift()) !== undefined) {
- switch(arg) {
- case '-t':
- case '--test':
- opts.tests = true;
- break;
- case '-c':
- case '--cover':
- opts.coverage = true;
- break;
- default:
- console.log('This is a utility script for starting service
containers using docker.');
- console.log('Usage: ' + process.argv.slice(0, 2).join(' ') + '
[OPTIONS]');
- console.log('Options are:');
- console.log(' -t, --test instead of starting the service,
run the tests');
- console.log(' -c, --cover run the tests and report the
coverage info');
- process.exit(/^-(h|-help)/.test(arg) ? 0 : 1);
- }
- }
-
- // start the process
- main(opts);
-
-} else {
-
- module.exports = main;
-
-}
-
diff --git a/scripts/gen-init-scripts.rb b/scripts/gen-init-scripts.rb
new file mode 100755
index 0000000..e523b97
--- /dev/null
+++ b/scripts/gen-init-scripts.rb
@@ -0,0 +1,71 @@
+#!/usr/bin/env ruby
+
+
+require 'erb'
+require 'json'
+require 'yaml'
+
+
+rootdir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+indir = File.join(rootdir, 'dist', 'init-scripts')
+outdir = indir
+
+
+class ScriptData
+
+ include ERB::Util
+
+ @@suffix = {'systemd' => '.service', 'upstart' => '.conf'}
+
+ def initialize input_dir
+ @template = {}
+ self.init input_dir
+ end
+
+ def set_info root_dir
+ self.read_info(root_dir).each do |key, value|
+ self.instance_variable_set "@#{key}".to_sym, value
+ end
+ @service_name = @name
+ @no_file ||= 10000
+ end
+
+ def generate output_dir
+ @template.each do |name, erb|
+ File.open(File.join(output_dir, "#{@name}#{@@suffix[name]}"), 'w') do
|io|
+ io.write erb.result(binding())
+ end
+ end
+ end
+
+ def init input_dir
+ Dir.glob(File.join(input_dir, '*.erb')).each do |fname|
+ @template[File.basename(fname, '.erb')] = ERB.new(File.read(fname))
+ end
+ end
+
+ def read_info root_dir
+ data = YAML.load(File.read(File.join(root_dir,
'config.yaml')))['services'][0]['conf']
+ return data.merge(JSON.load(File.read(File.join(root_dir,
'package.json'))))
+ end
+
+end
+
+
+if ARGV.size > 0 and ['-h', '--help'].include? ARGV[0]
+ puts 'This is a simple script to generate various service init scripts'
+ puts 'Usage: gen-init-scripts.rb [output_dir]'
+ exit 1
+elsif ARGV.size > 0
+ outdir = ARGV[0]
+end
+
+unless File.directory? outdir
+ STDERR.puts 'The output directory must exist! Aborting...'
+ exit 2
+end
+
+data = ScriptData.new indir
+data.set_info rootdir
+data.generate outdir
+
diff --git a/targets.yaml b/targets.yaml
new file mode 100644
index 0000000..6a16a18
--- /dev/null
+++ b/targets.yaml
@@ -0,0 +1,3 @@
+debian: 'debian:jessie'
+ubuntu: 'ubuntu:14.04'
+
diff --git a/test/features/app/app.js b/test/features/app/app.js
index 0ed4b7d..ce20eda 100644
--- a/test/features/app/app.js
+++ b/test/features/app/app.js
@@ -25,5 +25,41 @@
});
});
+ it('should set CORS headers', function() {
+ return preq.get({
+ uri: server.config.uri + 'robots.txt'
+ }).then(function(res) {
+ assert.deepEqual(res.status, 200);
+ assert.deepEqual(res.headers['access-control-allow-origin'], '*');
+ assert.notDeepEqual(res.headers['access-control-allow-headers'],
undefined);
+ });
+ });
+
+ it('should set CSP headers', function() {
+ return preq.get({
+ uri: server.config.uri + 'robots.txt'
+ }).then(function(res) {
+ assert.deepEqual(res.status, 200);
+ assert.deepEqual(res.headers['x-xss-protection'], '1; mode=block');
+ assert.deepEqual(res.headers['x-content-type-options'], 'nosniff');
+ assert.deepEqual(res.headers['x-frame-options'], 'SAMEORIGIN');
+ assert.deepEqual(res.headers['content-security-policy'],
'default-src');
+ assert.deepEqual(res.headers['x-content-security-policy'],
'default-src');
+ assert.deepEqual(res.headers['x-webkit-csp'], 'default-src');
+ });
+ });
+
+ it('should get static content uncompressed', function() {
+ return preq.get({
+ uri: server.config.uri + 'static/index.html',
+ headers: {
+ 'accept-encoding': ''
+ }
+ }).then(function(res) {
+ // check that the response is gzip-ed
+ assert.deepEqual(res.headers['content-encoding'], undefined, 'Did
not expect gzipped contents!');
+ });
+ });
+
});
--
To view, visit https://gerrit.wikimedia.org/r/205863
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibbe14ffec488b5791ab3ea4ff5923aee9e2c0ae1
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/services/mobileapps
Gerrit-Branch: master
Gerrit-Owner: Mobrovac <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits