Permissions Issue When Upgrading MongoDB with Custom dbPath or logPath

mongodb permissions issue

mongodb permissions issueIn Linux distributions, installing MongoDB for the first time using rpm/dpkg will create a conf file, dbPath, logPath and the init scripts on default paths. This includes the creation of a mongod user/group and provides mongod permissions to both the default dbPath (/var/lib/mongo) and logPath (/var/log/mongodb/mongod.log). Then you edit the settings in the config file at /etc/mongod.conf for custom settings like dbPath in different locations and start mongod service as you need.

But this is a little different when you are doing an upgrade or changing between Percona Server for MongoDB (PSMDB) and upstream MongoDB as they include the removal of the existing package and install of the new version. This article explains the problem in some cases with restored user mongod permissions when you are using custom dbPath or logPath locations when reinstalling the packages, and how to overcome it.

Behavior When Upgrading MongoDB Package

We know that uninstalling the MongoDB package would remove the related packages. But especially when you are uninstalling PSMDB, the user mongod is also dropped along with the packages which cause the existing directories to lose permissions and it is left with the uid/gid of the dropped mongod user/group as shown below.

Before Uninstall:

[root@app ~]# ls -l /var/lib/mongo/
total 16092
-rw-------. 1 mongod mongod    16384 Jan  1 13:46 collection-0-1422095431970586989.wt
-rw-------. 1 mongod mongod    32768 Jan  1 13:46 collection-0-3711456140137791318.wt
-rw-------. 1 mongod mongod    16384 Jan  1 13:46 collection-0--6887184941376867266.wt
-rw-------. 1 mongod mongod    16384 Jan  1 13:46 collection-10--2978246447481368990.wt
-rw-------. 1 mongod mongod     4096 Jan  1 13:46 collection-11-1422095431970586989.wt
...
...
[root@app ~]# systemctl stop mongod.service
[root@app ~]#

Now remove the MongoDB Package:

[root@app ~]# yum remove percona-server-mongodb*
Loaded plugins: fastestmirror
Resolving Dependencies
--> Running transaction check
---> Package percona-server-mongodb.x86_64 0:4.0.13-7.el7 will be erased
---> Package percona-server-mongodb-mongos.x86_64 0:4.0.13-7.el7 will be erased
---> Package percona-server-mongodb-server.x86_64 0:4.0.13-7.el7 will be erased
…
…

After removing the packages, check the user permissions for the mongodb files. They are now assigned with 996:993 which was uid:gid of the dropped mongod user/group:

[root@app ~]# ls -ld /var/log/mongo/
drwxr-x---. 2 999 997 4096 Jan  1 13:57 /var/log/mongo/
[root@app ~]# ls -ltrh /var/lib/mongo/
total 16M
-rw-------. 1 999 997   21 Jul  6 23:12 WiredTiger.lock
-rw-------. 1 999 997   45 Jul  6 23:12 WiredTiger
-rw-------. 1 999 997  114 Jul  6 23:12 storage.bson
-rw-------. 1 999 997  16K Sep 20 12:44 index-9--2978246447481368990.wt
-rw-------. 1 999 997  16K Sep 20 12:44 index-5--2978246447481368990.wt
-rw-------. 1 999 997  16K Sep 20 12:44 index-3--2978246447481368990.wt
-rw-------. 1 999 997  16K Sep 20 12:44 index-15--2978246447481368990.wt
...
...

And when you are reinstalling the PSMDB or upstream MongoDB packages, it would install the packages and create the default directories and mongod user again if not available:

[root@app ~]# percona-release enable psmdb-42 release
* Enabling the Percona Server for MongoDB 4.2 repository
<*> All done!
[root@app ~]# 
[root@app ~]# yum install percona-server-mongodb
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: repos-va.psychz.net
 * epel: iad.mirror.rackspace.com
 * extras: repos-va.psychz.net
 * updates: repos-va.psychz.net
percona-release-noarch 
...
...

Now check the permissions of the db files on default dbpath:

[root@app ~]# ls -lad /var/lib/mongo/ 
drwxr-x---. 4 mongod mongod 4096 Dec 20 14:53 /var/lib/mongo/

Default Behavior of MongoDB Installation

