Error parsing uri scheme must be mongodb or mongodb srv

Unable to use mongodb+srv URI format #968 Comments Description I’m unable to use the URI string format mongo+srv to connect to my MongoDB cluster. Environment Driver (1.4.2) and ext-mongodb (1.5.3) are latest versions available. PHP is a Docker container, starting from the official Alpine image: Test Script Expected and Actual Behavior Expected: no errors. […]

Содержание

  1. Unable to use mongodb+srv URI format #968
  2. Comments
  3. Description
  4. Environment
  5. Test Script
  6. Expected and Actual Behavior
  7. [Meteor 1.6] Invalid schema, expected mongodb #9422
  8. Comments

Unable to use mongodb+srv URI format #968

Description

I’m unable to use the URI string format mongo+srv to connect to my MongoDB cluster.

Environment

Driver (1.4.2) and ext-mongodb (1.5.3) are latest versions available.
PHP is a Docker container, starting from the official Alpine image:

Test Script

Expected and Actual Behavior

Expected: no errors.
Actual:

The text was updated successfully, but these errors were encountered:

Is it correct to say that this is an unsupported feature?
I’ve found this ticked where it’s marked as 1.6.0: https://jira.mongodb.org/browse/PHPC-1292

The error you’re seeing originates in mongoc_uri_parse_before_slash() within libmongoc after mongoc_uri_parse_srv() fails. Just by looking at your connection string, I can tell you that «mongo» is an invalid hostname for use with the mongodb+srv scheme.

The SRV specification explains this in a bit more detail:

In this preprocessing step, the driver will query the DNS server for SRV records on . , prefixed with _mongodb._tcp. : _mongodb._tcp.. .

A driver MUST verify that in addition to the , the consists of at least two parts: the domain name, and a TLD. Drivers MUST raise an error and MUST NOT contact the DNS server to obtain SRV (or TXT records) if the full URI does not consists of at least three parts.

The SRV examples in the Connection String section of the MongoDB manual satisfy this requirement; however, the text doesn’t actually state the two (or more) dot requirement. I went searching for a clear explanation of the requirement in the SRV record Wikipedia article and RFC2782 but didn’t turn up anything. I have a feeling that the requirement can be inferred from some definitions in the RFC text, but that’s still not helpful for the average user. Moreover, users shouldn’t be expected to read driver specifications.

I opened DOCS-12574 to request an addition to the MongoDB manual to better explain this requirement.

Is it correct to say that this is an unsupported feature?

Support for mongodb+srv was originally implemented in PHPC-1015, which was released in PHP driver 1.4.0.

PHPC-1292 pertains to polling SRV records for sharded deployments over time. Currently, drivers resolve SRV records once when a client is constructed. That ticket is not yet available, but is scheduled to be included in the upcoming 1.6.0 release.

I have a feeling that the requirement can be inferred from some definitions in the RFC text, but that’s still not helpful for the average user.

I believe I misspoke here. The two (or more) dot requirement does not appear to be a requirement of RFC2782; however, it is a requirement for MongoDB’s usage of SRV records (likely for security reasons, as noted in my last comment in DOCS-12574). In any event, this is hopefully something we can clear up in the manual text.

Thanks for the input @jmikola.

I’ve refined my test, and I’ve found that the issue is still there in a corner case, which unfortunately is OUR use case: we are using Consul, so our hostname doesn’t end with a public TLD, but with .consul . Furthermore, to avoid a DNS resolving issue which seems derived from Alpine, we need to also add the dot at the very end of the address, the top TLD, and this fails.

  • mongodb+srv://mongodb.example.consul/ works
  • mongodb+srv://mongodb.example.consul./ does not work.

Do you think that could be patched?

Do you think that could be patched?

The relevant code to patch would be valid_hostname() , which is called by mongoc_uri_parse_srv() (and other functions).

I don’t think we can reasonably modify this behavior in the driver proper, as it would conflict with this bit of the SRV specification:

A driver MUST verify that in addition to the , the consists of at least two parts: the domain name, and a TLD. Drivers MUST raise an error and MUST NOT contact the DNS server to obtain SRV (or TXT records) if the full URI does not consists of at least three parts.

A driver MUST verify that the host names returned through SRV records have the same parent . Drivers MUST raise an error and MUST NOT initiate a connection to any returned host name which does not share the same

Even if valid_hostname() or mongoc_uri_parse_srv() was changed to allow a trailing dot, I would think that the actual host string in the SRV/TXT record would not have a dot (correct me if I’m wrong) and therefore be invalidated due to having a different domain name from the original resolved host string. AFAIK, that behavior is also in place for security reasons to protect against blatant DNS spoofing (e.g. foo.example.com resolution yields a SRV record to mitm-attack.com ).

I have very little experience with Alpine (we’ve had just a handful of issues using that distro over the years) and have never worked with Consul. Is the issue you’re describing related to this write-up? If so, I wonder if the suggestion there of running a local caching DNS server might help.

Such a name consists of a sequence of domain labels separated by «.», each domain label starting and ending with an alphanumeric character and possibly also containing «-» characters. The rightmost domain label of a fully qualified domain name in DNS may be followed by a single «.» and should be if it is necessary to distinguish between the complete domain name and some local domain.

Between this and the grammar definitions in Collected ABNF for URI, it looks like a trailing dot is permitted in a valid host string. If this might actually address your problem (per «correct me if I’m wrong» above), then I’d be happy to raise the issue internally with other drivers and consider a change to libmongoc.

Offhand, I’m not sure if libmongoc is alone in disallowing trailing dots in its valid_hostname() function as this is not explicitly addressed in the SRV or Connection String specs. I will note that the Connection String: Host section does reference RFC3986 as the authority on host strings, so it’s possible that alone could justify changing libmongoc behavior hear.

Источник

[Meteor 1.6] Invalid schema, expected mongodb #9422

Since my upgrade from 1.5 to 1.6, I am occasionally facing that Meteor throws on startup with the error copied below. First, I thought this might be related to the upgrade itself and just did a meteor reset . Everything worked fine afterwards.

But now this error occurred although I did not touch release versions in the meantime. I could make it work again with meteor reset , but this of course killed all my local dev data again. So I am wondering what is causing this?

The text was updated successfully, but these errors were encountered:

The ‘invalid schema, expected mongodb’ error is thrown by the MongoDB driver if the database URL doesn’t start with mongodb:// and the Note: Restart Meteor to start the MongoDB server. message is printed by the mongo-dev-server package if the MongoDB URL is ‘no-mongo-server’ . Apparently, Meteor doesn’t start MongoDB and then attempts to connect to the database with an invalid URL.

Can you share the content of your app’s versions file (or at least the versions of mongo and mongo-dev-server )?

Sure, here’s the versions file:

Is there anything in your app that might be modifying process.env.MONGO_URL during runtime?

No, not that I knew.

I’m thinking there might have been a change in how mongo driver handles invalid urls since I worked on the mongo-dev-server package. I believe I chose no-mongo-server as the MONGO_URL because of the fact that there were no error when using an invalid MONGO_URL . But maybe that was a false assumption made from the fact that MONGO_URL=false didn’t error out.

