Skip to content

Commit 565c3df

Browse files
Merge pull request #141 from Percona-Lab/1.0.2
1.0.2 Release
2 parents d84c041 + afa63fe commit 565c3df

File tree

18 files changed

+187
-87
lines changed

18 files changed

+187
-87
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
FROM centos:centos7
22
MAINTAINER Tim Vaillancourt <tim.vaillancourt@percona.com>
33
RUN yum install -y https://www.percona.com/redir/downloads/percona-release/redhat/latest/percona-release-0.1-4.noarch.rpm epel-release && \
4-
yum install -y Percona-Server-MongoDB-32-tools zbackup && yum clean all && \
5-
curl -Lo /usr/bin/mongodb-consistent-backup https://github.com/Percona-Lab/mongodb_consistent_backup/releases/download/1.0.1/mongodb-consistent-backup.el7.centos.x86_64 && \
4+
yum install -y Percona-Server-MongoDB-34-tools zbackup && yum clean all && \
5+
curl -Lo /usr/bin/mongodb-consistent-backup https://github.com/Percona-Lab/mongodb_consistent_backup/releases/download/1.0.2/mongodb-consistent-backup.el7.centos.x86_64 && \
66
chmod +x /usr/bin/mongodb-consistent-backup
77
ENTRYPOINT ["mongodb-consistent-backup"]
88
CMD ["--help"]

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ Links
222222

223223
- https://www.percona.com/blog/2016/07/25/mongodb-consistent-backups/
224224
- https://www.percona.com/blog/2017/01/09/mongodb-pit-backups-part-2/
225+
- https://www.percona.com/blog/2017/05/10/percona-lab-mongodb_consistent_backup-1-0-release-explained/
225226
- https://docs.mongodb.com/manual/reference/program/mongodump/
226227
- https://docs.mongodb.com/manual/reference/program/mongorestore/
227228
- http://zbackup.org

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.1
1+
1.0.2

conf/mongodb-consistent-backup.example.conf

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ production:
1010
name: default
1111
location: /var/lib/mongodb-consistent-backup
1212
# mongodump:
13-
# binary: [path] (default: /usr/bin/mongodump)
14-
# compression: [none|gzip] (default: true - if supported)
15-
# threads: [1-16] (default: auto-generated - shards/cpu)
13+
# binary: [path] (default: /usr/bin/mongodump)
14+
# compression: [auto|none|gzip] (default: auto - enable gzip if supported)
15+
# threads: [1-16] (default: auto-generated - shards/cpu)
1616
#replication:
1717
# max_lag_secs: [1+] (default: 5)
1818
# min_priority: [0-999] (default: 0)
@@ -23,14 +23,14 @@ production:
2323
# wait_secs: [1+] (default: 300)
2424
# ping_secs: [1+] (default: 3)
2525
#oplog:
26-
# compression: [none|gzip] (default: true - if used by backup stage)
26+
# compression: [none|gzip] (default: gzip - if gzip is used by backup stage)
2727
# resolver_threads: [1+] (default: 2 per CPU)
2828
# tailer:
2929
# status_interval: 30
3030
archive:
3131
method: tar
3232
# tar:
33-
# compression: [none|gzip] (default: gzip, none if backup is compressed)
33+
# compression: [none|gzip] (default: gzip - none if backup is already compressed)
3434
# threads: [1+] (default: 1 per CPU)
3535
# zbackup:
3636
# binary: [path] (default: /usr/bin/zbackup)

mongodb_consistent_backup/Backup/Mongodump/Mongodump.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, manager, config, timer, base_dir, backup_dir, replsets, shard
2626
self.replsets = replsets
2727
self.sharding = sharding
2828

29-
self.compression_supported = ['none', 'gzip']
29+
self.compression_supported = ['auto', 'none', 'gzip']
3030
self.version = 'unknown'
3131
self.threads_max = 16
3232
self.config_replset = False
@@ -40,11 +40,15 @@ def __init__(self, manager, config, timer, base_dir, backup_dir, replsets, shard
4040
with hide('running', 'warnings'), settings(warn_only=True):
4141
self.version = local("%s --version|awk 'NR >1 {exit}; /version/{print $NF}'" % self.binary, capture=True)
4242

43+
self.choose_compression()
44+
45+
def choose_compression(self):
4346
if self.can_gzip():
44-
if self.compression() == 'none':
47+
if self.compression() == 'auto':
48+
logging.info("Mongodump binary supports gzip compression, auto-enabling gzip compression")
4549
self.compression('gzip')
4650
elif self.compression() == 'gzip':
47-
logging.warning("mongodump gzip compression requested on binary that does not support gzip!")
51+
raise OperationError("mongodump gzip compression requested on binary that does not support gzip!")
4852

4953
def can_gzip(self):
5054
if os.path.isfile(self.binary) and os.access(self.binary, os.X_OK):
@@ -121,8 +125,9 @@ def run(self):
121125
self.authdb,
122126
self.backup_dir,
123127
self.binary,
128+
self.version,
124129
self.threads(),
125-
self.do_gzip,
130+
self.do_gzip(),
126131
self.verbose
127132
)
128133
self.dump_threads.append(thread)
@@ -152,8 +157,9 @@ def run(self):
152157
self.authdb,
153158
self.backup_dir,
154159
self.binary,
160+
self.version,
155161
self.threads(),
156-
self.do_gzip,
162+
self.do_gzip(),
157163
self.verbose
158164
)]
159165
self.dump_threads[0].start()

