Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Windshaft #3109

Merged
merged 14 commits into from Jun 27, 2019
Merged
5 changes: 4 additions & 1 deletion deployment/ansible/group_vars/all
Expand Up @@ -28,7 +28,10 @@ daemontools_version: "1:0.76-6ubuntu1"

python_version: "2.7.12-1~16.04"

nodejs_npm_version: 2.1.17
app_nodejs_version: "0.10.32"
app_nodejs_npm_version: "2.1.17"
tiler_nodejs_version: "10.16.0"
tiler_nodejs_npm_version: "6.9.0"

java_version: "8u*"
java_major_version: "8"
Expand Down
Expand Up @@ -3,7 +3,7 @@ dependencies:
- { role: "model-my-watershed.base" }
- { role: "azavea.python", python_development: True }
- { role: "azavea.pip" }
- { role: "azavea.nodejs" }
- { role: "azavea.nodejs", nodejs_version: "{{ app_nodejs_version }}", nodejs_npm_version: "{{ app_nodejs_npm_version }}" }
- { role: "azavea.phantomjs" }
- { role: "azavea.build-essential" }
- { role: "model-my-watershed.celery" }
Expand Down
Expand Up @@ -16,13 +16,6 @@
chdir: "{{ app_home }}"
become: False

- name: Check for lint
command: "npm run lint"
args:
chdir: "{{ app_home }}"
become: False
ignore_errors: True

- name: Create JS bundles (staging/production)
command: "./bundle.sh --vendor --tests"
args:
Expand Down
@@ -1,5 +1,5 @@
---
dependencies:
- { role: "model-my-watershed.base" }
- { role: "azavea.nodejs" }
- { role: "azavea.nodejs", nodejs_version: "{{ tiler_nodejs_version }}", nodejs_npm_version: "{{ tiler_nodejs_npm_version }}" }
- { role: "azavea.nginx", nginx_delete_default_site: True }
Expand Up @@ -19,6 +19,4 @@
command: npm install --unsafe-perm
args:
chdir: "{{ tiler_home }}"
environment:
PKG_CONFIG_PATH: "/usr/lib/pkgconfig/pycairo.pc"
become: False
23 changes: 23 additions & 0 deletions deployment/ansible/tile-servers.yml
Expand Up @@ -6,5 +6,28 @@
- name: Update APT cache
apt: update_cache=yes cache_valid_time=3600

- name: Create a node_modules directory
file:
path: "/opt/tiler/node_modules"
state: directory
owner: "vagrant"
group: "vagrant"
when: "['development', 'test'] | some_are_in(group_names)"

- name: Create a node_modules cache directory
file:
path: "/var/cache/node_modules"
state: directory
owner: "vagrant"
group: "vagrant"
mode: "0755"
when: "['development', 'test'] | some_are_in(group_names)"

- name: Create bind mount for node_modules cache
command: "mount --bind /var/cache/node_modules /opt/tiler/node_modules"
args:
warn: no
when: "['development', 'test'] | some_are_in(group_names)"

roles:
- { role: "model-my-watershed.tiler" }
3 changes: 3 additions & 0 deletions src/tiler/.jshintrc
@@ -0,0 +1,3 @@
{
"esversion": 6
}
6 changes: 3 additions & 3 deletions src/tiler/healthCheck.js
@@ -1,6 +1,6 @@
var Step = require('windshaft/node_modules/step');
var Pg = require('windshaft/node_modules/cartodb-psql/node_modules/pg');
var Redis = require('windshaft/node_modules/redis-mpool/node_modules/redis');
var Step = require('step');
var Pg = require('pg');
var Redis = require('redis');

/**
* Attempts to connect to a PostgreSQL database, providing the
Expand Down
145 changes: 145 additions & 0 deletions src/tiler/http/mapController.js
@@ -0,0 +1,145 @@
'use strict';

var step = require('step');
var windshaft = require('windshaft');
var _ = require('underscore');

var MapConfig = windshaft.model.MapConfig;
var DummyMapConfigProvider = require('windshaft/lib/windshaft/models/providers/dummy_mapconfig_provider');
var MapStoreMapConfigProvider = windshaft.model.provider.MapStoreMapConfig;

/**
* @param app
* @param {MapStore} mapStore
* @param {MapBackend} mapBackend
* @param {TileBackend} tileBackend
* @constructor
*/
function MapController(app, mapStore, mapBackend, tileBackend) {
this._app = app;
this.mapStore = mapStore;
this.mapBackend = mapBackend;
this.tileBackend = tileBackend;
}

