Skip to content
Merged

NSS #56

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions packages/lambda/nss/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# NSS

NSS is a library required by chrome to run. Unfortunately the version provided
by the AWS lambda image is too old, so it's necessary to build it.

## Building

Start a smallish EC2 instance using the same AMI as lambda. You can find a link
to it [here][1]. Build on the instance using the following (adapted from
instructions found [here][2]):

```shell
sudo yum install mercurial
sudo yum groupinstall 'Development Tools'
sudo yum install zlib-devel

hg clone https://hg.mozilla.org/projects/nspr
hg clone https://hg.mozilla.org/projects/nss

cd nss

export BUILD_OPT=1
export USE_64=1
export NSDISTMODE=copy

gmake nss_build_all
```

Remove any simlinks in the `dist` directory (they'll be links to .chk files) and
zip it up for grabbing by scp. Place the archive in this folder (I've used a
reverse date and the commit hash as a name), and replace the name in the
lambda package file.

[1]: http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
[2]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Reference/Building_and_installing_NSS/Build_instructions
Binary file not shown.
4 changes: 2 additions & 2 deletions packages/lambda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
},
"config": {
"jsSrc": "src/",
"chromeVersion": "61.0.3135.0",
"tarballChecksum": "not implemented"
"chromeZipFileName": "chrome-headless-lambda-linux-62.0.3181.0.zip",
"nssZipFileName": "nss-2017-08-10-990be4e30bf8.zip"
},
"scripts": {
"test": "npm run lint && nyc ava",
Expand Down
72 changes: 50 additions & 22 deletions packages/lambda/scripts/postinstall.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
/*
@TODO: only download the archive if we haven't already downloaded it.
@TODO: peg to an archive version, so each package version only downloads specific chrome version
using pkg.config.chromeVersion
@TODO: checksum/crc check on archive using pkg.config.tarballChecksum
*/
const fs = require('fs')
const path = require('path')
const https = require('https')
const extract = require('extract-zip')

const TARBALL_FILENAME = 'chrome-headless-lambda-linux-60.0.3095.0.zip'
const TARBALL_URL = `https://raw.githubusercontent.com/adieuadieu/serverless-chrome/develop/packages/lambda/chrome/${TARBALL_FILENAME}`
const DOWNLOAD_PATH = path.resolve(__dirname, '../', TARBALL_FILENAME)
const EXTRACT_PATH = path.resolve(__dirname, '../', 'dist')
function unlink(path) {
return new Promise((resolve, reject) => {
fs.unlink(path, err => err ? reject(err) : resolve());
});
}

function rename(from, to) {
return new Promise((resolve, reject) => {
fs.rename(from, to, err => err ? reject(err) : resolve());
})
}

function extractFile (file, destination) {
return new Promise((resolve, reject) => {
extract(file, { dir: destination }, err => err ? reject(err) : resolve());
})
}

function download (url = TARBALL_URL, destination = DOWNLOAD_PATH) {
function download (url, destination) {
const file = fs.createWriteStream(destination)

return new Promise((resolve, reject) => {
Expand All @@ -33,25 +44,42 @@ function download (url = TARBALL_URL, destination = DOWNLOAD_PATH) {
})
}

// unzips and makes path.txt point at the correct executable
function extractFile (file = DOWNLOAD_PATH, destination = EXTRACT_PATH) {
return new Promise((resolve, reject) => {
extract(file, { dir: destination }, (error) => {
if (error) {
return reject(error)
}
const RAW_PACKAGES_URL = 'https://raw.githubusercontent.com/qubyte/serverless-chrome/nss/packages';

return resolve()
})
})
function downloadChrome() {
const ZIP_FILENAME = process.env.npm_package_config_chromeZipFileName;
const ZIP_URL = `${RAW_PACKAGES_URL}/lambda/chrome/${ZIP_FILENAME}`
const DOWNLOAD_PATH = path.resolve(__dirname, '..', ZIP_FILENAME)
const EXTRACT_PATH = path.resolve(__dirname, '..', 'dist')

console.log('Downloading precompiled headless Chrome binary for AWS Lambda.')

return download(ZIP_URL, DOWNLOAD_PATH)
.then(() => extractFile(DOWNLOAD_PATH, EXTRACT_PATH))
.then(() => unlink(DOWNLOAD_PATH))
.then(() => console.log('Completed Chrome download.'))
.catch(error => console.error(error))
}

if (require.main === module) {
console.log('Downloading precombiled headless Chrome binary for AWS Lambda')
function downloadNss() {
const ZIP_FILENAME = process.env.npm_package_config_nssZipFileName;
const ZIP_URL = `${RAW_PACKAGES_URL}/lambda/nss/${ZIP_FILENAME}`
const DOWNLOAD_PATH = path.resolve(__dirname, '..', ZIP_FILENAME)
const EXTRACT_PATH = path.resolve(__dirname, '..', 'dist')

download().then(extractFile).then(() => fs.unlink(DOWNLOAD_PATH)).catch((error) => {
console.error(error)
})
console.log('Downloading precompiled NSS library and binaries for AWS Lambda.')

return download(ZIP_URL, DOWNLOAD_PATH)
.then(() => extractFile(DOWNLOAD_PATH, EXTRACT_PATH))
.then(() => unlink(DOWNLOAD_PATH))
.then(() => rename(path.join(EXTRACT_PATH, 'dist'), path.join(EXTRACT_PATH, 'nss')))
.then(() => console.log('Completed NSS download.'))
.catch(error => console.error(error))
}

if (require.main === module) {
downloadChrome()
.then(downloadNss);
}

module.exports = {
Expand Down
10 changes: 10 additions & 0 deletions packages/lambda/src/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import fs from 'fs'
import path from 'path'
import LambdaChromeLauncher from './launcher'
import { debug } from './utils'
import DEFAULT_CHROME_FLAGS from './flags'

const DEVTOOLS_PORT = 9222
const DEVTOOLS_HOST = 'http://127.0.0.1'

// Prepend NSS related libraries and binaries to the library path and path respectively on lambda.
if (process.env.AWS_EXECUTION_ENV) {
const nssSubPath = fs.readFileSync(path.join(__dirname, 'nss', 'latest'), 'utf8').trim();
const nssPath = path.join(__dirname, 'nss', subnssSubPathPath);

process.env.LD_LIBRARY_PATH = path.join(nssPath, 'lib') + ':' + process.env.LD_LIBRARY_PATH;
process.env.PATH = path.join(nssPath, 'bin') + ':' + process.env.PATH;
}

// persist the instance across invocations
// when the *lambda* container is reused.
let chromeInstance
Expand Down