If we look into the source code, the installation of the MongoDB package through rpm or through yum/apt-get repository creates the mongod user/group as system user/group as mentioned with SYS_UID_MIN/SYS_UID_MAX and SYS_GID_MIN/SYS_GID_MAX variables (for CentOS, the variables could be found in /etc/login.defs file). The MongoDB code related to it is shown below:

if ! /usr/bin/id -g mongod &>/dev/null; then
/usr/sbin/groupadd -r mongod
fi
if ! /usr/bin/id mongod &>/dev/null; then
/usr/sbin/useradd -M -r -g mongod -d /var/lib/mongo -s /bin/false -c mongod mongod > /dev/null 2>&1
fi

After that, the MongoDB-related directories and files are created and given with the mongod user permissions, as mentioned in the below code snippet, to the default ones. This applies to both PSMDB and upstream MongoDB installations.

Upstream MongoDB Code:

https://github.com/mongodb/mongo/blob/master/rpm/mongodb-org.spec

mkdir -p $RPM_BUILD_ROOT/var/lib/mongo
mkdir -p $RPM_BUILD_ROOT/var/log/mongodb
mkdir -p $RPM_BUILD_ROOT/var/run/mongodb
touch $RPM_BUILD_ROOT/var/log/mongodb/mongod.log

%attr(0755,mongod,mongod) %dir /var/lib/mongo
%attr(0755,mongod,mongod) %dir /var/log/mongodb
%attr(0755,mongod,mongod) %dir /var/run/mongodb

PSMDB Code:

https://github.com/percona/percona-server-mongodb/blob/master/percona-packaging/redhat/percona-server-mongodb.spec.template

install -m 750 -d %{buildroot}/var/log/mongo
touch %{buildroot}/var/log/mongo/mongod.log
install -m 750 -d %{buildroot}/%{mongo_home}

%attr(0750,mongod,mongod) %dir %{mongo_home}
%attr(0750,mongod,mongod) %dir /var/log/mongo
%attr(0640,mongod,mongod) %ghost /var/log/mongo/mongod.log

Issue Occurs When Using Custom db/log file Paths:

When you are using custom dbPath or logPath files after dropping the existing PSMDB package, the mongod user is dropped as mentioned above. So after the uninstall, and before reinstalling the MongoDB package again, there are some rare cases listed below that can cause permission issues to MongoDB files:

  1. The mongod user is created manually as ordinary user (not using -r option with useradd command which creates system user).
    • drop mongodb packages
    • create mongod user again as ordinary user
    • install mongodb packages
  1. Creating some other system users before installing the MongoDB package. i.e. the newly-created system user might use the same uid/gid of the previously dropped mongod user. This will cause the new mongod user to have different uid/gid while installing the packages.
    • drop mongodb packages
    • create some other system users (which overwrites the pid/gid of dropped mongod user while removing MongoDB package) 
    • install mongodb package

Also, the third scenario is when you have created a mongod user manually as an ordinary user even before installing MongoDB for the first time, which might cause the said issue with the permission for the custom db/log files.

An Example of the Issue

See the example below for the same. The custom dbPath is /data/mongodb:

[root@app 7]# mkdir /data/mongodb
[root@app 7]# groupadd -r mongod
[root@app 7]# useradd -M -r -g mongod -d /var/lib/mongo -s /bin/false -c mongod mongod > /dev/null 2>&1
[root@app 7]# chown -R mongod.mongod /data/mongodb
[root@app 7]#
[root@app 7]# ls -ld /data/mongodb/
drwxr-xr-x. 2 mongod mongod 4096 Jan  1 14:44 /data/mongodb/

Install PSMDB 4.0 for the first time and check the directory permission again:

[root@app 7]# yum install percona-server-mongodb 
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.fibergrid.in
 * epel: sg.fedora.ipserverone.com
.....
.....
Complete!
[root@app 7]# ls -lad /var/lib/mongo/ 
drwxr-x---. 4 mongod mongod 4096 Dec 20 14:53 /var/lib/mongo
[root@app 7]# 
[root@app 7]# ls -ld /data/mongodb
drwxr-xr-x. 2 mongod mongod 4096 Jan 1 14:44 /data/mongodb/
[root@app 7]# 
[root@app 7]# grep mongo /etc/passwd
mongod:x:999:997:mongod:/var/lib/mongo:/bin/false
[root@app 7]#

Edit the conf file with custom dbPath and start mongod service:

[root@app 7]# vi /etc/mongod.conf 
[root@app 7]# 
[root@app 7]# grep dbPath /etc/mongod.conf 
dbPath: /data/mongodb
[root@app 7]# service mongod start
Redirecting to /bin/systemctl start mongod.service
[root@app 7]# service mongod stop
Redirecting to /bin/systemctl stop mongod.service

Now remove the MongoDB Package:

[root@app 7]# yum remove percona-server-mongodb*
Loaded plugins: fastestmirror
Resolving Dependencies
--> Running transaction check
---> Package percona-server-mongodb.x86_64 0:4.0.13-7.el7 will be erased
---> Package percona-server-mongodb-mongos.x86_64 0:4.0.13-7.el7 will be erased
---> Package percona-server-mongodb-server.x86_64 0:4.0.13-7.el7 will be erased
---> Package percona-server-mongodb-shell.x86_64 0:4.0.13-7.el7 will be erased
....
....
Complete!

Then check the permission for the data directory and as expected, they look like below – 999:997 which was uid/gid of dropped mongod user/group as part of “yum remove “.

[root@app 7]# ls -ld /data/mongodb/
drwxr-xr-x. 4 999 997 4096 Jan  1 15:13 /data/mongodb/
[root@app 7]#

As we have seen in the scenarios above and as per scenario 2, now create a system user/group called testusr as follows and you will be surprised to see the permission of /data/mongodb. This is because the user was created with the same uid/gid of dropped mongod user:

[root@app 7]# useradd -M -r testusr
[root@app 7]# grep test /etc/passwd
testusr:x:999:997::/home/testusr:/bin/bash
[root@app 7]# ls -ld /data/mongodb/
drwxr-xr-x. 4 testusr testusr 4096 Jan  1 15:13 /data/mongodb/

Upgrade to PSMDB 4.2 package now:

[root@app 7]# percona-release enable psmdb-42 release
* Enabling the Percona Server for MongoDB 4.2 repository
<*> All done!
[root@app 7]#
[root@app 7]# yum install percona-server-mongodb
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: repos-va.psychz.net
 * epel: iad.mirror.rackspace.com
 * extras: repos-va.psychz.net
 * updates: repos-va.psychz.net
percona-release-noarch                             | 2.9 kB  00:00:00
percona-release-x86_64                             | 2.9 kB  00:00:00
psmdb-42-release-noarch                            | 2.9 kB  00:00:00
psmdb-42-release-x86_64                            | 2.9 kB  00:00:00
(1/2): psmdb-42-release-noarch/7/primary_db        | 1.1 kB  00:00:00
(2/2): psmdb-42-release-x86_64/7/primary_db        |  16 kB  00:00:00
Resolving Dependencies
--> Running transaction check
---> Package percona-server-mongodb.x86_64 0:4.2.2-3.el7 will be installed
--> Processing Dependency: percona-server-mongodb-tools = 4.2.2-3.el7 for package: percona-server-mongodb-4.2.2-3.el7.x86_64
....
....
....
Complete!

Check the permission for the custom data directory path (/data/mongodb) and to the default path(/var/lib/mongo). We notice that the mongod permission for the custom path /data/mongodb was not restored on its own. Also the /etc/mongod.conf is moved to /etc/mongod.conf.rpmsave while installing the PSMDB package, and a new file /etc/mongod.conf is created from the package installation. So you need to edit the conf file as needed or restore the old conf file:

[root@app 7]# ls -ld /data/mongodb/
drwxr-xr-x. 4 testusr testusr 4096 Jan  1 15:13 /data/mongodb/
[root@app 7]# ls /etc/mongod*
/etc/mongod.conf /etc/mongod.conf.rpmsave
[root@app 7]# vi /etc/mongod.conf

The following error will be received when starting with the lost permission:

[root@app 7]# grep dbPath /etc/mongod.conf
  dbPath: /data/mongodb