i.e. Maybe this is cause by the fact that MONGO_URL=»no-mongo-server» isn’t falsey?

But that don’t explain why suddenly the mongo-dev-server package isn’t picked up at startup and results in MONGO_URL=»no-mongo-server» being set, as per this message Note: Restart Meteor to start the MongoDB server.

I’m wondering if the call to self.projectContext.resolveConstraints() is async and that makes self.projectContext.packageMap not be available or this lookup packageMap.getInfo(‘mongo-dev-server’) not able to find the package.

Lines 74 to 80 in c09d8e5

buildmessage . capture ( function ( ) <
self . projectContext . resolveConstraints ( ) ;
> ) ;
const packageMap = self . projectContext . packageMap ;
const hasMongoDevServerPackage =
packageMap && packageMap . getInfo ( ‘mongo-dev-server’ ) != null ;

@zimme Good thinking — I’ve confirmed self.projectContext.resolveConstraints() is not async though 🙁 .

@derwaldgeist Is this happening when you’re running a mobile build (e.g. meteor run ios-device )? If so I’m wondering if you’re hitting some combination of #8096 here. The app is unintentionally running in production mode on first startup, and since the mongo-dev-server package is debugOnly , it’s not being found by the runner, and a mongoUrl of no-mongo-server is being set. Then when the app rebuilds it’s running back in development mode again (as outlined in #8096) at which point the mongoUrl value of no-mongo-server then triggers the error message you’re seeing, since the mongo-dev-server package can be reached again (since debugOnly is now accepted again). This could help explain why you’re only seeing this happening sometimes.

#8096 has been tied to a handful of issues now, so I think addressing it should be moved up the priority list. I’ll aim to take a look — thanks!

EDIT: Just to confirm — I haven’t verified this; I’m just thinking out loud here . I’ll try to confirm shortly.

Thanks for the info. I’m not 100% sure if the problem occurred when I tried to run ios-device . Will have an eye on it when it happens next time. But I can say that the problem disappeared after doing a meteor reset . So this would kinda contradict your assumption, as the very first run works as expected.

One of my colleagues also saw this issue last week, and we never run ios-device.

I have now the same issue when trying to run test-packages

Update just putting: MONGO_URL=mongodb://127.0.0.1:27017 (as a dummy, there’s no db there) works.

While we think resolving this issue would be a great addition to the Meteor project, we’re going to close it for now due to low activity (see the bug issue lifespan section of Meteor’s triage doc for more information). If anyone comes across this issue in the future, and is interested in working on resolving it, please let us know by posting here and we’ll consider re-opening this issue. Thanks!

I am getting the exact same error. I am setting the MONGO_URL=false using
$export MONGO_URL=false because I am not using Mongo DB for my backend. How can I run my meteor app without mongo? Please help

@sourav2029 MONGO_URL must be a valid URL. If you don’t want to start MongoDB, simply remove the mongo package from your .meteor/packages file or run meteor remove mongo .

@klaussner If you set MONGO_URL=false it should prevent mongo from starting locally and you can’t really just remove the mongo package currently without losing other meteor functionality that «should» be unrelated to Mongo.

Ah, right. Thanks for clarifying, @zimme!

@sourav2029 Is it possible that you (or one of the packages you are using) creates a collection?

The invalid schema, expected mongodb error is thrown if MONGO_URL is set to false and the app attempts to create a collection. We could handle MONGO_URL === «false» here to throw a more meaningful error.

@klaussner This is what my . meteor/package looks like
standard-minifier-css@1.4.0
standard-minifier-js@2.3.1
es5-shim@4.7.0
ecmascript@0.10.0
shell-server@0.3.1
apollo

I don’t have any other dependency. I am just using meteor for packaging my app. The front end is in REACT and back end is in graphql. But when i build the app using meteor build i see mongo and npm-mongo inside bundle/programs/server/npm/node_modules/meteor . I am new in using it and am not sure how this is being generated.

I want to remove all mongo dependencies and be able to run my app by using MONGO_URL=false.
My meteor version is : «meteorRelease»: «METEOR@1.6.1»,

And this is my entire error log

The apollo package could be the problem. It uses accounts-base , which depends on mongo and creates the Meteor.users collection.

Thanks @klaussner that was it. Great help.

Getting the same error:

I have a MongoDB Atlas account and have reached out to them for clarification on my MONGO_URL strings as an owner and for my oplog user MONGO_OPLOG_URL string. These env vars look ok.

Mongo mentions that I need to incorporate the mongo driver, but my question is where do I put that code? SeeMongoClient below, I currently put it in my startup/both/index.js. Is that correct? I can’t seem to find any info on where to place this code. I want to use the api on the server to do reads/writes so I know I probably don’t want it there, I only put it here just to deploy my app and then reconfig once I was up and running. I want to place it server side. Do I make a new file in startup/server/?? or do I put in startup/both/.

In my package.json, I have mongo as a dependency «mongodb»: «^3.0.7» and it still fails Galaxy deployment.

I have also changed to the MONGO_URL = «false» and still can’t get past the meteor.js Galaxy error below.

Any ideas would be greatly appreciated!

@jaguarj What version of Meteor are you using? The version of the mongodb npm which is used by Meteor is handled by Meteor via the npm-mongo package — you shouldn’t need to require(‘mongodb’) , nor install the mongodb module yourself. As of Meteor 1.7, Meteor will ship with a newer version of mongodb (in the 3.x range) thanks to the work done with #9790. Perhaps you can try the latest beta? That beta cycle is being tracked in #9826.

Ok, thanks! I’ve set up a 3.4 mongo instance in atlas. I want to validate my settings with that first. Once that is complete, I will probably test with the meteor 1.7 build. I appreciate the information.

I am new to Mongo and i’m facing the same issue. please i need help.
here’s the error log

(node:5277) UnhandledPromiseRejectionWarning: Error: Invalid schema, expected mongodb or mongodb+srv
at module.exports (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongodb/lib/url_parser.js:21:21)
at connect (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongodb/lib/mongo_client.js:880:3)
at connectOp (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongodb/lib/mongo_client.js:269:3)
at executeOperation (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongodb/lib/utils.js:420:24)
at MongoClient.connect (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongodb/lib/mongo_client.js:260:10)
at Promise (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongoose/lib/connection.js:427:12)
at new Promise ()
at NativeConnection.Connection.openUri (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongoose/lib/connection.js:424:19)
at Mongoose.connect (/Users/nicholas/Desktop/Projects/shopping-cart/node_modules/mongoose/lib/index.js:208:15)
at Object. (/Users/nicholas/Desktop/Projects/shopping-cart/seed/product-seeder.js:5:10)
at Module._compile (internal/modules/cjs/loader.js:678:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
(node:5277) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:5277) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@Nicxzmiller Do you have a MONGO_URL set? If so, does it start with mongodb:// or something else? (It should start with either mongodb:// or mongodb+srv:// !)

I’m using Mongoose:/ instead of the mongodb://

@Nicxzmiller Though I’ve never tried, I do believe there are ways of getting Meteor to work with Mongoose—though I’m pretty sure all of them would involve you losing access to Meteor’s publish/subscribe mechanism.

