testcontainers-java icon indicating copy to clipboard operation
testcontainers-java copied to clipboard

Permissions error with config mounted into MySQL container

Open ezraroi opened this issue 7 years ago • 16 comments

11:42:05.293 [Test worker] ERROR 🐳 [mysql:5.7.22] - Container log output (if any) will follow:
11:42:05.304 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: 
11:42:05.305 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: ERROR: mysqld failed while attempting to check config
11:42:05.305 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: command was: "mysqld --verbose --help"
11:42:05.305 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: 
11:42:05.306 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 13 - Permission denied)
11:42:05.306 [tc-okhttp-stream-474827747] INFO 🐳 [mysql:5.7.22] - STDERR: mysqld: [ERROR] Fatal error in defaults handling. Program aborted!

We see this in the log (look on the null): Cmd: com.github.dockerjava.core.command.CopyArchiveToContainerCmdImpl@2c8c6bb[cp ,<null>, ,6ca1ea3ce4b2582536fac69ceeb991670930b1ac65a6b2206c1ab88f3c990b65,:,/etc/mysql/] 11:41:45.064 [Test worker] INFO 🐳 [mysql:5.7.22] - Starting container with ID: 6ca1ea3ce4b2582536fac69ceeb991670930b1ac65a6b2206c1ab88f3c990b65

If we override the MySQLContainer class and just rmove this line from the configure function: optionallyMapResourceParameterAsVolume(MY_CNF_CONFIG_OVERRIDE_PARAM_NAME, "/etc/mysql/conf.d", "mysql-default-conf");

Everything is working. Looks like it is copying invalid file to the container

ezraroi avatar Oct 14 '18 08:10 ezraroi

Hi @ezraroi, in which environment are you running? OS, Docker version?

kiview avatar Oct 15 '18 08:10 kiview

OS is Ubunto 16.04 and Docker version 17.03.2-ce, build f5ec1e2

ezraroi avatar Oct 15 '18 08:10 ezraroi

I am experiencing this same issue, also on Ubuntu 16.04 but on docker version 18.06.1-ce, build e68fc7a

bo0tzz avatar Oct 24 '18 16:10 bo0tzz

And this is happening for Testcontainers 1.9.1? Because of the mapping, this is probably some file permissions problem on the host with the config file.

Since we changed most other parts of Testcontainers to favor copying the file into the container instead of mounting or mapping, it would probably solve this problem here as well.

kiview avatar Nov 04 '18 16:11 kiview

Yes, version 1.9.1.

ezraroi avatar Nov 04 '18 19:11 ezraroi

Same Issue here

<testcontainers.version>1.11.2</testcontainers.version>

build	24-May-2019 09:21:02	2019-05-24 09:21:02.234 ERROR 605 --- [           main] ?.7.23] : Log output from the failed container:
build	24-May-2019 09:21:02	ERROR: mysqld failed while attempting to check config
build	24-May-2019 09:21:02	
build	24-May-2019 09:21:02	command was: "mysqld --verbose --help"
build	24-May-2019 09:21:02	
build	24-May-2019 09:21:02	mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 13 - Permission denied)
build	24-May-2019 09:21:02	mysqld: [ERROR] Fatal error in defaults handling. Program aborted!

noqqe avatar May 24 '19 07:05 noqqe

I think @kiview is right - this will be down to permissions on the volume mounted configuration. The right long-term solution has to be to change the container code to copy config files in, rather than volume mount. This has been possible for a while.

A PR to do this would be welcomed if anyone is interested; we can help talk through the solution to clarify anything that is needed.

rnorth avatar May 28 '19 20:05 rnorth

Same problem here Any immediate workaround? I'm on MacOs 10.14.5 and test containers 1.11.2

edit: same thing on 1.11.3

gedl avatar Jun 06 '19 18:06 gedl

I am also facing this problem. A workaround which seems to work OK for me and is in the spirit of "copy config files in, rather than volume mount", is something like:

 mysql = (MySQLContainer) new MySQLContainer().withDatabaseName("some_database")
        .withCopyFileToContainer(MountableFile.forClasspathResource("db/testMySQL.cnf"), "/etc/mysql/conf.d/")
        .withLogConsumer(logConsumer);

I haven't dug into this much further than that but I assume the ultimate PR would do something similar in the MySQLContainer class?

mkornblum avatar Jun 26 '19 21:06 mkornblum

I also experienced this problem and looked into this further.

This was with

