Relic Solution: FTP, SFTP, LDAP, TCP, and SMTP Examples

Additional modules are now available that allow users to monitor FTP, FTPS, SFTP, LDAP, TCP, and SMTP in addition to the HTTP, HTTPS, DNS, ICMP, SNMP, and traceroute capabilities that have been historically available in Synthetics. These simplified examples will get you started using these new modules to quickly expand protocol coverage. Additional assertions and error checks may be needed to verify success. Use the individual module links below to learn more about module usage and capabilities.

FTP/FTPS
Module: basic-ftp

Example Description:

  1. Connect to a FTP server using a password that is stored as a secure credential
  2. Lists the current directory contents
  3. Closes the connection

Example Monitor:

var ftp = require('basic-ftp');

example()

function example() {
const client = new ftp.Client()
client.ftp.verbose = true
client.access({
host: "MyFTPServer",
user: "FTPUser",
password: $secure.FTP_PASSWORD
 }).then(function() {
return client.list();
 }) 
 .then(function(list) {
console.log(list)
 })
 .then(function() {
client.close()
 })
}

SFTP
Module: ssh2-sftp-client

Example Description:

  1. Connect to a SFTP server using a password that is stored as a secure credential
  2. Create a test .txt file that will be used to test upload capabilities
  3. Delete the test file from the SFTP server if found
  4. Upload the test file to the SFTP server
  5. Download the test file from the SFTP server
  6. Delete the test file from the SFTP server

Example Monitor:

const Client = require('ssh2-sftp-client');
var fs = require ('fs');
var endpoint = 'YourSFTPServer';

// Create a simple test file.
fs.writeFileSync('test-sftp.txt', 'Hello World from New Relic Synthetics');
var testFile = fs.createReadStream('test-sftp.txt');
var remotePath = '/test-sftp.txt';

const config = {
host: endpoint,
username: 'MyUsername',
password: $secure.MY_PASSWORD,
   // You only need to define algorithms if your server is still using ssh-dss
algorithms: {
  serverHostKey: ['ssh-rsa', 'ssh-dss']
    }
}

const sftp = new Client('US');

// Connect to the SFTP server using the configuration defined above.
sftp.connect(config)

// Check if our test file exists before issuing put. Delete it and then proceed if so.
.then(function() {
    return sftp.exists(remotePath);
})

.then(function(bool) {
    if(bool) 
    {
        console.log('Test file from previous run exists. Removing.')
        return sftp.delete(remotePath);
    }
    else
    {
        console.log('No test files from previous executions. Proceeding.');
    }
})

.then(function () {
    console.log('Putting test file on SFTP server.');
    return sftp.put(testFile, remotePath);
})

.then(function () {
    console.log('Getting test file from SFTP server.');
    var destination = fs.createWriteStream('test-sftp-download.txt');
    return sftp.get(remotePath, destination)
})

.then(function () {
    var fileContents = fs.readFileSync('test-sftp-download.txt');
    console.log('Reading downloaded test file.');
    console.log(fileContents.toString())
})

.then(function() {
    console.log('Deleting test file from FTP server.');
    return sftp.delete(remotePath)
})

.then(function (){
    return sftp.end();
})

.catch(function(err) {
    throw err;
})

LDAP
Module: ldapauth-fork

Example Description:

  1. Connect to a LDAP server using a password that is stored as a secure credential
  2. Test authentication of a different user

Example Monitor:

var LdapAuth = require('ldapauth-fork');

var options = {
    url: 'ldap://YourLdapServer:389',
    bindDN: 'BindUsername',
    bindCredentials: $secure.LDAP_BIND_PASSWORD,
    searchBase: 'dc=yourDomain,dc=com',
    searchFilter: '(cn=)'
}

// Connect to LDAP server
var ldap = newLdapAuth(options);

ldap.on('error', function(err) {
    throw new Error('Unable to connect to LDAP server. Error: '+err);
})

// Test user authentication
ldap.authenticate('TestUser', $secure.LDAP_TEST_PASSWORD, function(err, user) {
   if (err) {
       ldap.close();
       throw new Error('Unable to authenticate user. Error: '+err);
   }
   else {
        console.log('User authentication successful.');
        ldap.close();
   }
})

TCP
Module: net

Example Description:

  1. Open a TCP connection to Google using port 80
  2. Write to the connection to simulate a HTTP GET
  3. Log the response
  4. Close the connection

Example Monitor:

var net = require('net');

var client = net.connect({
    port: 80,
    host: 'www.google.com'
    }, () => {

    console.log('connected to server!');
    client.write('GET / HTTP/1.1\r\n');
    client.write('Host: www.google.com\r\n');
    client.write('User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n');
    client.write('\r\n')
})