MapController.prototype.register = function(app) {
var tile = this.tile.bind(this);
var cors = this.cors.bind(this);

app.get(app.base_url + '/:z/:x/:y@:scale_factor?x.:format(png|grid\.json)', tile);
app.get(app.base_url + '/:z/:x/:y.:format(png|grid\.json)', tile);
app.options(app.base_url, cors);
};

// send CORS headers when client send options.
MapController.prototype.cors = function(req, res, next) {
this._app.doCORS(res, 'Content-Type');
return next();
};

MapController.prototype.create = function initLayergroup(req, mapConfig, callback) {
this.mapBackend.createLayergroup(
mapConfig, req.params, new DummyMapConfigProvider(mapConfig, req.params), callback
);
};

// Gets a tile for a given token and set of tile ZXY coords. (OSM style)
MapController.prototype.tile = function(req, res) {
var self = this;
var mapConfig;

this._app.doCORS(res);
step(
function mapController$prepareParams() {
self._app.req2params(req, this);
},
function mapController$getMapConfig(err) {
mapConfig = MapConfig.create({
layers: [{
type: 'mapnik',
options: {
sql: req.params.sql,
cartocss: req.params.style,
cartocss_version: '2.0.1',
interactivity: req.params.interactivity,
geom_column: 'geom',
}
}]
});
self.mapStore.load(mapConfig.id(), this);
},
function mapController$saveMapConfig(err, layer) {
if (layer) {
this(null, layer);
} else {
self.create(req, mapConfig, this);
}
},
function mapController$getTile(err, layer) {
if ( err ) {
throw err;
}
req.params.token = layer.layergroupid;
self.tileBackend.getTile(new MapStoreMapConfigProvider(self.mapStore, req.params), req.params, this);
},
function mapController$finalize(err, tile, headers) {
self.finalizeGetTileOrGrid(err, req, res, tile, headers);
self._app.cacheTile(req, tile);
return null;
},
function finish(err) {
if ( err ) {
// TODO Replace with Rollbar
console.error("windshaft.tiles: " + err);
}
}
);
};

// This function is meant for being called as the very last
// step by all endpoints serving tiles or grids
MapController.prototype.finalizeGetTileOrGrid = function(err, req, res, tile, headers) {
if (err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var errMsg = err.message ? ( '' + err.message ) : ( '' + err );

// Rewrite mapnik parsing errors to start with layer number
var matches = errMsg.match("(.*) in style 'layer([0-9]+)'");
if (matches) {
errMsg = 'style'+matches[2]+': ' + matches[1];
}

var status = err.http_status || statusFromErrorMessage(errMsg);

this._app.sendError(res, { errors: [errMsg] }, status, 'TILE', err);
} else {
res.status(200)
// Add cache header for 30 days
.set(_.extend(headers, { 'Cache-Control': 'max-age=2592000' }))
.send(tile);
}
};

function statusFromErrorMessage(errMsg) {
// Find an appropriate statusCode based on message
var statusCode = 400;
if ( -1 !== errMsg.indexOf('permission denied') ) {
statusCode = 403;
}
else if ( -1 !== errMsg.indexOf('authentication failed') ) {
statusCode = 403;
}
else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) {
statusCode = 400;
}
else if ( -1 !== errMsg.indexOf('does not exist') ) {
if ( -1 !== errMsg.indexOf(' role ') ) {
statusCode = 403; // role 'xxx' does not exist
} else {
statusCode = 404;
}
}
return statusCode;
}

module.exports = MapController;
9 changes: 9 additions & 0 deletions src/tiler/http/rollbar.js
@@ -0,0 +1,9 @@
'use strict';

var Rollbar = require('rollbar'),
token = process.env.ROLLBAR_SERVER_SIDE_ACCESS_TOKEN;

module.exports = token ? new Rollbar(token) : {
handleError: ex => { console.error(ex); },
errorHandler: () => {},
};