Relic Solution: Include fixtures in Scripted Monitors with custom local modules and the CPM

With the release of the Containerized Private Minion also came a new capability, the ability to include custom node-modules in scripted monitor runtime.

Not only does this mean you can import node modules of your choice from NPM, but this also includes the option of local modules as well.

In this post we’ll create a custom local node module called my-fixtures that exposes a getter for a file called test.txt

Setting up the custom modules directory

To start lets have on the host of our CPM a directory called custom-modules/ that will expose to the CPM the package.json that has all of our node module dependencies that we want in our runtime.

custom-modules/
   |-package.json

In our run command for the CPM, this directory is included like so:

docker run -d \
    -e MINION_PRIVATE_LOCATION_KEY={MY-PRIVATE-LOCATION-KEY} \
    -v /custom-modules:/var/lib/newrelic/synthetics/modules:rw \
    -v /tmp:/tmp:rw  \
    -v /var/run/docker.sock:/var/run/docker.sock \
    quay.io/newrelic/synthetics-minion:latest

We’ll create our own custom local node module called my-fixtures that will help expose files that we want to read from in our scripted monitors.

In /custom-modules create a directory called local_modules where we’ll include all local modules we develop, and another directory specifically for our my-fixtures module.

custom-modules/
   |- local_modules/
      |- my-fixtures/
   |- package.json

In our package.json in /custom-modules we’ll include our my-fixtures module as a dependency:

{
  "name": "custom-modules",
  "version": "1.0.1",
  "description": "example custom modules directory",
  "dependencies": {
    "my-fixtures": "file:local_modules/my-fixtures"
  }
}

Creating our local custom module

Next lets develop our my-fixtures module:

  1. We’ll need an additional package.json for the module itself and an entry js file, index.js. The package.json for our my-fixtures module can read as such:
{ 
    "name":"my-fixtures",
    "version":"0.0.1",
    "main":"index.js"
  }
  1. Lets include the files we want to have exposed in our runtime in a sub-folder in our module called fixtures. To start lets include a file called test.txt that contains the content “Hello World!” Our project directory should look like this so far:
custom-modules/
   |- local_modules/
      |- my-fixtures/
         |- fixtures/
            |- test.txt
         |- index.js
         |- package.json
   |- package.json
  1. The index.js for our module will expose helper getter functions that perform reads of those files. Minimally, our index.js can look like this:
const fs = require('fs')
const path = require('path')

module.exports = {
    getTestFixture: function() {
        return fs.readFileSync(path.resolve(__dirname,'./fixtures/test.txt'), {encoding: 'UTF-8'})
    }
}

Using our custom module

Now we are ready to use our my-fixtures custom module in a scripted monitor. Launch the CPM with the -v /custom-modules:/var/lib/newrelic/synthetics/modules:rw \ run option shared earlier. The CPM will build the dependencies described in package.json in custom-modules.

We can test this in an API Test monitor with the following script:

const f = require('my-fixtures')
const testFixture = f.getTestFixture();

console.log(testFixture)

You should see print to the script log the contents of test.txt!

Note
If you make any modifications to your custom module, you’ll need to delete a cache of the node_modules created by the CPM on host. This is stored in your custom node module directory as a hidden dot file named after a runtime version, for example .3.0.0

custom_modules/
   |-.3.0.0
...
7 Likes