client.on('data', function(data){
    console.log('Received: ' +data);
    client.destroy();
})

client.on('end', function() {
    console.log('Connection closed');
})

SMTP
Module: nodemailer

Example Description:

Use Gmail to send a test email utilizing a password stored as a secure credential.

Example Monitor:

var assert = require('assert');
var nodemailer = require('nodemailer');

let transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    auth: {
        user: "YourGmailAccount",
        pass: $secure.GMAILAPPPASSWORD
   }
});

var message = {
    from: 'YourGmailAccount',
    to: 'EmailDestinationAccount',
    subject: 'Test message from New Relic Synthetic monitor',
    text: 'Testing the nodemailer package.',
}

transporter.sendMail(message, function(err, info, response){
    assert.ok(!err, "Error sending email: "+err)
})
5 Likes

These are great, thank you. However, I tried setting up the SFTP monitor script and although it works based on the output in the Script Log, the result of the monitor running is always " CHECK FAILED

NetworkError: Monitor produced no traffic".

What can be done to get around this error and let it know the check was actually successful?

My only workaround at the moment is adding a line at the bottom. So, if the SFTP checks succeeded it would be reached and run this dummy $browser.get(). Not ideal for many reasons, but it’s all I could come up with to get around the error above.

$browser.get(“http://example.com”);

1 Like

A scripted browser monitor type expects to see network traffic in the browser and will fail if it is missing. Please use a scripted API monitor type with any of these modules since you are not interacting with a browser.

You can quickly validate this in a scripted API monitor by creating a script that only has the following content, which will not fail.

console.log('Testing');
3 Likes

Hi There , does anyone have SMTP Mail reading from Inbox example? If so, please post. Thanks

The nodemailer module is provided that allows you to use SMTP to send email. There is currently not a module available on public locations that allow you to receive email using POP3 or IMAP.

Additional custom modules can be imported to a containerized private minion on Docker or K8S if you identify an IMAP / POP3 module that you would like to use.

1 Like

Please note that the TCP example above using the net module only supports non-secure TCP connections. If the port you need to test is secured with SSL/TLS you should use the tls module instead. The tls module was added to the private minion image in version 3.0.32 and is also available on public locations. While the tls and net examples use HTTP/HTTPS ports, any TCP port should be supported.

var tls = require('tls');

var client = tls.connect({
  port: 443,
  host: 'www.google.com'
}, () => {
  console.log('connected to server!');
  client.write('GET / HTTP/1.1\r\n');
  client.write('Host: www.google.com\r\n');
  client.write('User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n');
  client.write('\r\n')
})

client.on('data', function(data){
  console.log('Received: ' +data);
  client.destroy();
})

client.on('end', function() {
  console.log('Connection closed');
})
2 Likes

Hi @bpeck, I would like to ask you for help to understand if it is possible to get “Network timings” statistical data when I’m using the sftp module in API monitor? my script is working as expected, and I see success and failure attempts on when applicable…

at the same time, on the Dashboard, duration of each request is 0ms (regardless of success or failure) that is for sure not the case…

is there any workaround that I can apply to have my API monitor based on “ssh2-sftp-client” module to report/collect some connectivity statistic (automatically or manually) to be rported in the Dashboards UI, at least duration?

Edit: I think I solved my problem with using recommendation from this post (custom dashboard & using $util.insights): Measuring a file download in Synthetics, but would like to know if there is a way to do it more “generically”…

Using a Date object and the $util.insights.set functionality to include custom attributes on the SyntheticCheck events created for your monitor executions is going to be your best bet. Typically, I do this a little differently than the linked example you included though. Here is an example showing a section of the script using a custom timer:

// This is not a complete script. The variables, etc. defined in the full example in the first post would be required.
const sftp = new Client('US');

const connectStart = Date.now();

// Connect to the SFTP server using the configuration defined above.
sftp.connect(config)

// Check if our test file exists before issuing put. Delete it and then proceed if so.
.then(function() {
  const connectTime = Date.now() - timerstart;
  console.log('Connected in ' + connectTime + ' ms');
  $util.insights.set("connectTime", connectTime);
  assert.ok(connectTime < 4000, "ERROR - took 4 seconds or longer to connect. Connect time: " + connectTime);  
  return sftp.exists(remotePath);
})

Multiple timers and custom attributes can be added to extend this functionality. While these timers can be used to detect failure scenarios and to enable trending via dashboards, the timer values cannot populate the duration attribute on the monitor itself.

3 Likes