mongodb_consistent_backup/Backup/Mongodump/MongodumpThread.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,28 @@
1414

1515
# noinspection PyStringFormat
1616
class MongodumpThread(Process):
17-
def __init__(self, state, uri, timer, user, password, authdb, base_dir, binary,
17+
def __init__(self, state, uri, timer, user, password, authdb, base_dir, binary, version,
1818
threads=0, dump_gzip=False, verbose=False):
1919
Process.__init__(self)
20-
self.state = state
21-
self.uri = uri
22-
self.timer = timer
23-
self.user = user
24-
self.password = password
25-
self.authdb = authdb
26-
self.base_dir = base_dir
27-
self.binary = binary
28-
self.threads = threads
29-
self.dump_gzip = dump_gzip
30-
self.verbose = verbose
31-
32-
self.timer_name = "%s-%s" % (self.__class__.__name__, self.uri.replset)
33-
self.exit_code = 1
34-
self._command = None
20+
self.state = state
21+
self.uri = uri
22+
self.timer = timer
23+
self.user = user
24+
self.password = password
25+
self.authdb = authdb
26+
self.base_dir = base_dir
27+
self.binary = binary
28+
self.version = version
29+
self.threads = threads
30+
self.dump_gzip = dump_gzip
31+
self.verbose = verbose
32+
33+
self.timer_name = "%s-%s" % (self.__class__.__name__, self.uri.replset)
34+
self.exit_code = 1
35+
self._command = None
36+
self.do_stdin_passwd = False
37+
self.stdin_passwd_sent = False
38+
3539
self.backup_dir = os.path.join(self.base_dir, self.uri.replset)
3640
self.dump_dir = os.path.join(self.backup_dir, "dump")
3741
self.oplog_file = os.path.join(self.dump_dir, "oplog.bson")
@@ -60,6 +64,18 @@ def parse_mongodump_line(self, line):
6064
except:
6165
return None
6266

67+
def is_password_prompt(self, line):
68+
if self.do_stdin_passwd and ("Enter Password:" in line or "reading password from standard input" in line):
69+
return True
70+
return False
71+
72+
def handle_password_prompt(self):
73+
if self.do_stdin_passwd and not self.stdin_passwd_sent:
74+
logging.debug("Received password prompt from mongodump, writing password to stdin")
75+
self._process.stdin.write(self.password + "\n")
76+
self._process.stdin.flush()
77+
self.stdin_passwd_sent = True
78+
6379
def wait(self):
6480
try:
6581
while self._process.stderr:
@@ -68,7 +84,11 @@ def wait(self):
6884
for fd in poll[0]:
6985
read = self._process.stderr.readline()
7086
line = self.parse_mongodump_line(read)
71-
if line:
87+
if not line:
88+
continue
89+
elif self.is_password_prompt(read):
90+
self.handle_password_prompt()
91+
else:
7292
logging.info(line)
7393
if self._process.poll() != None:
7494
break
@@ -85,11 +105,19 @@ def mongodump_cmd(self):
85105
mongodump_flags.extend(["--numParallelCollections="+str(self.threads)])
86106
if self.dump_gzip:
87107
mongodump_flags.extend(["--gzip"])
108+
if tuple("3.4.0".split(".")) <= tuple(self.version.split(".")):
109+
mongodump_flags.extend(["--readPreference=secondary"])
88110
if self.authdb and self.authdb != "admin":
89111
logging.debug("Using database %s for authentication" % self.authdb)
90112
mongodump_flags.extend(["--authenticationDatabase", self.authdb])
91113
if self.user and self.password:
92-
mongodump_flags.extend(["-u", self.user, "-p", self.password])
114+
# >= 3.0.2 supports password input via stdin to mask from ps
115+
if tuple("3.0.2".split(".")) <= tuple(self.version.split(".")):
116+
mongodump_flags.extend(["-u", self.user, "-p", '""'])
117+
self.do_stdin_passwd = True
118+
else:
119+
logging.warning("Mongodump is too old to set password securely! Upgrade to mongodump >= 3.2.0 to resolve this")
120+
mongodump_flags.extend(["-u", self.user, "-p", self.password])
93121
mongodump_cmd.extend(mongodump_flags)
94122
return mongodump_cmd
95123

@@ -106,7 +134,7 @@ def run(self):
106134
rmtree(self.dump_dir)
107135
os.makedirs(self.dump_dir)
108136
logging.debug("Running mongodump cmd: %s" % mongodump_cmd)
109-
self._process = Popen(mongodump_cmd, stderr=PIPE)
137+
self._process = Popen(mongodump_cmd, stdin=PIPE, stderr=PIPE)
110138
self.wait()
111139
self.exit_code = self._process.returncode
112140
if self.exit_code > 0:

mongodb_consistent_backup/Backup/Mongodump/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ def config(parser):
55
parser.add_argument("--backup.mongodump.binary", dest="backup.mongodump.binary",
66
help="Path to 'mongodump' binary (default: /usr/bin/mongodump)", default='/usr/bin/mongodump')
77
parser.add_argument("--backup.mongodump.compression", dest="backup.mongodump.compression",
8-
help="Compression method to use on backup (default: gzip)", default="gzip",
9-
choices=["none", "gzip"])
8+
help="Compression method to use on backup (default: auto)", default="auto",
9+
choices=["auto", "none", "gzip"])
1010
parser.add_argument("--backup.mongodump.threads", dest="backup.mongodump.threads",
1111
help="Number of threads to use for each mongodump process. There is 1 x mongodump per shard, be careful! (default: shards/CPUs)",
1212
default=0, type=int)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
from Backup import Backup
22