<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.testcontainers</groupId>
				<artifactId>testcontainers-bom</artifactId>
				<version>1.12.4</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

In my instance the problem is being caused when the mysql-default-conf resource (my.cnf) inside the mysql-1.12.4.jar is extracted into a temporary folder under /tmp on the host so it can be copied into the mysql container (destination /etc/mysql/conf.d).

The reason it was failing to copy was that the temporary folder was created with no read permission for all users due to my umask setting.

ls -lrat /tmp
...
drwxrwx---.  2 user user     20 Jan 14 22:34 .testcontainers-tmp-15478807415261855030

The solution for me was to change my umask setting so that all users could read the temp folder.

umask 002

@rnorth @kiview - from what I could tell all config files in modules are copied into the container instead of volume mapping (unless I'm missing something)? If you think this is worth documenting somewhere let me know and i'll make the change and submit a PR.

jarebudev avatar Jan 14 '20 23:01 jarebudev

This is actually a bug in the testcontainers implementation in general, checking 1.14.3 and 1.15-rc2, that it almost always never explicitly sets the file permission on resources copied from the host system into a container, but instead relies on the file permissions being correctly set on the host system. This is a major problem, affecting multiple containers when trying to run the test suites.

In this particular case, regarding MySQLContainer, the automatic configuration is done in methods MySQLContainer.configure() and parent class method JdbcDatabaseContainer.optionallyMapResourceParameterAsVolume(), which internally calls MountableFile.forClasspathResource(resourceName) instead of MountableFile.forClasspathResource(resourceName, fileMode).

A sound approach and a proper fix is to explicitly set the file permissions in the implementation class MySQLContainer.configure() that knows about the requirements and change the calls appropriately.

Second, the approach of implicit file permissions in MountableFile.forClassPathResource() should be deprecated in favour of explicitly setting them, i.e. normal use case should be to explicitly set them, unless explicitly file permission are set to be default from the host system.

rottenha avatar Oct 09 '20 11:10 rottenha

I experienced the same issue. @rottenha is correct about the root cause. Just want to give a workaround before the fix. Before starting the container, you can set the MY_CNF_CONFIG_OVERRIDE_PARAM_NAME(which value is TC_MY_CNF) to null in the container parameter, like this:

MySQLContainer mysql = new MySQLContainer("mysql:5.7");
mysql.addParameter("TC_MY_CNF", null);
mysql.start();

soglad avatar Jul 09 '21 07:07 soglad

I am configuring my Test Container with an URL

spring.datasource.url=jdbc:tc:mysql:5.7.28:///scm_ccs?user=root&password=&TC_TMPFS=/testtmpfs-ccs:rw&TC_MY_CNF=mysql.test.cnf&TC_INITSCRIPT=tc_init_mysql.sql

When the container runs it is stopping with mysqld: Can't read dir of '/etc/mysql/conf.d' (Errcode 20 - Not a directory)

2021-10-26 17_52_15-Container instance

When I looked at the source code and one of the work arounds I was wondering if there is not simply a / missing in the file org.testcontainers.containers.MySQLContainer in line 64 at the end of the string "/etc/mysql/conf.d". Shouldn't it be "/etc/mysql/conf.d/"?

mkirchmann avatar Oct 26 '21 16:10 mkirchmann

Any updates on this issue? @mkirchmann were you able to get your container to run from the URL?

ccostin93 avatar Mar 14 '22 16:03 ccostin93

This happens because umask in some Distros is by default 027, which means all permissions get created with no Others Execution

TestContainers by default in POSIX environments uses the default from the OS

777 - 027 = 750

Owner: Read-Write-Execute
Group: Read-Execute
Others: None (Docker volume falls here)

I created a PR to force the file permission to 755, which should fix this issue. Awaiting reviews from Maintainers

As @jarebudev was stating, if you add umask 022 to $HOME/.bashrc, this should workaround the current issue

Snippet:

echo "umask 022" >> $HOME/.bashrc

driverpt avatar Jun 01 '22 10:06 driverpt

Hi, is there any solution to what @mkirchmann asked? I'm having the exact same behaviour. If I change this pathNameInContainer to "/etc/mysql/conf.d**/**", with a slash in the end, it works. The problem is that I don't see a way to do it, easily by just adding the dependency. Is there any solution/workaround to this? I tried @driverpt suggestion, but it didn't changed the erroneous behaviour.

lemano avatar Dec 18 '22 18:12 lemano