Regardless though, from what I can tell the MONGO_URL should still be using mongodb:// as the scheme. For example, even the Mongoose connection documentation still uses mongodb:// .

Ultimately, I think you’ll need to explore other options on this in order to accomplish what you’re trying to do (using Mongoose) and this issue is not the same as the problem you’re encountering.

I’m facing the same problem. I Did ‘meteor reset’ and it didn’t work. Also, I deleted the ‘meteor’ directory and restored the latest working one, tried to run meteor again and still, it doesn’t work.
I have the latest updated Meteor.

edit: I removed the MONGO_URL by ‘set MONGO_URL=’
and it worked, Although I never changed it before.

Error!Error: Invalid schema, expected mongodb or mongodb+srv

Источник

Есть проблема, одно приложение простого узла js проекта с добавлением и получением данных от пользователя и сохранением в mongo (используйте 3 .. ver), все в порядке (сохранение, получение и т. д.), пример:

var express = require('express');
var router = express.Router();
var mongo = require('mongodb').MongoClient;
var objectID = require('mongodb').ObjectID;
var assert = require('assert');

const url = 'mongodb://localhost:27017';
const dbName = 'ldex';
const tblOffers = 'offers';

router.post('/insert', function (req, res, next) {
    var order = {
        type: 'Sell',
        ..............
        max: req.body.max,
        protection: req.body.protection,
        comment: req.body.comment,
        date: new Date().toDateString()
    };

    mongo.connect(url, function (err, client) {
        assert.equal(null, err);

        const db = client.db(dbName);

        db.collection(tblOffers).insertOne(order, function (err, res) {
            assert.equal(null, err);
            console.log('Offer placed');
            client.close();
        })
    });

    res.redirect('/exchange')
});

Но вот еще одно приложение, парсер, у которого такое же соединение mongo, оно добавляет в него некоторые данные с другого веб-сайта (когда mongo не используется, все в порядке, я получаю данные хорошо), вот часть кода:

...
let assert = require('assert');
let mongo = require('mongodb').MongoClient;
let router = express.Router();

const url = 'mongodb://localhost:27017/';
const dbName = 'ceramo';
const tblOffers = 'items';

...

/*
 *  Get items from specific group
 */

function getGroupItems(url, callback) {
    request({uri: url}, function (error, response, body) {
        let list = [];
        let $ = cheerio.load(body);
        $('#tovar').find('a.cat_item_disc_a').each(function(i, elem) {
            list[i] = 'https://plitkazavr.ru' + $(this).attr('href');
        });
        callback(list);
    });
}

/*
 *  Parse one item from specific link
 */

function getItem(url) {
    request({uri: url}, function (error, response, body) {
        let list = {};
        let $ = cheerio.load(body);
        $('#item_border').find('> #item_prop > ul').find('li.item_list').each(function(i, elem) {
            list[$(this).find('.item_cell').first().text()] = $(this).find('div.item_cell.item_val').text();
        });
        list.price = (parseFloat($('#item_price').text()));
        list.img = ('https://plitkazavr.ru' + $('#item_img').attr('src'));
        list.meta = ($('#item_wrap').find('meta[itemprop="description"]').attr("content"));

        mongo.connect(url, function (err, client) {
            assert.equal(null, err);

            const db = client.db(dbName);

            db.collection(tblOffers).insertOne(order, function (err, res) {
                assert.equal(null, err);
                console.log('Offer placed');
                client.close();
            })
        });

    });
}

router.get('/parse', function (req, res, next) {

    getGroupItems('https://plitkazavr.ru/Naxos/Clio', function (items) {
        items.forEach(function(item, i, arr) {
            setTimeout(function() {
                getItem(item);
            }, 1000);
        });
    });

    res.end('ok');
});

И он не работает и дает

`Error: Invalid schema, expected `mongodb` or `mongodb+srv

Не понимаю, в чем проблема, помогите пожалуйста …

Ваш URL-адрес MongoDB кажется неполным, он должен включать ваш dbName, прежде чем он будет передан в соединение мангуста, как это

const url = 'mongodb://localhost:27017/';
const fullUrl = url + dbName; // which should evaluate to this 'mongodb://localhost:27017/ceramo'


