0
votes

I am working on an Azure Cloud Function (runs on node js) that should return a collection of documents from my Azure Cosmos DB for MongoDB API account.

It all works fine when I build and start the function locally, but fails when I deploy it to Azure. This is the error: MongoNetworkError: failed to connect to server [++++.mongo.cosmos.azure.com:++++] on first connect ...

I am new to CosmosDB and Azure Cloud Functions, so I am struggling to find the problem. I looked at the Firewall and virtual networks settings in the portal and tried out different variations of the connection string.

As it seems to work locally, I assume it could be a configuration setting in the portal.
Can someone help me out?

1.Set up the connection
I used the primary connection string provided by the portal.

import * as mongoClient from 'mongodb';
import { cosmosConnectionStrings } from './credentials';
import { Context } from '@azure/functions';

// The MongoDB Node.js 3.0 driver requires encoding special characters in the Cosmos DB password. 
const config = {
  url: cosmosConnectionStrings.primary_connection_string_v1,
  dbName: "****"
};

export async function createConnection(context: Context): Promise<any> {

  let db: mongoClient.Db;
  let connection: any;

  try {
    connection = await mongoClient.connect(config.url, {
      useNewUrlParser: true,
      ssl: true
    }); 

    context.log('Do we have a connection? ', connection.isConnected());

    if (connection.isConnected()) {
      db = connection.db(config.dbName);
      context.log('Connected to: ', db.databaseName);
    }

  } catch (error) {
    context.log(error);
    context.log('Something went wrong');
  }

  return {
    connection,
    db
  };
}



2. The main function
The main function that execute the query and returns the collection.

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('Get all projects function processed a request.');

            try {

                const { db, connection } = await createConnection(context);

                if (db) {
                    const projects = db.collection('projects')
                    const res = await projects.find({})
                    const body = await res.toArray()
                    context.log('Response projects: ', body);

                    connection.close()

                    context.res = {
                        status: 200,
                        body
                    }
                } else {
                    context.res = {
                        status: 400,
                        body: 'Could not connect to database'
                    }; 
                }

            } catch (error) {
                context.log(error); 
                context.res = {
                    status: 400,
                    body: 'Internal server error'
                }; 
    }  
};
1
what variations of connection string have you tried? what is the format of the connection string that works locally?akg179
This is the format that works locally: mongodb://[myInstanceName]:[primaryAccountKey]@[myInstanceName].documents.azure.com:10255/?ssl=tru. I tried the primary password and the secondary password as input for the primaryAccountKey. Using encodeURI() to encode the password wasn't the answer either.subzerodeluxe
What about the firewall and network settings of your cosmosdb?Cindy Pau
It works now! I think I made a mistake in not using the correct host key as query param, which is a bit weird because yesterday I tried different keys to no avail.subzerodeluxe
I was a bit too excited. This was actually not the main problem. The main problem was indeed the firewall settings. Changing the settings to allow access from all networks worked. Obviously this is not the preferred option I will investigate the best option from this point onwardssubzerodeluxe

1 Answers

0
votes

I had another look at the firewall and private network settings and read the offical documentation on configuring an IP firewall. On default the current IP adddress of your local machine is added to the IP whitelist. That's why the function worked locally.

Based on the documentation I tried all the options described below. They all worked for me. However, it still remains unclear why I had to manually perform an action to make it work. I am also not sure which option is best.

  • Set Allow access from to All networks
    All networks (including the internet) can access the database (obviously not advised)

  • Add the inbound and outbound IP addresses of the cloud function project to the whitelist
    This could be challenging if the IP addresses changes over time. If you are on the consumption plan this will probably happen.

  • Check the Accept connections from within public Azure datacenters option in the Exceptions section

    If you access your Azure Cosmos DB account from services that don’t provide a static IP (for example, Azure Stream Analytics and Azure Functions), you can still use the IP firewall to limit access. You can enable access from other sources within the Azure by selecting the Accept connections from within Azure datacenters option.

    This option configures the firewall to allow all requests from Azure, including requests from the subscriptions of other customers deployed in Azure. The list of IPs allowed by this option is wide, so it limits the effectiveness of a firewall policy. Use this option only if your requests don’t originate from static IPs or subnets in virtual networks. Choosing this option automatically allows access from the Azure portal because the Azure portal is deployed in Azure.