33

4+
def config(parser):
5+
parser.add_argument("-n", "--backup.name", dest="backup.name", help="Name of the backup set (required)", type=str)
6+
parser.add_argument("-l", "--backup.location", dest="backup.location", help="Base path to store the backup data (required)", type=str)
7+
parser.add_argument("-m", "--backup.method", dest="backup.method", help="Method to be used for backup (default: mongodump)", default='mongodump', choices=['mongodump'])
8+
return parser

mongodb_consistent_backup/Common/Config.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,9 @@ def makeParser(self):
5151
parser.add_argument("-v", "--verbose", dest="verbose", help="Verbose output", default=False, action="store_true")
5252
parser.add_argument("-H", "--host", dest="host", help="MongoDB Hostname, IP address or '<replset>/<host:port>,<host:port>,..' URI (default: localhost)", default="localhost", type=str)
5353
parser.add_argument("-P", "--port", dest="port", help="MongoDB Port (default: 27017)", default=27017, type=int)
54-
parser.add_argument("-u", "--user", dest="user", help="MongoDB Authentication Username (for optional auth)", type=str)
54+
parser.add_argument("-u", "--user", "--username", dest="username", help="MongoDB Authentication Username (for optional auth)", type=str)
5555
parser.add_argument("-p", "--password", dest="password", help="MongoDB Authentication Password (for optional auth)", type=str)
5656
parser.add_argument("-a", "--authdb", dest="authdb", help="MongoDB Auth Database (for optional auth - default: admin)", default='admin', type=str)
57-
parser.add_argument("-n", "--backup.name", dest="backup.name", help="Name of the backup set (required)", type=str)
58-
parser.add_argument("-l", "--backup.location", dest="backup.location", help="Base path to store the backup data (required)", type=str)
59-
parser.add_argument("-m", "--backup.method", dest="backup.method", help="Method to be used for backup (default: mongodump)", default='mongodump', choices=['mongodump'])
6057
parser.add_argument("-L", "--log-dir", dest="log_dir", help="Path to write log files to (default: disabled)", default='', type=str)
6158
parser.add_argument("--lock-file", dest="lock_file", help="Location of lock file (default: /tmp/mongodb-consistent-backup.lock)", default='/tmp/mongodb-consistent-backup.lock', type=str)
6259
parser.add_argument("--sharding.balancer.wait_secs", dest="sharding.balancer.wait_secs", help="Maximum time to wait for balancer to stop, in seconds (default: 300)", default=300, type=int)

mongodb_consistent_backup/Common/DB.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def connect(self):
4545
conn['admin'].command({"ping":1})
4646
except (ConnectionFailure, OperationFailure, ServerSelectionTimeoutError), e:
4747
logging.error("Unable to connect to %s! Error: %s" % (self.uri, e))
48-
raise OperationError(e)
48+
raise DBConnectionError(e)
4949
if conn is not None:
5050
self._conn = conn
5151
return self._conn

0 commit comments

Comments
 (0)