From d4ac72577d1b2ae928339e85aee6e6d37e6e748a Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 30 Jan 2009 12:37:46 -0500 Subject: [PATCH 1/9] Kill child mongod instances if killed abruptly --- shell/ShellUtils.cpp | 8 ++++++-- shell/ShellUtils.h | 1 + shell/dbshell.cpp | 13 ++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/shell/ShellUtils.cpp b/shell/ShellUtils.cpp index baa6bff09f6..5747e0d63be 100644 --- a/shell/ShellUtils.cpp +++ b/shell/ShellUtils.cpp @@ -315,10 +315,14 @@ v8::Handle< v8::Value > StopMongod( const v8::Arguments &a ) { return v8::Undefined(); } +void KillMongodbInstances() { + for( map< int, pid_t >::iterator i = dbs.begin(); i != dbs.end(); ++i ) + killDb( i->first ); +} + MongodScope::~MongodScope() { try { - for( map< int, pid_t >::iterator i = dbs.begin(); i != dbs.end(); ++i ) - killDb( i->first ); + KillMongodbInstances(); } catch ( ... ) { assert( false ); } diff --git a/shell/ShellUtils.h b/shell/ShellUtils.h index 23ba33eeb8b..2e3b09cbe97 100644 --- a/shell/ShellUtils.h +++ b/shell/ShellUtils.h @@ -45,3 +45,4 @@ struct MongodScope { }; void RecordMyLocation( const char *_argv0 ); +void KillMongodbInstances(); diff --git a/shell/dbshell.cpp b/shell/dbshell.cpp index 27b40c8da6d..4170f7da2f3 100644 --- a/shell/dbshell.cpp +++ b/shell/dbshell.cpp @@ -16,6 +16,17 @@ void quitNicely( int sig ){ exit(0); } +void quitAbruptly( int sig ) { + KillMongodbInstances(); + exit(14); +} + +void setupSignals() { + signal( SIGINT , quitNicely ); + signal( SIGABRT , quitAbruptly ); + signal( SIGSEGV , quitAbruptly ); +} + string fixHost( string url , string host , string port ){ if ( host.size() == 0 && port.size() == 0 ) return url; @@ -38,7 +49,7 @@ string fixHost( string url , string host , string port ){ } int main(int argc, char* argv[]) { - signal( SIGINT , quitNicely ); + setupSignals(); RecordMyLocation( argv[ 0 ] ); From 898a1f66c25f934e1ceaa910e0b9e764edeb5b85 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 30 Jan 2009 14:51:31 -0500 Subject: [PATCH 2/9] Add slaveOk option --- shell/MongoJS.cpp | 9 ++++++--- shell/mongo.js | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/shell/MongoJS.cpp b/shell/MongoJS.cpp index 422d8634b10..2e5e45dbc58 100644 --- a/shell/MongoJS.cpp +++ b/shell/MongoJS.cpp @@ -76,7 +76,7 @@ Handle mongoInit(const Arguments& args){ } args.This()->Set( CONN_STRING , External::New( conn ) ); - + args.This()->Set( String::New( "slaveOk" ) , Boolean::New( false ) ); return v8::Undefined(); } @@ -292,9 +292,12 @@ Handle mongoFind(const Arguments& args){ if ( haveFields ) fields = v8ToMongo( args[2]->ToObject() ); - auto_ptr cursor = conn->query( ns, q , (int)(args[3]->ToNumber()->Value()) , (int)(args[4]->ToNumber()->Value()) , haveFields ? &fields : 0 ); - Local mongo = args.This(); + Local slaveOkVal = mongo->Get( String::New( "slaveOk" ) ); + jsassert( slaveOkVal->IsBoolean(), "slaveOk member invalid" ); + bool slaveOk = slaveOkVal->BooleanValue(); + + auto_ptr cursor = conn->query( ns, q , (int)(args[3]->ToNumber()->Value()) , (int)(args[4]->ToNumber()->Value()) , haveFields ? &fields : 0, slaveOk ? Option_SlaveOk : 0 ); v8::Function * cons = (v8::Function*)( *( mongo->Get( String::New( "internalCursor" ) ) ) ); Local c = cons->NewInstance(); diff --git a/shell/mongo.js b/shell/mongo.js index ef6ebd84dac..97e2c15a322 100644 --- a/shell/mongo.js +++ b/shell/mongo.js @@ -1,5 +1,6 @@ // mongo.js +// NOTE 'Mongo' may be defined here or in MongoJS.cpp. Add code to init, not to this constructor. if ( typeof Mongo == "undefined" ){ Mongo = function( host ){ this.init( host ); @@ -13,6 +14,10 @@ Mongo.prototype.update = function( ns , query , obj ){ throw "update not impleme mongoInject( Mongo.prototype ); +Mongo.prototype.setSlaveOk = function() { + this.slaveOk = true; +} + Mongo.prototype.getDB = function( name ){ return new DB( this , name ); } From 4b1a2ca99952bdabc152384d6903cd872804bfaf Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 30 Jan 2009 14:51:54 -0500 Subject: [PATCH 3/9] Add pair1.js test --- jstests/repl/pair1.js | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 jstests/repl/pair1.js diff --git a/jstests/repl/pair1.js b/jstests/repl/pair1.js new file mode 100644 index 00000000000..6b83a5e25a3 --- /dev/null +++ b/jstests/repl/pair1.js @@ -0,0 +1,99 @@ +// Basic pairing test + +var baseName = "jstests_repl1test"; + +ismaster = function( n ) { + im = n.getDB( "admin" ).runCommand( { "ismaster" : 1 } ); + assert( im ); + return im.ismaster; +} + +var writeOneIdx = 0; + +writeOne = function( n ) { + n.getDB( baseName ).z.save( { _id: new ObjectId(), i: ++writeOneIdx } ); +} + +getOne = function( n ) { + print( tojson( n.getDB( baseName ).z.find( { i: writeOneIdx } ).toArray() ) ); + return n.getDB( baseName ).z.find( { i: writeOneIdx } ).toArray().length; +} + +checkWrite = function( m, s ) { + writeOne( m ); + assert.eq( 1, getOne( m ) ); + s.setSlaveOk(); + assert.soon( function() { + if ( -1 == s.getDBNames().indexOf( baseName ) ) + return false; + if ( -1 == s.getDB( baseName ).getCollectionNames().indexOf( "z" ) ) + return false; + return 1 == getOne( s ); + } ); +} + +// spec small oplog for fast startup on 64bit machines +a = startMongod( "--port", "27018", "--dbpath", "/data/db/" + baseName + "-arbiter" ); +l = startMongod( "--port", "27019", "--dbpath", "/data/db/" + baseName + "-left", "--pairwith", "127.0.0.1:27020", "127.0.0.1:27018", "--oplogSize", "1" ); +r = startMongod( "--port", "27020", "--dbpath", "/data/db/" + baseName + "-right", "--pairwith", "127.0.0.1:27019", "127.0.0.1:27018", "--oplogSize", "1" ); + +print( a.slaveOk ); + +assert.soon( function() { + am = ismaster( a ); + lm = ismaster( l ); + rm = ismaster( r ); + + assert( am == 1 ); + assert( lm == -1 || lm == 0 ); + assert( rm == -1 || rm == 0 || rm == 1 ); + + return ( lm == 0 && rm == 1 ); + } ); + +checkWrite( r, l ); + +stopMongod( 27020 ); + +assert.soon( function() { + lm = ismaster( l ); + assert( lm == 0 || lm == 1 ); + return ( lm == 1 ); + } ); + +r = startMongod( "--port", "27020", "--dbpath", "/data/db/" + baseName + "-right", "--pairwith", "127.0.0.1:27019", "127.0.0.1:27018", "--oplogSize", "1" ); + +assert.soon( function() { + lm = ismaster( l ); + rm = ismaster( r ); + + assert( lm == 1 ); + assert( rm == -1 || rm == 0 ); + + return ( rm == 0 ); + } ); + +// Once this returns, the initial sync for r will have completed. +checkWrite( l, r ); + +stopMongod( 27019 ); + +assert.soon( function() { + rm = ismaster( r ); + assert( rm == 0 || rm == 1 ); + return ( rm == 1 ); + } ); + +l = startMongod( "--port", "27019", "--dbpath", "/data/db/" + baseName + "-left", "--pairwith", "127.0.0.1:27020", "127.0.0.1:27018", "--oplogSize", "1" ); + +assert.soon( function() { + lm = ismaster( l ); + rm = ismaster( r ); + + assert( lm == -1 || lm == 0 ); + assert( rm == 1 ); + + return ( lm == 0 && rm == 1 ); + } ); + +checkWrite( r, l ); From 2ecf386ce66a2fb8ad8583f88e7d2076495f2b0e Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 30 Jan 2009 14:57:01 -0500 Subject: [PATCH 4/9] Cleanup --- jstests/repl/pair1.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/jstests/repl/pair1.js b/jstests/repl/pair1.js index 6b83a5e25a3..59b91e570ad 100644 --- a/jstests/repl/pair1.js +++ b/jstests/repl/pair1.js @@ -14,21 +14,20 @@ writeOne = function( n ) { n.getDB( baseName ).z.save( { _id: new ObjectId(), i: ++writeOneIdx } ); } -getOne = function( n ) { - print( tojson( n.getDB( baseName ).z.find( { i: writeOneIdx } ).toArray() ) ); +getCount = function( n ) { return n.getDB( baseName ).z.find( { i: writeOneIdx } ).toArray().length; } checkWrite = function( m, s ) { writeOne( m ); - assert.eq( 1, getOne( m ) ); + assert.eq( 1, getCount( m ) ); s.setSlaveOk(); assert.soon( function() { if ( -1 == s.getDBNames().indexOf( baseName ) ) return false; if ( -1 == s.getDB( baseName ).getCollectionNames().indexOf( "z" ) ) return false; - return 1 == getOne( s ); + return 1 == getCount( s ); } ); } @@ -37,8 +36,6 @@ a = startMongod( "--port", "27018", "--dbpath", "/data/db/" + baseName + "-arbit l = startMongod( "--port", "27019", "--dbpath", "/data/db/" + baseName + "-left", "--pairwith", "127.0.0.1:27020", "127.0.0.1:27018", "--oplogSize", "1" ); r = startMongod( "--port", "27020", "--dbpath", "/data/db/" + baseName + "-right", "--pairwith", "127.0.0.1:27019", "127.0.0.1:27018", "--oplogSize", "1" ); -print( a.slaveOk ); - assert.soon( function() { am = ismaster( a ); lm = ismaster( l ); From 7fa1cf29da60c930771e16654de6b0ae055253f4 Mon Sep 17 00:00:00 2001 From: Aaron Date: Fri, 30 Jan 2009 14:57:17 -0500 Subject: [PATCH 5/9] Update project --- mongo.xcodeproj/project.pbxproj | 156 ++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/mongo.xcodeproj/project.pbxproj b/mongo.xcodeproj/project.pbxproj index 0498942c483..f80749be5fc 100644 --- a/mongo.xcodeproj/project.pbxproj +++ b/mongo.xcodeproj/project.pbxproj @@ -221,6 +221,64 @@ 93A8C4CA0F31257B00C92B85 /* update.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update.js; sourceTree = ""; }; 93A8C4CB0F31257B00C92B85 /* update2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update2.js; sourceTree = ""; }; 93A8C4CC0F31257B00C92B85 /* where1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = where1.js; sourceTree = ""; }; + 93A8C7B70F325A3100C92B85 /* .dbshell */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .dbshell; sourceTree = ""; }; + 93A8C7B80F325A3100C92B85 /* _runner.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = _runner.js; sourceTree = ""; }; + 93A8C7B90F325A3100C92B85 /* apitest_db.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = apitest_db.js; sourceTree = ""; }; + 93A8C7BA0F325A3100C92B85 /* apitest_dbcollection.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = apitest_dbcollection.js; sourceTree = ""; }; + 93A8C7BB0F325A3100C92B85 /* auth.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = auth.js; sourceTree = ""; }; + 93A8C7BC0F325A3100C92B85 /* basic1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic1.js; sourceTree = ""; }; + 93A8C7BD0F325A3100C92B85 /* basic2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic2.js; sourceTree = ""; }; + 93A8C7BE0F325A3100C92B85 /* basic3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic3.js; sourceTree = ""; }; + 93A8C7BF0F325A3100C92B85 /* basic4.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic4.js; sourceTree = ""; }; + 93A8C7C00F325A3100C92B85 /* basic5.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic5.js; sourceTree = ""; }; + 93A8C7C10F325A3100C92B85 /* basic6.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic6.js; sourceTree = ""; }; + 93A8C7C20F325A3100C92B85 /* basic7.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = basic7.js; sourceTree = ""; }; + 93A8C7C30F325A3100C92B85 /* capped.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = capped.js; sourceTree = ""; }; + 93A8C7C40F325A3100C92B85 /* capped2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = capped2.js; sourceTree = ""; }; + 93A8C7C50F325A3100C92B85 /* cursor2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor2.js; sourceTree = ""; }; + 93A8C7C60F325A3100C92B85 /* cursor3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor3.js; sourceTree = ""; }; + 93A8C7C70F325A3100C92B85 /* cursor4.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor4.js; sourceTree = ""; }; + 93A8C7C80F325A3100C92B85 /* cursor5.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor5.js; sourceTree = ""; }; + 93A8C7C90F325A3100C92B85 /* cursor6.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor6.js; sourceTree = ""; }; + 93A8C7CA0F325A3100C92B85 /* cursor7.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = cursor7.js; sourceTree = ""; }; + 93A8C7CB0F325A3100C92B85 /* error1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = error1.js; sourceTree = ""; }; + 93A8C7CC0F325A3100C92B85 /* find1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = find1.js; sourceTree = ""; }; + 93A8C7CD0F325A3100C92B85 /* find2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = find2.js; sourceTree = ""; }; + 93A8C7CE0F325A3100C92B85 /* find3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = find3.js; sourceTree = ""; }; + 93A8C7CF0F325A3100C92B85 /* index1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index1.js; sourceTree = ""; }; + 93A8C7D00F325A3100C92B85 /* index2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index2.js; sourceTree = ""; }; + 93A8C7D10F325A3100C92B85 /* index3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index3.js; sourceTree = ""; }; + 93A8C7D20F325A3100C92B85 /* index4.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index4.js; sourceTree = ""; }; + 93A8C7D30F325A3100C92B85 /* index5.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index5.js; sourceTree = ""; }; + 93A8C7D40F325A3100C92B85 /* index6.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index6.js; sourceTree = ""; }; + 93A8C7D50F325A3100C92B85 /* index7.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index7.js; sourceTree = ""; }; + 93A8C7D60F325A3100C92B85 /* index_check1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = index_check1.js; sourceTree = ""; }; + 93A8C7D70F325A3100C92B85 /* jni1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni1.js; sourceTree = ""; }; + 93A8C7D80F325A3100C92B85 /* jni2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni2.js; sourceTree = ""; }; + 93A8C7D90F325A3100C92B85 /* jni3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni3.js; sourceTree = ""; }; + 93A8C7DA0F325A3100C92B85 /* jni4.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni4.js; sourceTree = ""; }; + 93A8C7DB0F325A3100C92B85 /* jni7.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni7.js; sourceTree = ""; }; + 93A8C7DC0F325A3100C92B85 /* jni8.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni8.js; sourceTree = ""; }; + 93A8C7DD0F325A3100C92B85 /* jni9.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = jni9.js; sourceTree = ""; }; + 93A8C7E00F325A3100C92B85 /* compile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = compile; sourceTree = ""; }; + 93A8C7E10F325A3100C92B85 /* objid1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = objid1.js; sourceTree = ""; }; + 93A8C7E20F325A3100C92B85 /* objid2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = objid2.js; sourceTree = ""; }; + 93A8C7E30F325A3100C92B85 /* objid3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = objid3.js; sourceTree = ""; }; + 93A8C7E50F325A3100C92B85 /* find1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = find1.js; sourceTree = ""; }; + 93A8C7E60F325A3100C92B85 /* remove.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = remove.js; sourceTree = ""; }; + 93A8C7E70F325A3100C92B85 /* remove2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = remove2.js; sourceTree = ""; }; + 93A8C7E80F325A3100C92B85 /* remove4.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = remove4.js; sourceTree = ""; }; + 93A8C7EA0F325A3100C92B85 /* pair1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = pair1.js; sourceTree = ""; }; + 93A8C7EB0F325A3100C92B85 /* repl1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = repl1.js; sourceTree = ""; }; + 93A8C7EC0F325A3100C92B85 /* repl2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = repl2.js; sourceTree = ""; }; + 93A8C7ED0F325A3100C92B85 /* sort1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = sort1.js; sourceTree = ""; }; + 93A8C7EE0F325A3100C92B85 /* sort2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = sort2.js; sourceTree = ""; }; + 93A8C7EF0F325A3100C92B85 /* sort3.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = sort3.js; sourceTree = ""; }; + 93A8C7F00F325A3100C92B85 /* sort_numeric.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = sort_numeric.js; sourceTree = ""; }; + 93A8C7F10F325A3100C92B85 /* uniqueness.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = uniqueness.js; sourceTree = ""; }; + 93A8C7F20F325A3100C92B85 /* update.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update.js; sourceTree = ""; }; + 93A8C7F30F325A3100C92B85 /* update2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update2.js; sourceTree = ""; }; + 93A8C7F40F325A3100C92B85 /* where1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = where1.js; sourceTree = ""; }; 93AF75500F216D0300994C66 /* jsontests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsontests.cpp; sourceTree = ""; }; 93B4A81A0F1C01B4000C862C /* security.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = security.cpp; sourceTree = ""; }; 93B4A81B0F1C01D8000C862C /* lasterror.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lasterror.cpp; sourceTree = ""; }; @@ -289,6 +347,7 @@ 9302D9AE0F30B17400DFA4EF /* jstests */ = { isa = PBXGroup; children = ( + 93A8C7B60F325A3100C92B85 /* jstests */, 93A8C4950F31257B00C92B85 /* jstests */, 9302D9E60F30B5A300DFA4EF /* repl1.js */, 9302D9AF0F30B17400DFA4EF /* apitest_db.js */, @@ -569,6 +628,103 @@ path = perf; sourceTree = ""; }; + 93A8C7B60F325A3100C92B85 /* jstests */ = { + isa = PBXGroup; + children = ( + 93A8C7B70F325A3100C92B85 /* .dbshell */, + 93A8C7B80F325A3100C92B85 /* _runner.js */, + 93A8C7B90F325A3100C92B85 /* apitest_db.js */, + 93A8C7BA0F325A3100C92B85 /* apitest_dbcollection.js */, + 93A8C7BB0F325A3100C92B85 /* auth.js */, + 93A8C7BC0F325A3100C92B85 /* basic1.js */, + 93A8C7BD0F325A3100C92B85 /* basic2.js */, + 93A8C7BE0F325A3100C92B85 /* basic3.js */, + 93A8C7BF0F325A3100C92B85 /* basic4.js */, + 93A8C7C00F325A3100C92B85 /* basic5.js */, + 93A8C7C10F325A3100C92B85 /* basic6.js */, + 93A8C7C20F325A3100C92B85 /* basic7.js */, + 93A8C7C30F325A3100C92B85 /* capped.js */, + 93A8C7C40F325A3100C92B85 /* capped2.js */, + 93A8C7C50F325A3100C92B85 /* cursor2.js */, + 93A8C7C60F325A3100C92B85 /* cursor3.js */, + 93A8C7C70F325A3100C92B85 /* cursor4.js */, + 93A8C7C80F325A3100C92B85 /* cursor5.js */, + 93A8C7C90F325A3100C92B85 /* cursor6.js */, + 93A8C7CA0F325A3100C92B85 /* cursor7.js */, + 93A8C7CB0F325A3100C92B85 /* error1.js */, + 93A8C7CC0F325A3100C92B85 /* find1.js */, + 93A8C7CD0F325A3100C92B85 /* find2.js */, + 93A8C7CE0F325A3100C92B85 /* find3.js */, + 93A8C7CF0F325A3100C92B85 /* index1.js */, + 93A8C7D00F325A3100C92B85 /* index2.js */, + 93A8C7D10F325A3100C92B85 /* index3.js */, + 93A8C7D20F325A3100C92B85 /* index4.js */, + 93A8C7D30F325A3100C92B85 /* index5.js */, + 93A8C7D40F325A3100C92B85 /* index6.js */, + 93A8C7D50F325A3100C92B85 /* index7.js */, + 93A8C7D60F325A3100C92B85 /* index_check1.js */, + 93A8C7D70F325A3100C92B85 /* jni1.js */, + 93A8C7D80F325A3100C92B85 /* jni2.js */, + 93A8C7D90F325A3100C92B85 /* jni3.js */, + 93A8C7DA0F325A3100C92B85 /* jni4.js */, + 93A8C7DB0F325A3100C92B85 /* jni7.js */, + 93A8C7DC0F325A3100C92B85 /* jni8.js */, + 93A8C7DD0F325A3100C92B85 /* jni9.js */, + 93A8C7DE0F325A3100C92B85 /* logs */, + 93A8C7E10F325A3100C92B85 /* objid1.js */, + 93A8C7E20F325A3100C92B85 /* objid2.js */, + 93A8C7E30F325A3100C92B85 /* objid3.js */, + 93A8C7E40F325A3100C92B85 /* perf */, + 93A8C7E60F325A3100C92B85 /* remove.js */, + 93A8C7E70F325A3100C92B85 /* remove2.js */, + 93A8C7E80F325A3100C92B85 /* remove4.js */, + 93A8C7E90F325A3100C92B85 /* repl */, + 93A8C7ED0F325A3100C92B85 /* sort1.js */, + 93A8C7EE0F325A3100C92B85 /* sort2.js */, + 93A8C7EF0F325A3100C92B85 /* sort3.js */, + 93A8C7F00F325A3100C92B85 /* sort_numeric.js */, + 93A8C7F10F325A3100C92B85 /* uniqueness.js */, + 93A8C7F20F325A3100C92B85 /* update.js */, + 93A8C7F30F325A3100C92B85 /* update2.js */, + 93A8C7F40F325A3100C92B85 /* where1.js */, + ); + name = jstests; + sourceTree = ""; + }; + 93A8C7DE0F325A3100C92B85 /* logs */ = { + isa = PBXGroup; + children = ( + 93A8C7DF0F325A3100C92B85 /* pipes */, + ); + path = logs; + sourceTree = ""; + }; + 93A8C7DF0F325A3100C92B85 /* pipes */ = { + isa = PBXGroup; + children = ( + 93A8C7E00F325A3100C92B85 /* compile */, + ); + path = pipes; + sourceTree = ""; + }; + 93A8C7E40F325A3100C92B85 /* perf */ = { + isa = PBXGroup; + children = ( + 93A8C7E50F325A3100C92B85 /* find1.js */, + ); + path = perf; + sourceTree = ""; + }; + 93A8C7E90F325A3100C92B85 /* repl */ = { + isa = PBXGroup; + children = ( + 93A8C7EA0F325A3100C92B85 /* pair1.js */, + 93A8C7EB0F325A3100C92B85 /* repl1.js */, + 93A8C7EC0F325A3100C92B85 /* repl2.js */, + ); + path = repl; + sourceTree = ""; + }; C6859E8C029090F304C91782 /* Documentation */ = { isa = PBXGroup; children = ( From bc0133da89a0610538b4bc6e1e5a5fb704366495 Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Fri, 30 Jan 2009 15:05:18 -0500 Subject: [PATCH 6/9] method for taking a string and computing string digest --- util/md5.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/util/md5.hpp b/util/md5.hpp index ba2a84b7414..f191b1566e6 100644 --- a/util/md5.hpp +++ b/util/md5.hpp @@ -29,4 +29,10 @@ namespace mongo { return ss.str(); } + inline std::string md5simpledigest( string s ){ + md5digest d; + md5( s.c_str() , d ); + return digestToString( d ); + } + } // namespace mongo From c3d792be346f89de07437cb8a4c60c6ab7c690cf Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Fri, 30 Jan 2009 15:05:28 -0500 Subject: [PATCH 7/9] getHeader --- util/miniwebserver.cpp | 20 +++++++++++++++++++- util/miniwebserver.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/util/miniwebserver.cpp b/util/miniwebserver.cpp index 4b4a1ad70f7..77c44dfc396 100644 --- a/util/miniwebserver.cpp +++ b/util/miniwebserver.cpp @@ -20,6 +20,8 @@ #include "stdafx.h" #include "miniwebserver.h" +#include + namespace mongo { MiniWebServer::MiniWebServer() { @@ -167,7 +169,23 @@ namespace mongo { ::send(s, response.c_str(), response.size(), 0); } - + + string MiniWebServer::getHeader( const char * req , string wanted ){ + const char * headers = strstr( req , "\n" ); + if ( ! headers ) + return ""; + pcrecpp::StringPiece input( headers + 1 ); + + string name; + string val; + pcrecpp::RE re("([\\w\\-]+): (.*?)\r?\n"); + while ( re.Consume( &input, &name, &val) ){ + if ( name == wanted ) + return val; + } + return ""; + } + void MiniWebServer::run() { SockAddr from; while ( 1 ) { diff --git a/util/miniwebserver.h b/util/miniwebserver.h index d41935bd49f..ac2872276e4 100644 --- a/util/miniwebserver.h +++ b/util/miniwebserver.h @@ -42,6 +42,7 @@ namespace mongo { protected: string parseURL( const char * buf ); string parseMethod( const char * headers ); + string getHeader( const char * headers , string name ); void parseParams( map & params , string query ); static const char *body( const char *buf ); From 120f8597044a6dec720e7120d208dffb15b64fd2 Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Fri, 30 Jan 2009 15:06:12 -0500 Subject: [PATCH 8/9] change password digest from md5( "mongo" + pwd ) to md5( username + ":mongo:" + pwd ) --- client/dbclient.cpp | 9 +++++---- client/dbclient.h | 2 +- client/examples/authTest.cpp | 2 +- shell/db.js | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/client/dbclient.cpp b/client/dbclient.cpp index 34595f021af..f149ca9431e 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -106,12 +106,13 @@ namespace mongo { BSONObj getnoncecmdobj = fromjson("{getnonce:1}"); - string DBClientWithCommands::createPasswordDigest( const char * clearTextPassword ){ + string DBClientWithCommands::createPasswordDigest( const char * username , const char * clearTextPassword ){ md5digest d; { md5_state_t st; md5_init(&st); - md5_append(&st, (const md5_byte_t *) "mongo", 5 ); + md5_append(&st, (const md5_byte_t *) username, strlen(username)); + md5_append(&st, (const md5_byte_t *) ":mongo:", 5 ); md5_append(&st, (const md5_byte_t *) clearTextPassword, strlen(clearTextPassword)); md5_finish(&st, d); } @@ -123,7 +124,7 @@ namespace mongo { string password = password_text; if( digestPassword ) - password = createPasswordDigest( password_text ); + password = createPasswordDigest( username , password_text ); BSONObj info; string nonce; @@ -305,7 +306,7 @@ namespace mongo { bool DBClientConnection::auth(const char *dbname, const char *username, const char *password_text, string& errmsg, bool digestPassword) { string password = password_text; if( digestPassword ) - password = createPasswordDigest( password_text ); + password = createPasswordDigest( username , password_text ); if( autoReconnect ) { /* note we remember the auth info before we attempt to auth -- if the connection is broken, we will diff --git a/client/dbclient.h b/client/dbclient.h index 520c759b7d1..4601599a75e 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -248,7 +248,7 @@ namespace mongo { */ virtual bool auth(const char *dbname, const char *username, const char *pwd, string& errmsg, bool digestPassword = true); - string createPasswordDigest( const char * clearTextPassword ); + string createPasswordDigest( const char * username , const char * clearTextPassword ); /* returns true in isMaster parm if this db is the current master of a replica pair. diff --git a/client/examples/authTest.cpp b/client/examples/authTest.cpp index 50cef661cdd..78fc57286b6 100644 --- a/client/examples/authTest.cpp +++ b/client/examples/authTest.cpp @@ -19,7 +19,7 @@ int main() { conn.remove( "test.system.users" , emptyObj ); } - conn.insert( "test.system.users" , BSON( "user" << "eliot" << "pwd" << conn.createPasswordDigest( "bar" ) ) ); + conn.insert( "test.system.users" , BSON( "user" << "eliot" << "pwd" << conn.createPasswordDigest( "eliot" , "bar" ) ) ); errmsg.clear(); bool ok = conn.auth( "test" , "eliot" , "bar" , errmsg ); diff --git a/shell/db.js b/shell/db.js index ef2d6bf274c..591803bcd04 100644 --- a/shell/db.js +++ b/shell/db.js @@ -35,7 +35,7 @@ DB.prototype.addUser = function( username , pass ){ var c = this.getCollection( "system.users" ); var u = c.findOne( { user : username } ) || { user : username }; - u.pwd = hex_md5( "mongo" + pass ); + u.pwd = hex_md5( username + ":mongo:" + pass ); print( tojson( u ) ); c.save( u ); @@ -49,7 +49,7 @@ DB.prototype.auth = function( username , pass ){ authenticate : 1 , user : username , nonce : n.nonce , - key : hex_md5( n.nonce + username + hex_md5( "mongo" + pass ) ) + key : hex_md5( n.nonce + username + hex_md5( username + ":mongo:" + pass ) ) } ); From a53d5c7c1cebb9081f492b3ebd3d39873477da40 Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Fri, 30 Jan 2009 15:06:33 -0500 Subject: [PATCH 9/9] if there are users in admin, need to authenticate against that to use webserver --- db/dbwebserver.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/db/dbwebserver.cpp b/db/dbwebserver.cpp index 5cadb0cefff..7bd01064737 100644 --- a/db/dbwebserver.cpp +++ b/db/dbwebserver.cpp @@ -18,12 +18,15 @@ #include "stdafx.h" #include "../util/miniwebserver.h" +#include "../util/md5.hpp" #include "db.h" #include "repl.h" #include "replset.h" #include "instance.h" #include "security.h" +#include + namespace mongo { extern int port; @@ -152,6 +155,62 @@ namespace mongo { ss << "\nreplInfo: " << replInfo << '\n'; } + + bool allowed( const char * rq , vector& headers ){ + + if ( db.findOne( "admin.system.users" , emptyObj ).isEmpty() ) + return true; + + string auth = getHeader( rq , "Authorization" ); + + if ( auth.size() > 0 && auth.find( "Digest " ) == 0 ){ + auth = auth.substr( 7 ) + ", "; + + map parms; + pcrecpp::StringPiece input( auth ); + + string name, val; + pcrecpp::RE re("(\\w+)=\"?(.*?)\"?, "); + while ( re.Consume( &input, &name, &val) ){ + parms[name] = val; + } + + BSONObj user = db.findOne( "admin.system.users" , BSON( "user" << parms["username"] ) ); + if ( ! user.isEmpty() ){ + string ha1 = user["pwd"].str(); + string ha2 = md5simpledigest( (string)"GET" + ":" + parms["uri"] ); + + string r = ha1 + ":" + parms["nonce"]; + if ( parms["nc"].size() && parms["cnonce"].size() && parms["qop"].size() ){ + r += ":"; + r += parms["nc"]; + r += ":"; + r += parms["cnonce"]; + r += ":"; + r += parms["qop"]; + } + r += ":"; + r += ha2; + r = md5simpledigest( r ); + + if ( r == parms["response"] ) + return true; + } + + + } + + stringstream authHeader; + authHeader + << "WWW-Authenticate: " + << "Digest realm=\"mongo\", " + << "nonce=\"abc\", " + << "algorithm=MD5, qop=\"auth\" " + ; + + headers.push_back( authHeader.str() ); + return 0; + } virtual void doRequest( const char *rq, // the full request @@ -163,6 +222,12 @@ namespace mongo { ) { //out() << "url [" << url << "]" << endl; + + if ( ! allowed( rq , headers ) ){ + responseCode = 401; + responseMsg = "not allowed\n"; + return; + } if ( url.size() > 1 ) { handleRESTRequest( rq , url , responseMsg , responseCode , headers );