mongo.connect(fullUrl, function (err, client) {...}


2

Fortune Ekeruo
4 Фев 2018 в 06:06

// Copyright (C) MongoDB, Inc. 2022-present. // // 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 package options import ( «bytes» «context» «crypto/tls» «crypto/x509» «encoding/pem» «errors» «fmt» «io/ioutil» «net» «net/http» «os» «reflect» «testing» «time» «github.com/google/go-cmp/cmp» «github.com/google/go-cmp/cmp/cmpopts» «go.mongodb.org/mongo-driver/bson» «go.mongodb.org/mongo-driver/bson/bsoncodec» «go.mongodb.org/mongo-driver/event» «go.mongodb.org/mongo-driver/internal» «go.mongodb.org/mongo-driver/internal/assert» «go.mongodb.org/mongo-driver/mongo/readconcern» «go.mongodb.org/mongo-driver/mongo/readpref» «go.mongodb.org/mongo-driver/mongo/writeconcern» «go.mongodb.org/mongo-driver/x/mongo/driver/connstring» ) var tClientOptions = reflect.TypeOf(&ClientOptions{}) func TestClientOptions(t *testing.T) { t.Run(«ApplyURI/doesn’t overwrite previous errors», func(t *testing.T) { uri := «not-mongo-db-uri://» want := internal.WrapErrorf( errors.New(`scheme must be «mongodb» or «mongodb+srv»`), «error parsing uri», ) co := Client().ApplyURI(uri).ApplyURI(«mongodb://localhost/») got := co.Validate() if !cmp.Equal(got, want, cmp.Comparer(compareErrors)) { t.Errorf(«Did not received expected error. got %v; want %v», got, want) } }) t.Run(«Validate/returns error», func(t *testing.T) { want := errors.New(«validate error») co := &ClientOptions{err: want} got := co.Validate() if !cmp.Equal(got, want, cmp.Comparer(compareErrors)) { t.Errorf(«Did not receive expected error. got %v; want %v», got, want) } }) t.Run(«Set», func(t *testing.T) { testCases := []struct { name string fn interface{} // method to be run arg interface{} // argument for method field string // field to be set dereference bool // Should we compare a pointer or the field }{ {«AppName», (*ClientOptions).SetAppName, «example-application», «AppName», true}, {«Auth», (*ClientOptions).SetAuth, Credential{Username: «foo», Password: «bar»}, «Auth», true}, {«Compressors», (*ClientOptions).SetCompressors, []string{«zstd», «snappy», «zlib»}, «Compressors», true}, {«ConnectTimeout», (*ClientOptions).SetConnectTimeout, 5 * time.Second, «ConnectTimeout», true}, {«Dialer», (*ClientOptions).SetDialer, testDialer{Num: 12345}, «Dialer», true}, {«HeartbeatInterval», (*ClientOptions).SetHeartbeatInterval, 5 * time.Second, «HeartbeatInterval», true}, {«Hosts», (*ClientOptions).SetHosts, []string{«localhost:27017», «localhost:27018», «localhost:27019»}, «Hosts», true}, {«LocalThreshold», (*ClientOptions).SetLocalThreshold, 5 * time.Second, «LocalThreshold», true}, {«MaxConnIdleTime», (*ClientOptions).SetMaxConnIdleTime, 5 * time.Second, «MaxConnIdleTime», true}, {«MaxPoolSize», (*ClientOptions).SetMaxPoolSize, uint64(250), «MaxPoolSize», true}, {«MinPoolSize», (*ClientOptions).SetMinPoolSize, uint64(10), «MinPoolSize», true}, {«MaxConnecting», (*ClientOptions).SetMaxConnecting, uint64(10), «MaxConnecting», true}, {«PoolMonitor», (*ClientOptions).SetPoolMonitor, &event.PoolMonitor{}, «PoolMonitor», false}, {«Monitor», (*ClientOptions).SetMonitor, &event.CommandMonitor{}, «Monitor», false}, {«ReadConcern», (*ClientOptions).SetReadConcern, readconcern.Majority(), «ReadConcern», false}, {«ReadPreference», (*ClientOptions).SetReadPreference, readpref.SecondaryPreferred(), «ReadPreference», false}, {«Registry», (*ClientOptions).SetRegistry, bson.NewRegistryBuilder().Build(), «Registry», false}, {«ReplicaSet», (*ClientOptions).SetReplicaSet, «example-replicaset», «ReplicaSet», true}, {«RetryWrites», (*ClientOptions).SetRetryWrites, true, «RetryWrites», true}, {«ServerSelectionTimeout», (*ClientOptions).SetServerSelectionTimeout, 5 * time.Second, «ServerSelectionTimeout», true}, {«Direct», (*ClientOptions).SetDirect, true, «Direct», true}, {«SocketTimeout», (*ClientOptions).SetSocketTimeout, 5 * time.Second, «SocketTimeout», true}, {«TLSConfig», (*ClientOptions).SetTLSConfig, &tls.Config{}, «TLSConfig», false}, {«WriteConcern», (*ClientOptions).SetWriteConcern, writeconcern.New(writeconcern.WMajority()), «WriteConcern», false}, {«ZlibLevel», (*ClientOptions).SetZlibLevel, 6, «ZlibLevel», true}, {«DisableOCSPEndpointCheck», (*ClientOptions).SetDisableOCSPEndpointCheck, true, «DisableOCSPEndpointCheck», true}, {«LoadBalanced», (*ClientOptions).SetLoadBalanced, true, «LoadBalanced», true}, } opt1, opt2, optResult := Client(), Client(), Client() for idx, tc := range testCases { t.Run(tc.name, func(t *testing.T) { fn := reflect.ValueOf(tc.fn) if fn.Kind() != reflect.Func { t.Fatal(«fn argument must be a function») } if fn.Type().NumIn() < 2 || fn.Type().In(0) != tClientOptions { t.Fatal(«fn argument must have a *ClientOptions as the first argument and one other argument») } if _, exists := tClientOptions.Elem().FieldByName(tc.field); !exists { t.Fatalf(«field (%s) does not exist in ClientOptions», tc.field) } args := make([]reflect.Value, 2) client := reflect.New(tClientOptions.Elem()) args[0] = client want := reflect.ValueOf(tc.arg) args[1] = want if !want.IsValid() || !want.CanInterface() { t.Fatal(«arg property of test case must be valid») } _ = fn.Call(args) // To avoid duplication we’re piggybacking on the Set* tests to make the // MergeClientOptions test simpler and more thorough. // To do this we set the odd numbered test cases to the first opt, the even and // divisible by three test cases to the second, and the result of merging the two to // the result option. This gives us coverage of options set by the first option, by // the second, and by both. if idx%2 != 0 { args[0] = reflect.ValueOf(opt1) _ = fn.Call(args) } if idx%2 == 0 || idx%3 == 0 { args[0] = reflect.ValueOf(opt2) _ = fn.Call(args) } args[0] = reflect.ValueOf(optResult) _ = fn.Call(args) got := client.Elem().FieldByName(tc.field) if !got.IsValid() || !got.CanInterface() { t.Fatal(«cannot create concrete instance from retrieved field») } if got.Kind() == reflect.Ptr && tc.dereference { got = got.Elem() } if !cmp.Equal( got.Interface(), want.Interface(), cmp.AllowUnexported(readconcern.ReadConcern{}, writeconcern.WriteConcern{}, readpref.ReadPref{}), cmp.Comparer(func(r1, r2 *bsoncodec.Registry) bool { return r1 == r2 }), cmp.Comparer(func(cfg1, cfg2 *tls.Config) bool { return cfg1 == cfg2 }), cmp.Comparer(func(fp1, fp2 *event.PoolMonitor) bool { return fp1 == fp2 }), ) { t.Errorf(«Field not set properly. got %v; want %v», got.Interface(), want.Interface()) } }) } t.Run(«MergeClientOptions/all set», func(t *testing.T) { want := optResult got := MergeClientOptions(nil, opt1, opt2) if diff := cmp.Diff( got, want, cmp.AllowUnexported(readconcern.ReadConcern{}, writeconcern.WriteConcern{}, readpref.ReadPref{}), cmp.Comparer(func(r1, r2 *bsoncodec.Registry) bool { return r1 == r2 }), cmp.Comparer(func(cfg1, cfg2 *tls.Config) bool { return cfg1 == cfg2 }), cmp.Comparer(func(fp1, fp2 *event.PoolMonitor) bool { return fp1 == fp2 }), cmp.AllowUnexported(ClientOptions{}), cmpopts.IgnoreFields(http.Client{}, «Transport»), ); diff != «» { t.Errorf(«diff:n%s», diff) t.Errorf(«Merged client options do not match. got %v; want %v», got, want) } }) // go-cmp dont support error comparisons (https://github.com/google/go-cmp/issues/24) // Use specifique test for this t.Run(«MergeClientOptions/err», func(t *testing.T) { opt1, opt2 := Client(), Client() opt1.err = errors.New(«Test error») got := MergeClientOptions(nil, opt1, opt2) if got.err.Error() != «Test error» { t.Errorf(«Merged client options do not match. got %v; want %v», got.err.Error(), opt1.err.Error()) } }) t.Run(«MergeClientOptions/uri», func(t *testing.T) { opt1, opt2 := Client(), Client() opt1.uri = «Test URI» got := MergeClientOptions(nil, opt1, opt2) if got.uri != «Test URI» { t.Errorf(«Merged client options do not match. got %v; want %v», got.uri, opt1.uri) } }) }) t.Run(«ApplyURI», func(t *testing.T) { baseClient := func() *ClientOptions { return Client().SetHosts([]string{«localhost»}) } testCases := []struct { name string uri string result *ClientOptions }{ { «ParseError», «not-mongo-db-uri://», &ClientOptions{ err: internal.WrapErrorf( errors.New(`scheme must be «mongodb» or «mongodb+srv»`), «error parsing uri», ), HTTPClient: internal.DefaultHTTPClient, }, }, { «ReadPreference Invalid Mode», «mongodb://localhost/?maxStaleness=200», &ClientOptions{ err: fmt.Errorf(«unknown read preference %v», «»), Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, }, }, { «ReadPreference Primary With Options», «mongodb://localhost/?readPreference=Primary&maxStaleness=200», &ClientOptions{ err: errors.New(«can not specify tags, max staleness, or hedge with mode primary»), Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, }, }, { «TLS addCertFromFile error», «mongodb://localhost/?ssl=true&sslCertificateAuthorityFile=testdata/doesntexist», &ClientOptions{ err: &os.PathError{Op: «open», Path: «testdata/doesntexist»}, Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, }, }, { «TLS ClientCertificateKey», «mongodb://localhost/?ssl=true&sslClientCertificateKeyFile=testdata/doesntexist», &ClientOptions{ err: &os.PathError{Op: «open», Path: «testdata/doesntexist»}, Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, }, }, { «AppName», «mongodb://localhost/?appName=awesome-example-application», baseClient().SetAppName(«awesome-example-application»), }, { «AuthMechanism», «mongodb://localhost/?authMechanism=mongodb-x509», baseClient().SetAuth(Credential{AuthSource: «$external», AuthMechanism: «mongodb-x509»}), }, { «AuthMechanismProperties», «mongodb://foo@localhost/?authMechanism=gssapi&authMechanismProperties=SERVICE_NAME:mongodb-fake», baseClient().SetAuth(Credential{ AuthSource: «$external», AuthMechanism: «gssapi», AuthMechanismProperties: map[string]string{«SERVICE_NAME»: «mongodb-fake»}, Username: «foo», }), }, { «AuthSource», «mongodb://foo@localhost/?authSource=random-database-example», baseClient().SetAuth(Credential{AuthSource: «random-database-example», Username: «foo»}), }, { «Username», «mongodb://foo@localhost/», baseClient().SetAuth(Credential{AuthSource: «admin», Username: «foo»}), }, { «Unescaped slash in username», «mongodb:///:pwd@localhost», &ClientOptions{ err: internal.WrapErrorf( errors.New(«unescaped slash in username»), «error parsing uri», ), HTTPClient: internal.DefaultHTTPClient, }, }, { «Password», «mongodb://foo:bar@localhost/», baseClient().SetAuth(Credential{ AuthSource: «admin», Username: «foo», Password: «bar», PasswordSet: true, }), }, { «Single character username and password», «mongodb://f:b@localhost/», baseClient().SetAuth(Credential{ AuthSource: «admin», Username: «f», Password: «b», PasswordSet: true, }), }, { «Connect», «mongodb://localhost/?connect=direct», baseClient().SetDirect(true), }, { «ConnectTimeout», «mongodb://localhost/?connectTimeoutms=5000», baseClient().SetConnectTimeout(5 * time.Second), }, { «Compressors», «mongodb://localhost/?compressors=zlib,snappy», baseClient().SetCompressors([]string{«zlib», «snappy»}).SetZlibLevel(6), }, { «DatabaseNoAuth», «mongodb://localhost/example-database», baseClient(), }, { «DatabaseAsDefault», «mongodb://foo@localhost/example-database», baseClient().SetAuth(Credential{AuthSource: «example-database», Username: «foo»}), }, { «HeartbeatInterval», «mongodb://localhost/?heartbeatIntervalms=12000», baseClient().SetHeartbeatInterval(12 * time.Second), }, { «Hosts», «mongodb://localhost:27017,localhost:27018,localhost:27019/», baseClient().SetHosts([]string{«localhost:27017», «localhost:27018», «localhost:27019»}), }, { «LocalThreshold», «mongodb://localhost/?localThresholdMS=200», baseClient().SetLocalThreshold(200 * time.Millisecond), }, { «MaxConnIdleTime», «mongodb://localhost/?maxIdleTimeMS=300000», baseClient().SetMaxConnIdleTime(5 * time.Minute), }, { «MaxPoolSize», «mongodb://localhost/?maxPoolSize=256», baseClient().SetMaxPoolSize(256), }, { «MinPoolSize», «mongodb://localhost/?minPoolSize=256», baseClient().SetMinPoolSize(256), }, { «MaxConnecting», «mongodb://localhost/?maxConnecting=10», baseClient().SetMaxConnecting(10), }, { «ReadConcern», «mongodb://localhost/?readConcernLevel=linearizable», baseClient().SetReadConcern(readconcern.Linearizable()), }, { «ReadPreference», «mongodb://localhost/?readPreference=secondaryPreferred», baseClient().SetReadPreference(readpref.SecondaryPreferred()), }, { «ReadPreferenceTagSets», «mongodb://localhost/?readPreference=secondaryPreferred&readPreferenceTags=foo:bar», baseClient().SetReadPreference(readpref.SecondaryPreferred(readpref.WithTags(«foo», «bar»))), }, { «MaxStaleness», «mongodb://localhost/?readPreference=secondaryPreferred&maxStaleness=250», baseClient().SetReadPreference(readpref.SecondaryPreferred(readpref.WithMaxStaleness(250 * time.Second))), }, { «RetryWrites», «mongodb://localhost/?retryWrites=true», baseClient().SetRetryWrites(true), }, { «ReplicaSet», «mongodb://localhost/?replicaSet=rs01», baseClient().SetReplicaSet(«rs01»), }, { «ServerSelectionTimeout», «mongodb://localhost/?serverSelectionTimeoutMS=45000», baseClient().SetServerSelectionTimeout(45 * time.Second), }, { «SocketTimeout», «mongodb://localhost/?socketTimeoutMS=15000», baseClient().SetSocketTimeout(15 * time.Second), }, { «TLS CACertificate», «mongodb://localhost/?ssl=true&sslCertificateAuthorityFile=testdata/ca.pem», baseClient().SetTLSConfig(&tls.Config{ RootCAs: createCertPool(t, «testdata/ca.pem»), }), }, { «TLS Insecure», «mongodb://localhost/?ssl=true&sslInsecure=true», baseClient().SetTLSConfig(&tls.Config{InsecureSkipVerify: true}), }, { «TLS ClientCertificateKey», «mongodb://localhost/?ssl=true&sslClientCertificateKeyFile=testdata/nopass/certificate.pem», baseClient().SetTLSConfig(&tls.Config{Certificates: make([]tls.Certificate, 1)}), }, { «TLS ClientCertificateKey with password», «mongodb://localhost/?ssl=true&sslClientCertificateKeyFile=testdata/certificate.pem&sslClientCertificateKeyPassword=passphrase», baseClient().SetTLSConfig(&tls.Config{Certificates: make([]tls.Certificate, 1)}), }, { «TLS Username», «mongodb://localhost/?ssl=true&authMechanism=mongodb-x509&sslClientCertificateKeyFile=testdata/nopass/certificate.pem», baseClient().SetAuth(Credential{ AuthMechanism: «mongodb-x509», AuthSource: «$external», Username: `C=US,ST=New York,L=New York City, Inc,O=MongoDB,OU=WWW`, }), }, { «WriteConcern J», «mongodb://localhost/?journal=true», baseClient().SetWriteConcern(writeconcern.New(writeconcern.J(true))), }, { «WriteConcern WString», «mongodb://localhost/?w=majority», baseClient().SetWriteConcern(writeconcern.New(writeconcern.WMajority())), }, { «WriteConcern W», «mongodb://localhost/?w=3», baseClient().SetWriteConcern(writeconcern.New(writeconcern.W(3))), }, { «WriteConcern WTimeout», «mongodb://localhost/?wTimeoutMS=45000», baseClient().SetWriteConcern(writeconcern.New(writeconcern.WTimeout(45 * time.Second))), }, { «ZLibLevel», «mongodb://localhost/?zlibCompressionLevel=4», baseClient().SetZlibLevel(4), }, { «TLS tlsCertificateFile and tlsPrivateKeyFile», «mongodb://localhost/?tlsCertificateFile=testdata/nopass/cert.pem&tlsPrivateKeyFile=testdata/nopass/key.pem», baseClient().SetTLSConfig(&tls.Config{Certificates: make([]tls.Certificate, 1)}), }, { «TLS only tlsCertificateFile», «mongodb://localhost/?tlsCertificateFile=testdata/nopass/cert.pem», &ClientOptions{ err: internal.WrapErrorf( errors.New(«the tlsPrivateKeyFile URI option must be provided if the tlsCertificateFile option is specified»), «error validating uri», ), HTTPClient: internal.DefaultHTTPClient, }, }, { «TLS only tlsPrivateKeyFile», «mongodb://localhost/?tlsPrivateKeyFile=testdata/nopass/key.pem», &ClientOptions{ err: internal.WrapErrorf( errors.New(«the tlsCertificateFile URI option must be provided if the tlsPrivateKeyFile option is specified»), «error validating uri», ), HTTPClient: internal.DefaultHTTPClient, }, }, { «TLS tlsCertificateFile and tlsPrivateKeyFile and tlsCertificateKeyFile», «mongodb://localhost/?tlsCertificateFile=testdata/nopass/cert.pem&tlsPrivateKeyFile=testdata/nopass/key.pem&tlsCertificateKeyFile=testdata/nopass/certificate.pem», &ClientOptions{ err: internal.WrapErrorf( errors.New(«the sslClientCertificateKeyFile/tlsCertificateKeyFile URI option cannot be provided «+ «along with tlsCertificateFile or tlsPrivateKeyFile»), «error validating uri», ), HTTPClient: internal.DefaultHTTPClient, }, }, { «disable OCSP endpoint check», «mongodb://localhost/?tlsDisableOCSPEndpointCheck=true», baseClient().SetDisableOCSPEndpointCheck(true), }, { «directConnection», «mongodb://localhost/?directConnection=true», baseClient().SetDirect(true), }, { «TLS CA file with multiple certificiates», «mongodb://localhost/?tlsCAFile=testdata/ca-with-intermediates.pem», baseClient().SetTLSConfig(&tls.Config{ RootCAs: createCertPool(t, «testdata/ca-with-intermediates-first.pem», «testdata/ca-with-intermediates-second.pem», «testdata/ca-with-intermediates-third.pem»), }), }, { «TLS empty CA file», «mongodb://localhost/?tlsCAFile=testdata/empty-ca.pem», &ClientOptions{ Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, err: errors.New(«the specified CA file does not contain any valid certificates»), }, }, { «TLS CA file with no certificates», «mongodb://localhost/?tlsCAFile=testdata/ca-key.pem», &ClientOptions{ Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, err: errors.New(«the specified CA file does not contain any valid certificates»), }, }, { «TLS malformed CA file», «mongodb://localhost/?tlsCAFile=testdata/malformed-ca.pem», &ClientOptions{ Hosts: []string{«localhost»}, HTTPClient: internal.DefaultHTTPClient, err: errors.New(«the specified CA file does not contain any valid certificates»), }, }, { «loadBalanced=true», «mongodb://localhost/?loadBalanced=true», baseClient().SetLoadBalanced(true), }, { «loadBalanced=false», «mongodb://localhost/?loadBalanced=false», baseClient().SetLoadBalanced(false), }, { «srvServiceName», «mongodb+srv://test22.test.build.10gen.cc/?srvServiceName=customname», baseClient().SetSRVServiceName(«customname»). SetHosts([]string{«localhost.test.build.10gen.cc:27017», «localhost.test.build.10gen.cc:27018»}), }, { «srvMaxHosts», «mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=2», baseClient().SetSRVMaxHosts(2). SetHosts([]string{«localhost.test.build.10gen.cc:27017», «localhost.test.build.10gen.cc:27018»}), }, { «GODRIVER-2263 regression test», «mongodb://localhost/?tlsCertificateKeyFile=testdata/one-pk-multiple-certs.pem», baseClient().SetTLSConfig(&tls.Config{Certificates: make([]tls.Certificate, 1)}), }, { «GODRIVER-2650 X509 certificate», «mongodb://localhost/?ssl=true&authMechanism=mongodb-x509&sslClientCertificateKeyFile=testdata/one-pk-multiple-certs.pem», baseClient().SetAuth(Credential{ AuthMechanism: «mongodb-x509», AuthSource: «$external», // Subject name in the first certificate is used as the username for X509 auth. Username: `C=US,ST=New York,L=New York City,O=MongoDB,OU=Drivers,CN=localhost`, }).SetTLSConfig(&tls.Config{Certificates: make([]tls.Certificate, 1)}), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := Client().ApplyURI(tc.uri) // Manually add the URI and ConnString to the test expectations to avoid adding them in each test // definition. The ConnString should only be recorded if there was no error while parsing. tc.result.uri = tc.uri cs, err := connstring.ParseAndValidate(tc.uri) if err == nil { tc.result.cs = &cs } // We have to sort string slices in comparison, as Hosts resolved from SRV URIs do not have a set order. stringLess := func(a, b string) bool { return a < b } if diff := cmp.Diff( tc.result, result, cmp.AllowUnexported(ClientOptions{}, readconcern.ReadConcern{}, writeconcern.WriteConcern{}, readpref.ReadPref{}), cmp.Comparer(func(r1, r2 *bsoncodec.Registry) bool { return r1 == r2 }), cmp.Comparer(compareTLSConfig), cmp.Comparer(compareErrors), cmpopts.SortSlices(stringLess), cmpopts.IgnoreFields(connstring.ConnString{}, «SSLClientCertificateKeyPassword»), cmpopts.IgnoreFields(http.Client{}, «Transport»), ); diff != «» { t.Errorf(«URI did not apply correctly: (-want +got)n%s», diff) } }) } }) t.Run(«direct connection validation», func(t *testing.T) { t.Run(«multiple hosts», func(t *testing.T) { expectedErr := errors.New(«a direct connection cannot be made if multiple hosts are specified») testCases := []struct { name string opts *ClientOptions }{ {«hosts in URI», Client().ApplyURI(«mongodb://localhost,localhost2»)}, {«hosts in options», Client().SetHosts([]string{«localhost», «localhost2»})}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := tc.opts.SetDirect(true).Validate() assert.NotNil(t, err, «expected errror, got nil») assert.Equal(t, expectedErr.Error(), err.Error(), «expected error %v, got %v», expectedErr, err) }) } }) t.Run(«srv», func(t *testing.T) { expectedErr := errors.New(«a direct connection cannot be made if an SRV URI is used») // Use a non-SRV URI and manually set the scheme because using an SRV URI would force an SRV lookup. opts := Client().ApplyURI(«mongodb://localhost:27017») opts.cs.Scheme = connstring.SchemeMongoDBSRV err := opts.SetDirect(true).Validate() assert.NotNil(t, err, «expected errror, got nil») assert.Equal(t, expectedErr.Error(), err.Error(), «expected error %v, got %v», expectedErr, err) }) }) t.Run(«loadBalanced validation», func(t *testing.T) { testCases := []struct { name string opts *ClientOptions err error }{ {«multiple hosts in URI», Client().ApplyURI(«mongodb://foo,bar»), internal.ErrLoadBalancedWithMultipleHosts}, {«multiple hosts in options», Client().SetHosts([]string{«foo», «bar»}), internal.ErrLoadBalancedWithMultipleHosts}, {«replica set name», Client().SetReplicaSet(«foo»), internal.ErrLoadBalancedWithReplicaSet}, {«directConnection=true», Client().SetDirect(true), internal.ErrLoadBalancedWithDirectConnection}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // The loadBalanced option should not be validated if it is unset or false. err := tc.opts.Validate() assert.Nil(t, err, «Validate error when loadBalanced is unset: %v», err) tc.opts.SetLoadBalanced(false) err = tc.opts.Validate() assert.Nil(t, err, «Validate error when loadBalanced=false: %v», err) tc.opts.SetLoadBalanced(true) err = tc.opts.Validate() assert.Equal(t, tc.err, err, «expected error %v when loadBalanced=true, got %v», tc.err, err) }) } }) t.Run(«minPoolSize validation», func(t *testing.T) { testCases := []struct { name string opts *ClientOptions err error }{ { «minPoolSize < maxPoolSize», Client().SetMinPoolSize(128).SetMaxPoolSize(256), nil, }, { «minPoolSize == maxPoolSize», Client().SetMinPoolSize(128).SetMaxPoolSize(128), nil, }, { «minPoolSize > maxPoolSize», Client().SetMinPoolSize(64).SetMaxPoolSize(32), errors.New(«minPoolSize must be less than or equal to maxPoolSize, got minPoolSize=64 maxPoolSize=32»), }, { «maxPoolSize == 0», Client().SetMinPoolSize(128).SetMaxPoolSize(0), nil, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := tc.opts.Validate() assert.Equal(t, tc.err, err, «expected error %v, got %v», tc.err, err) }) } }) t.Run(«srvMaxHosts validation», func(t *testing.T) { testCases := []struct { name string opts *ClientOptions err error }{ {«replica set name», Client().SetReplicaSet(«foo»), internal.ErrSRVMaxHostsWithReplicaSet}, {«loadBalanced=true», Client().SetLoadBalanced(true), internal.ErrSRVMaxHostsWithLoadBalanced}, {«loadBalanced=false», Client().SetLoadBalanced(false), nil}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := tc.opts.Validate() assert.Nil(t, err, «Validate error when srvMxaHosts is unset: %v», err) tc.opts.SetSRVMaxHosts(0) err = tc.opts.Validate() assert.Nil(t, err, «Validate error when srvMaxHosts is 0: %v», err) tc.opts.SetSRVMaxHosts(2) err = tc.opts.Validate() assert.Equal(t, tc.err, err, «expected error %v when srvMaxHosts > 0, got %v», tc.err, err) }) } }) t.Run(«srvMaxHosts validation», func(t *testing.T) { t.Parallel() testCases := []struct { name string opts *ClientOptions err error }{ { name: «valid ServerAPI», opts: Client().SetServerAPIOptions(ServerAPI(ServerAPIVersion1)), err: nil, }, { name: «invalid ServerAPI», opts: Client().SetServerAPIOptions(ServerAPI(«nope»)), err: errors.New(`api version «nope» not supported; this driver version only supports API version «1»`), }, { name: «invalid ServerAPI with other invalid options», opts: Client().SetServerAPIOptions(ServerAPI(«nope»)).SetSRVMaxHosts(1).SetReplicaSet(«foo»), err: errors.New(`api version «nope» not supported; this driver version only supports API version «1»`), }, } for _, tc := range testCases { tc := tc // Capture range variable. t.Run(tc.name, func(t *testing.T) { t.Parallel() err := tc.opts.Validate() assert.Equal(t, tc.err, err, «want error %v, got error %v», tc.err, err) }) } }) } func createCertPool(t *testing.T, paths string) *x509.CertPool { t.Helper() pool := x509.NewCertPool() for _, path := range paths { pool.AddCert(loadCert(t, path)) } return pool } func loadCert(t *testing.T, file string) *x509.Certificate { t.Helper() data := readFile(t, file) block, _ := pem.Decode(data) cert, err := x509.ParseCertificate(block.Bytes) assert.Nil(t, err, «ParseCertificate error for %s: %v», file, err) return cert } func readFile(t *testing.T, path string) []byte { data, err := ioutil.ReadFile(path) assert.Nil(t, err, «ReadFile error for %s: %v», path, err) return data } type testDialer struct { Num int } func (testDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { return nil, nil } func compareTLSConfig(cfg1, cfg2 *tls.Config) bool { if cfg1 == nil && cfg2 == nil { return true } if cfg1 == nil || cfg2 == nil { return true } if (cfg1.RootCAs == nil && cfg1.RootCAs != nil) || (cfg1.RootCAs != nil && cfg1.RootCAs == nil) { return false } if cfg1.RootCAs != nil { cfg1Subjects := cfg1.RootCAs.Subjects() cfg2Subjects := cfg2.RootCAs.Subjects() if len(cfg1Subjects) != len(cfg2Subjects) { return false } for idx, firstSubject := range cfg1Subjects { if !bytes.Equal(firstSubject, cfg2Subjects[idx]) { return false } } } if len(cfg1.Certificates) != len(cfg2.Certificates) { return false } if cfg1.InsecureSkipVerify != cfg2.InsecureSkipVerify { return false } return true } func compareErrors(err1, err2 error) bool { if err1 == nil && err2 == nil { return true } if err1 == nil || err2 == nil { return false } ospe1, ok1 := err1.(*os.PathError) ospe2, ok2 := err2.(*os.PathError) if ok1 && ok2 { return ospe1.Op == ospe2.Op && ospe1.Path == ospe2.Path } if err1.Error() != err2.Error() { return false } return true }

have a problem, one project simple node js app with adding and getting data from user and saving into mongo (use 3.. ver), everything OK (saving, getting etc), example is

var express = require('express');
var router = express.Router();
var mongo = require('mongodb').MongoClient;
var objectID = require('mongodb').ObjectID;
var assert = require('assert');

const url = 'mongodb://localhost:27017';
const dbName = 'ldex';
const tblOffers = 'offers';

router.post('/insert', function (req, res, next) {
    var order = {
        type: 'Sell',
        ..............
        max: req.body.max,
        protection: req.body.protection,
        comment: req.body.comment,
        date: new Date().toDateString()
    };

    mongo.connect(url, function (err, client) {
        assert.equal(null, err);

        const db = client.db(dbName);

        db.collection(tblOffers).insertOne(order, function (err, res) {
            assert.equal(null, err);
            console.log('Offer placed');
            client.close();
        })
    });

    res.redirect('/exchange')
});

But here is another app, parser, that have the same mongo connection, it’s adding some data in it from other web-site (when do not use mongo all ok, I recieve data well), here is the part of code:

...
let assert = require('assert');
let mongo = require('mongodb').MongoClient;
let router = express.Router();

const url = 'mongodb://localhost:27017/';
const dbName = 'ceramo';
const tblOffers = 'items';

...

/*
 *  Get items from specific group
 */

function getGroupItems(url, callback) {
    request({uri: url}, function (error, response, body) {
        let list = [];
        let $ = cheerio.load(body);
        $('#tovar').find('a.cat_item_disc_a').each(function(i, elem) {
            list[i] = 'https://plitkazavr.ru' + $(this).attr('href');
        });
        callback(list);
    });
}

/*
 *  Parse one item from specific link
 */

function getItem(url) {
    request({uri: url}, function (error, response, body) {
        let list = {};
        let $ = cheerio.load(body);
        $('#item_border').find('> #item_prop > ul').find('li.item_list').each(function(i, elem) {
            list[$(this).find('.item_cell').first().text()] = $(this).find('div.item_cell.item_val').text();
        });
        list.price = (parseFloat($('#item_price').text()));
        list.img = ('https://plitkazavr.ru' + $('#item_img').attr('src'));
        list.meta = ($('#item_wrap').find('meta[itemprop="description"]').attr("content"));

        mongo.connect(url, function (err, client) {
            assert.equal(null, err);

            const db = client.db(dbName);

            db.collection(tblOffers).insertOne(order, function (err, res) {
                assert.equal(null, err);
                console.log('Offer placed');
                client.close();
            })
        });

    });
}

router.get('/parse', function (req, res, next) {

    getGroupItems('https://plitkazavr.ru/Naxos/Clio', function (items) {
        items.forEach(function(item, i, arr) {
            setTimeout(function() {
                getItem(item);
            }, 1000);
        });
    });

    res.end('ok');
});

And it’s down on connection and gives the

`Error: Invalid schema, expected `mongodb` or `mongodb+srv

Don’t understand where is a problem, help please…

отдает значения из secrets?
Задаю значения, объявляю потом env переменную в go.yml, но тест падает, когда пытаюсь использовать значение из переменной. С такой ошибкой: error parsing uri: scheme must be «mongodb» or «mongodb+srv»
То есть проблема в uri, которую я храню в secrets.
Локально все работает

go.yml

russian

software

it

database

go


2

ответов


Zver

А echo $URI выводит?

странно, он вообще не выполняется

Но я в коде еще вывожу uri, который получаю и он выводит 3 звездочки. Поэтому и нет возможности посмотреть что там под ними и понять где проблема

Похожие вопросы

#docker #pymongo

Вопрос:

У меня есть небольшое приложение для колбы, использующее MongoDB. Когда я запускаю приложение локально, используя flask run, оно работает идеально, и проблем с базой данных нет. Однако, когда я пытаюсь создать контейнер с помощью docker-compose up —build, я получаю эту ошибку:

 Successfully tagged web_messaging_website:latest
Recreating web_messaging_website_1 ... done
Attaching to web_messaging_website_1
website_1  | [2021-04-04 17:52:35  0000] [1] [INFO] Starting gunicorn 20.1.0
website_1  | [2021-04-04 17:52:35  0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
website_1  | [2021-04-04 17:52:35  0000] [1] [INFO] Using worker: sync
website_1  | [2021-04-04 17:52:35  0000] [8] [INFO] Booting worker with pid: 8
website_1  | [2021-04-04 17:52:36  0000] [8] [ERROR] Exception in worker process
website_1  | Traceback (most recent call last):
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 589, in spawn_worker
website_1  |     worker.init_process()
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 134, in init_process
website_1  |     self.load_wsgi()
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/base.py", line 146, in load_wsgi
website_1  |     self.wsgi = self.app.wsgi()
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
website_1  |     self.callable = self.load()
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 58, in load
website_1  |     return self.load_wsgiapp()
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 48, in load_wsgiapp
website_1  |     return util.import_app(self.app_uri)
website_1  |   File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 412, in import_app
website_1  |     app = app(*args, **kwargs)
website_1  |   File "/web_messaging/web_messaging/app.py", line 31, in create_app
website_1  |     extensions(app)
website_1  |   File "/web_messaging/web_messaging/app.py", line 72, in extensions
website_1  |     mongo.init_app(app)
website_1  |   File "/usr/local/lib/python3.7/site-packages/flask_pymongo/__init__.py", line 147, in init_app
website_1  |     parsed_uri = uri_parser.parse_uri(uri)
website_1  |   File "/usr/local/lib/python3.7/site-packages/pymongo/uri_parser.py", line 434, in parse_uri
website_1  |     "begin with '%s' or '%s'" % (SCHEME, SRV_SCHEME))
website_1  | pymongo.errors.InvalidURI: Invalid URI scheme: URI must begin with 'mongodb://' or 'mongodb srv://'
website_1  | [2021-04-04 17:52:36  0000] [8] [INFO] Worker exiting (pid: 8)
website_1  | [2021-04-04 17:52:36  0000] [1] [INFO] Shutting down: Master
website_1  | [2021-04-04 17:52:36  0000] [1] [INFO] Reason: Worker failed to boot.
 

Я использую Flask-PyMongo==2.3.0 и pymongo==3.11.3.

 .
├── ...
├── web_messaging                    
│   ├── app.py 
│   ├── __init__.py        
│   ├── ...       
│            
├── __init__py             
├── .env             
├── requirements.txt              
├── docker-compose.yml
├── Dockerfile
└── config 
   ├── settings.py 
   ├── gunicorn.py
   └── __init__.py
 

докер-compose.yml

 version: '2'

services:
  website:
    build: .
    command: >
      gunicorn -c "python:config.gunicorn" --reload "web_messaging.app:create_app()"
    env_file:
      - '.env'
    volumes:
      - '.:/web_messaging'
    ports:
      - '8000:8000'
 

.env

 MONGO_URI='mongodb srv://USERNAME:PASSWORD@cluster0.fut2y.mongodb.net/mousset?ssl=trueamp;ssl_cert_reqs=CERT_NONE'
 

Комментарии:

1. Просто предположение — попробуйте удалить кавычки в вашем файле .env, например MONGO_URI=mongodb srv...

Понравилась статья? Поделить с друзьями:
  • Error parsing timestamp
  • Error parsing the server clients xml file
  • Error parsing the response to json
  • Error parsing remote folder listing
  • Error parsing pcc subspaces from pcct astra linux