From b337665f3b187e7563b66ba40216ce45f42001bc Mon Sep 17 00:00:00 2001 From: Maciej Laskowski Date: Tue, 27 Aug 2019 14:43:11 +0200 Subject: [PATCH] lighthouse image for aet --- lighthouse-beta/Dockerfile | 65 ++++++++++++++++++++ lighthouse-beta/README.md | 27 +++++++++ lighthouse-beta/package.json | 15 +++++ lighthouse-beta/server.js | 112 +++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 lighthouse-beta/Dockerfile create mode 100644 lighthouse-beta/README.md create mode 100644 lighthouse-beta/package.json create mode 100644 lighthouse-beta/server.js diff --git a/lighthouse-beta/Dockerfile b/lighthouse-beta/Dockerfile new file mode 100644 index 0000000..a6ed0ba --- /dev/null +++ b/lighthouse-beta/Dockerfile @@ -0,0 +1,65 @@ +# +# AET Docker +# +# Copyright (C) 2019 Maciej Laskowski +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# This Dockerfile is inspired by https://github.com/GoogleChromeLabs/lighthousebot/tree/master/builder, +# originally by Eric Bidelman +# +FROM node:10-slim + +LABEL maintainer="Maciej Laskowski " + +# Install utilities +RUN apt-get update --fix-missing && apt-get -y upgrade + +# Install latest chrome dev package. +RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \ + && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \ + && apt-get update \ + && apt-get install -y google-chrome-stable --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /src/*.deb + +ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 /usr/local/bin/dumb-init +RUN chmod +x /usr/local/bin/dumb-init + +# Download latest Lighthouse from npm. +# cache bust so we always get the latest version of LH when building the image. +ARG CACHEBUST=1 +RUN npm i lighthouse -g + +# Install express. +COPY config/package.json . +RUN npm i --production + +# Add the simple server. +COPY config/server.js / +RUN chmod +x /server.js + +# Add a chrome user and setup home dir. +RUN groupadd --system chrome && \ + useradd --system --create-home --gid chrome --groups audio,video chrome && \ + mkdir --parents /home/chrome/reports && \ + chown --recursive chrome:chrome /home/chrome + +USER chrome + +# Disable Lighthouse error reporting to prevent prompt. +ENV CI=true + +EXPOSE 5000 + +ENTRYPOINT ["dumb-init", "--", "npm", "run", "start"] diff --git a/lighthouse-beta/README.md b/lighthouse-beta/README.md new file mode 100644 index 0000000..7355de7 --- /dev/null +++ b/lighthouse-beta/README.md @@ -0,0 +1,27 @@ +> Work In Progress... + +# AET Lighthouse Docker image + +Since there is still no official Lighthouse Docker image, +this one is forked https://github.com/GoogleChromeLabs/lighthousebot/tree/master/builder +and adjusted to AET needs. + +## Running +Execute: + +`docker run -dit -p 5000:5000 --rm --name lighthouse_aet --cap-add=SYS_ADMIN skejven/aet_lighthouse` + +## Limitations + +### Lighthouse and Docker +Currently Lighthouse does not have official Docker image. +`aet_lighthouse` image is inspired by https://github.com/GoogleChromeLabs/lighthousebot/tree/master/builder. +What more, this image can't be deployed with Docker Swarm, because it requires `SYS_ADMIN` capabilities +which is not supported in swarm mode. + +What is more, Lighthouse on Docker runs quite unstable... If you can use another Lighthouse instance, it will +probably be a good idea. + +### Max 1 url +Yes... This is due to lack of scaling Lighthouse instance. If you play with that module, please remember +to have max 1 url running it in your suite. \ No newline at end of file diff --git a/lighthouse-beta/package.json b/lighthouse-beta/package.json new file mode 100644 index 0000000..577a6bb --- /dev/null +++ b/lighthouse-beta/package.json @@ -0,0 +1,15 @@ +{ + "name": "aet-lighthouse-server", + "version": "1.0.0", + "description": "AET Lighthouse Server", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "author": "Maciej Laskowski", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "body-parser": "^1.19.0" + } +} diff --git a/lighthouse-beta/server.js b/lighthouse-beta/server.js new file mode 100644 index 0000000..f42754e --- /dev/null +++ b/lighthouse-beta/server.js @@ -0,0 +1,112 @@ +/* + * aet-extensions: lighthouse + * + * Copyright (C) 2019 Maciej Laskowski + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +'use strict'; + +const express = require('express'); +const bodyParser = require('body-parser'); + +const spawn = require('child_process').spawn; +const fs = require('fs'); + +const WORK_DIR = `reports`; + +function validURL(url, res) { + if (!url) { + res.status(400).send('Please provide a URL.'); + return false; + } + + if (!url.startsWith('http')) { + res.status(400).send('URL must start with http.'); + return false; + } + + return true; +} + +function cleanUp(fileName) { + try { + fs.unlinkSync(`${WORK_DIR}/${fileName}`); + console.info(`${fileName} removed`); + } catch (err) { + console.error(err) + } +} + +function respond(fileName, start, res) { + try { + let rawData = fs.readFileSync(`${WORK_DIR}/${fileName}`); + let reportAsJson = JSON.parse(rawData); + const duration = Date.now() - start; + res.status(200).send({ + duration: duration, + report: reportAsJson + }); + } catch (err) { + console.error(err); + res.status(500).send(`Failed to create response: ${err}`); + } +} + +function callLighthouseAndRespond(args, url, res, start, fileName) { + return new Promise(resolve => { + console.log(`Running: lighthouse ${args} ${url}`); + const child = spawn('lighthouse', [...args, url]); + child.stderr.pipe(process.stderr); + child.stdout.pipe(process.stdout); + + child.on('close', statusCode => { + respond(fileName, start, res); + cleanUp(fileName); +}); +}) +} + +function runLighthouse(body, res, next, order) { + const url = body.url; + //ToDo rest of the params + const start = Date.now(); + if (!validURL(url, res)) { + return; + } + const format = 'json'; + const fileName = `report.${start}.${format}`; + const args = [ + `--chrome-flags="--headless`,// --disable-gpu"`, + `--output-path=${WORK_DIR}/${fileName}`, + `--output=${format}`, + `--port=0` + ]; + callLighthouseAndRespond(args, url, res, start, fileName, order); +} + +/* + * Server initialization + */ +const app = express(); +app.use(bodyParser.json()); + +app.post('/api/v1/inspect', (req, res, next) => { + console.log(`processing ${req.query.url}`); +runLighthouse(req.body, res, next); +}); + +const PORT = 5000; + +app.listen(PORT, () => { + console.log(`server running on port ${PORT}`) +});