@@ -49,6 +49,8 @@ sub new {
4949 ' protocol:s' => { name => ' protocol' },
5050 ' username:s' => { name => ' username' },
5151 ' password:s' => { name => ' password' },
52+ ' auth-source:s' => { name => ' auth_source' },
53+ ' replica-set:s' => { name => ' replica_set' },
5254 ' timeout:s' => { name => ' timeout' },
5355 ' ssl-opt:s@' => { name => ' ssl_opt' },
5456 ' no-ssl' => { name => ' no_ssl' }
@@ -79,6 +81,8 @@ sub check_options {
7981 $self -> {timeout } = (defined ($self -> {option_results }-> {timeout })) ? $self -> {option_results }-> {timeout } : 10;
8082 $self -> {username } = (defined ($self -> {option_results }-> {username })) ? $self -> {option_results }-> {username } : ' ' ;
8183 $self -> {password } = (defined ($self -> {option_results }-> {password })) ? $self -> {option_results }-> {password } : ' ' ;
84+ $self -> {auth_source } = (defined ($self -> {option_results }-> {auth_source })) ? $self -> {option_results }-> {auth_source } : ' ' ;
85+ $self -> {replica_set } = (defined ($self -> {option_results }-> {replica_set })) ? $self -> {option_results }-> {replica_set } : ' ' ;
8286 $self -> {no_ssl } = (defined ($self -> {option_results }-> {no_ssl })) ? 1 : 0;
8387
8488 if ($self -> {hostname } eq ' ' ) {
@@ -106,25 +110,58 @@ sub get_port {
106110 return $self -> {port };
107111}
108112
109- sub connect {
113+ sub build_uri {
110114 my ($self , %options ) = @_ ;
111115
112- my $uri = URI::Encode-> new({encode_reserved => 1});
113- my $encoded_username = $uri -> encode($self -> {username });
114- my $encoded_password = $uri -> encode($self -> {password });
116+ my $encoder = URI::Encode-> new({encode_reserved => 1});
117+ my $encoded_username = $encoder -> encode($self -> {username });
118+ my $encoded_password = $encoder -> encode($self -> {password });
119+
120+ my $host = defined ($options {host }) && $options {host } ne ' ' ? $options {host } : $self -> {hostname };
121+ my $port = defined ($options {port }) ? $options {port } : $self -> {port };
115122
116- $uri = $self -> {protocol } . ' ://' ;
123+ my $uri = $self -> {protocol } . ' ://' ;
117124 $uri .= $encoded_username . ' :' . $encoded_password . ' @' if ($encoded_username ne ' ' && $encoded_password ne ' ' );
118- $uri .= $self -> { hostname } if ($self -> { hostname } ne ' ' );
119- $uri .= ' :' . $self -> { port } if ($self -> { port } ne ' ' && $self -> {protocol } ne ' mongodb+srv' );
125+ $uri .= $host if ($host ne ' ' );
126+ $uri .= ' :' . $port if ($port ne ' ' && $host !~ / : \d + $ / && $self -> {protocol } ne ' mongodb+srv' );
120127
121- $self -> {output }-> output_add(long_msg => ' Connection URI: ' . $uri , debug => 1);
128+ my @params = ();
129+ push @params , ' authSource=' . $encoder -> encode($self -> {auth_source }) if ($self -> {auth_source } ne ' ' );
130+ push @params , ' replicaSet=' . $encoder -> encode($self -> {replica_set }) if ($self -> {replica_set } ne ' ' );
131+ # MongoDB URI parser requires a '/' between the host list and the
132+ # query string, even when no default database is specified.
133+ $uri .= ' /?' . join (' &' , @params ) if (scalar (@params ) > 0);
134+
135+ return $uri ;
136+ }
137+
138+ sub redact_uri {
139+ my ($self , $uri ) = @_ ;
140+
141+ # Hide the password between ':' and '@' in 'scheme://user:password@host...'
142+ # so that --debug never leaks credentials.
143+ $uri =~ s { (://[^:/@]+):[^@]+@} { $1 :***\@ } ;
144+ return $uri ;
145+ }
146+
147+ sub build_mongodb_options {
148+ my ($self , %options ) = @_ ;
122149
123150 my %mongodb_options = ();
124151 if ($self -> {no_ssl } == 0) {
125152 $mongodb_options {ssl } = (defined ($self -> {ssl_opts }) && scalar (keys %{$self -> {ssl_opts }}) > 0) ? $self -> {ssl_opts } : 1;
126153 }
127154
155+ return %mongodb_options ;
156+ }
157+
158+ sub connect {
159+ my ($self , %options ) = @_ ;
160+
161+ my $uri = $self -> build_uri();
162+ $self -> {output }-> output_add(long_msg => ' Connection URI: ' . $self -> redact_uri($uri ), debug => 1);
163+
164+ my %mongodb_options = $self -> build_mongodb_options();
128165 $self -> {client } = MongoDB::MongoClient-> new(host => $uri , %mongodb_options );
129166 $self -> {client }-> connect ();
130167
@@ -161,6 +198,20 @@ sub run_command {
161198 return $db -> run_command($options {command });
162199}
163200
201+ sub run_command_on_host {
202+ my ($self , %options ) = @_ ;
203+
204+ my $uri = $self -> build_uri(host => $options {host }, port => $options {port });
205+ $self -> {output }-> output_add(long_msg => ' Connection URI: ' . $self -> redact_uri($uri ), debug => 1);
206+
207+ my %mongodb_options = $self -> build_mongodb_options();
208+ my $client = MongoDB::MongoClient-> new(host => $uri , %mongodb_options );
209+ $client -> connect ();
210+
211+ my $db = $client -> get_database($options {database });
212+ return $db -> run_command($options {command });
213+ }
214+
164215sub list_databases {
165216 my ($self , %options ) = @_ ;
166217
@@ -221,6 +272,14 @@ MongoDB username.
221272
222273MongoDB password.
223274
275+ =item B<--auth-source >
276+
277+ Authentication database (authSource connection string option).
278+
279+ =item B<--replica-set >
280+
281+ Replica set name (replicaSet connection string option).
282+
224283=item B<--timeout >
225284
226285Set timeout in seconds (default: 10).
0 commit comments