[root@app 7]# systemctl start mongod
Job for mongod.service failed because the control process exited with error code. See "systemctl status mongod.service" and "journalctl -xe" for details.
[root@app 7]# tail /var/log/mongo/mongod.log 
2020-01-01T15:23:31.929+0000 I  CONTROL  [initandlisten] build environment:
2020-01-01T15:23:31.929+0000 I  CONTROL  [initandlisten]     distarch: x86_64
2020-01-01T15:23:31.929+0000 I  CONTROL  [initandlisten]     target_arch: x86_64
2020-01-01T15:23:31.929+0000 I  CONTROL  [initandlisten] options: { config: "/etc/mongod.conf", net: { bindIp: "127.0.0.1", port: 27017 }, processManagement: { fork: true, pidFilePath: "/var/run/mongod.pid" }, storage: { dbPath: "/data/mongodb", journal: { enabled: true } }, systemLog: { destination: "file", logAppend: true, path: "/var/log/mongo/mongod.log" } }
2020-01-01T15:23:31.930+0000 I  STORAGE  [initandlisten] exception in initAndListen: IllegalOperation: Attempted to create a lock file on a read-only directory: /data/mongodb, terminating
2020-01-01T15:23:31.930+0000 I  NETWORK  [initandlisten] shutdown: going to close listening sockets...
2020-01-01T15:23:31.930+0000 I  NETWORK  [initandlisten] removing socket file: /tmp/mongodb-27017.sock
2020-01-01T15:23:31.930+0000 I  -        [initandlisten] Stopping further Flow Control ticket acquisitions.
2020-01-01T15:23:31.930+0000 I  CONTROL  [initandlisten] now exiting
2020-01-01T15:23:31.930+0000 I  CONTROL  [initandlisten] shutting down with code:100

Solution:

You have to manually provide mongod user permission and the old setting in config file as before to start with the new version of MongoDB package.

[root@app 7]# chown -R mongod.mongod /data/mongodb
[root@app 7]# service mongod start

Update the Package Instead of Remove & Install

The other good news is you don’t need to follow these steps if you are updating the package instead of removing and installing the next version. This path doesn’t remove the mongod user and also doesn’t move the /etc/mongod.conf to /etc/mongodb.conf.rpmsave. So you can use this method to upgrade.

[root@app 7]# percona-release enable psmdb-42 release
* Enabling the Percona Server for MongoDB 4.2 repository
<*> All done!
[root@app 7]# yum update percona-server-mongodb
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: repos-va.psychz.net
 * epel: iad.mirror.rackspace.com
 * extras: repos-va.psychz.net
 * updates: repos-va.psychz.net
psmdb-42-release-noarch                   | 2.9 kB  00:00:00     
psmdb-42-release-x86_64                   | 2.9 kB  00:00:00     
Resolving Dependencies
--> Running transaction check
---> Package percona-server-mongodb.x86_64 0:4.0.13-7.el7 will be updated
---> Package percona-server-mongodb.x86_64 0:4.2.2-3.el7 will be an update
--> Processing Dependency: percona-server-mongodb-tools = 4.2.2-3.el7 for package: percona-server-mongodb-4.2.2-3.el7.x86_64
--> Processing Dependency: percona-server-mongodb-mongos = 4.2.2-3.el7 for package: percona-server-mongodb-4.2.2-3.el7.x86_64
--> Processing Dependency: percona-server-mongodb-shell = 4.2.2-3.el7 for package: percona-server-mongodb-4.2.2-3.el7.x86_64
--> Processing Dependency: percona-server-mongodb-server = 4.2.2-3.el7 for package: percona-server-mongodb-4.2.2-3.el7.x86_64
--> Running transaction check
---> Package percona-server-mongodb-mongos.x86_64 0:4.0.13-7.el7 will be updated
---> Package percona-server-mongodb-mongos.x86_64 0:4.2.2-3.el7 will be an update
---> Package percona-server-mongodb-server.x86_64 0:4.0.13-7.el7 will be updated
---> Package percona-server-mongodb-server.x86_64 0:4.2.2-3.el7 will be an update
---> Package percona-server-mongodb-shell.x86_64 0:4.0.13-7.el7 will be updated
..
..
..
Complete!

While writing this blog post, there were a lot of discussions internally and per them, I have raised this JIRA https://jira.percona.com/browse/PSMDB-546  to update the documentation and reflect this update path instead of removing and installing the newer version.

CONCLUSION

When you are doing upgrade/downgrade, check the permissions of the data directory and the log files before starting the MongoDB service. If needed, provide the permissions of mongod user to the db files to start the service without issue. Hope this helps you if you are facing such issues.


by Vinodh Krishnaswamy via Percona Database Performance Blog

Comments