I am trying to figure out how to change MySQL configuration before a Travis CI test run. We are using the "sudo:false" directive, I think to use containers...I'm not the best devops person.
But even when I set sudo to true, I can't restart MySQL after I try to add lines to "/etc/mysql/my.cnf".
So,
- cat "some/directory/my.cnf" | sudo tee -a /etc/mysql/my.cnf
- sudo /etc/init.d/mysql restart
gives me: "start: Job failed to start", but I don't even want to use sudo. For PHP config, I can do something like:
- echo "apc.shm_size=256M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
but I can't see anything in my home folder about MySQL.
I also know about:
- mysql -e "SET GLOBAL innodb_buffer_pool_size = 512M;"
but the things I want to set give me:
ERROR 1238 (HY000) at line 1: Variable 'innodb_buffer_pool_size' is a read only variable
So, I'm at a loss on how to accomplish changing MySQL configuration on Travis CI, and every internet search and method I've tried has failed me.
innodb_buffer_pool_size cannot be dynamically changed until MySQL 5.7.5. What version are you using?
Before that version, here are some options:
Modify /etc/my.cnf (or wherever it is located)
Assuming my.cnf has an 'include' at the end, then temporarily add a file to the directory mentioned. It needs 2 lines [mysqld] and innodb_buffer_pool_size=512M; then restart mysqld.
Add --innodb_buffer_pool_size=512M to the launching of mysqld.
Other "VARIABLES" may, or may not, be dynamically settable. Research each one separately.
i present a .travis.yml configuration that allows you to run and restart mysqld without using sudo - the logic is along the lines of:
just out of interest, why can't you use sudo?
obtain the generic linux .tar.gz from https://dev.mysql.com/downloads/mysql/ in before_script using wget - store the .tar.gz within a directory that will be cached - don't do this if the file already exists
unpack the .tar.gz to the cached directory - don't do this if the unpack target already exists
scrub the error log and recreate the .cnf file
now in script, start mysqld for the first time, wait for a bit, check that it's running, then stop it
make any change to the config you want
start mysqld for the second time, wait for a bit, check the config change, then stop it
the proof .travis.yml (mysql 5.6.40 generic linux 64-bit) is here: https://github.com/knyrb/mysql-travisci/blob/master/.travis.yml - here is a (non-working) rough idea of the contents:
before_script:
<..snip..>
- if [ -f 'scripts/mysql_install_db' ]; then ./scripts/mysql_install_db --defaults-file="$TCI_D_MYSQL_ROOT/my.cnf"; fi
script:
<..snip..>
- bin/mysqld --defaults-file="$TCI_D_MYSQL_ROOT/my.cnf" --socket=/tmp/.thesock &
- bin/mysqladmin --defaults-file="$TCI_D_MYSQL_ROOT/my.cnf" --socket=/tmp/.thesock ping
- export TCI_MYSQL_PID_1="`cat $TCI_D_MYSQL_ROOT/mysql.pid`"
- kill -SIGTERM $TCI_MYSQL_PID_1
<..snip..>
after_success:
<..snip..>
after_failure:
<..snip..>
- cat "$TCI_D_MYSQL_ROOT/mysql.err"
discussion left for posterity:
as you've identified, there are certain configuration parameters in mysql that can only be set prior to the server starting viz. anything that is 'dynamic: no' in table 14.13 for mysql 5.6 - i restate the obvious fwiw: the php parameters are dynamically inflicted on the php process via php.ini
(never tested this - don't know if it works - the constraint was 'no sudo' and this method clearly requires sudo) first off, have you tried using the service binary (https://linux.die.net/man/8/service) instead of a direct call to mysql? viz. https://docs.travis-ci.com/user/database-setup/#MySQL-5.7 :
before_install:
- sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('new_password') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
- sudo mysql_upgrade
- sudo service mysql restart
what case(s) are you testing by changing these mysql parameters prior to each test's runtime as distinct from configuring them 'permanently' in the test instance db server?
assuming your mysqld is firing up at container start via services: mysql? could you configure travis to start mysqld specifically in before_install or script and specify the parameters that you want at start time, with mysqld running under the ci framework travis (i think this should allow it to start/stop/restart etc without any sudo use, but i haven't tested it) (see: https://github.com/knyrb/mysql-travisci for a proof of concept)
see: https://docs.travis-ci.com/user/database-setup/#MySQL, which hints the possibility (although with jackrabbit),
no: must run mysqld as root to switch user though you would run mysqld --user=travis (https://dev.mysql.com/doc/refman/5.6/en/server-options.html#option_mysqld_user), or maybe in the cnf file with [mysqld] user=travis directive (https://dev.mysql.com/doc/mysql-security-excerpt/5.6/en/changing-mysql-user.html)
(never tested this but it should work as well) another option might be to have a github project for each specific environment test you want to perform, with mysqld configured to run with its limiting parameters already set: your tests would be per container, rather than with interim restarts (possibly insane, depending on how bad you want it!)
(if your tests are performance related, remember to give the db a/ some warmup queries before you start measuring)
i ask purely out of interest: when it comes to testing different environments and configuration limits, my humble opinion will always favour a 'more is more' approach!
(never tested this either) not sure if you're using a recent enough version of mysql for this option to work, but i see there is an instruction in mysql 8 restart
this might work for you if you can have a mysql stored proc trigger a restart of the database service from a priveleged account calling a stored proc - you would call this stored proc then wait for the server to restart, say with one of the following methods:
a call to sleep did the job in the proof (it won't account for failure - but the ci build fails if any process returns != 0)
if your using a local unix/ domain socket, wait on the file /tmp/mysql.sock (or your equivalent) using any of the methods here: https://superuser.com/questions/878640/unix-script-wait-until-a-file-exists while .. sleep, inotifywait from the inotify tools; or from within python using inotify.adapters.InotifyTree().eventgen() (probably overkill!)
attempt a connection with a generous timeout, mysql -S/tmp/mysql.sock --connect-timeout=# --user=youruser --password
https://stackoverflow.com/a/21189440/4036945 (wait .. sleep using curl to hit up a webservice that in turn connects to the db: maybe your app has a 'status' page? and maybe it waits a while and retries a db connection before it returns to the http client)
https://unix.stackexchange.com/a/5279 (wait .. sleep using netcat, netstat and lsof, but these i think will all require sudo unless you start mysql from within the ci framework, in which netstat from the ci framework should provide the info)
Related
tricky question and I don't know if SO is the good space (maybe AskUbuntu ? or SuperUser ?)
I've set my Lampp on my ubuntu in /opt/lampp/
Problem, when I need to call direct bin as mysqldump, I end up calling the default installed one on my ubuntu, not the one linked to my lampp :
$ mysqldump --user=root test
mysqldump: Got error: 2002: Can't connect
to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
when trying to connect
As you can see, it check for /var/run.
If I want to use the good one, I should specify the path :
$ /opt/lampp/bin/mysqldump --user=root test
-- MySQL dump 10.13 Distrib 5.6.21, for Linux (x86_64)
I could use the full path in my PHP call, but my PHP prod server will then not work.
How can I set the Lampp bin as default to be used by php with exec('mysqldump')?
You really have several choices to do what you want.
You could create a configuration file that depends on your environement (local, dev, preprod, prod ...). This file may declare an array of configurations, one of which is the path of the executable you need. Your php code will know the environment by checking a global variable, for instance $_SERVER, which can be set in your web server's vhost file. I think that's the clean way of doing.
You could hardcode a path for you executable (let's say /home/www/mysqldump) and create a symbolic link with ln -s (if I remember right, or check the man page) between your environment's executable /opt/lampp/bin/mysqldump and /home/www/mysqldump. You have to prepare all your environments that way. I think it's a bit ugly but it's quick.
I am sure there are tons of other solutions.
Setting. I'm running Ubuntu 15.04 on a custom machine with an existing PHP / Apache / Sqlite setup. I recently installed MySql to fiddle around with Laravel a bit. It was working perfectly until I wasn't paying attention and did something incredibly stupid. I intended to export all of the user's privileges to a new database, was in a hurry, and instead clicked the button to dump all users. So, yeah. Complete dumped every user in MySql, including root. Obviously I was unable to log back in with PhpMyAdmin, because no root user. Since this was just a testing install I went ahead and purged MySql and re-installed, thinking it would just go through the install process again. NOPE. I've uninstalled / reinstalled using the terminal, synatpic, and Ubuntu Software Center. In each case the install of MySql client server just breezes through without even asking for a root user. I can't even check status to see if the server is running without getting an unauthorized error. I would really like to get this fixed, but without uninstalling apache2 and php. Any help would be greatly appreciated.
After yet another purge / install cycle I have mysql mostly working again. I can log in as root from the command line, and I am able to log in via PhpMyAdmin, for the most part. Unfortunately, while I seem to still have all of the necessary PhpMyAdmin functionality the page itself throws several iterations of the following error:
Connection for controluser as defined in your configuration failed.
I've researched this error and none of the conditions that are said to cause it exist in my system.
First try this.
mysql -u root -p password
if first method does not work then use following method to reset your MySQL password.
Check your version of the MySQL database.
apt-cache policy mysql-server
Start configuration setting of the MySQL database.
sudo dpkg-reconfigure mysql-server-** . **
"replace ** . ** with your MySQL database version"
It will open a configuration prompt where you will can change password.
If both of the above methods fails then use this method as last resort.
Stop your MySQL database server
sudo /etc/init.d/mysql stop
Start demon process without grant table.
sudo /usr/sbin/mysqld --skip-grant-tables --skip-networking
Start MySQL and flush the privilige.
mysql -u root
FLUSH PRIVILEGES;
Now set the password for the root user.
USE mysql
UPDATE user SET Password = PASSWORD('newpwd')
WHERE Host = 'localhost' AND User = 'root';
I have a project in php, there I connect to the server via ssh and my task is to change the postgresql.conf parameters.
I tried this:
psql -Upgadmin -p 11935 -d postgres -c array_nulls=off
ERROR: syntax error at or near "array_nulls"
LINE 1: array_nulls=off
^
or should I change the settings in postgresql.conf using sed, which command should I use?
Any server setting that you succeed in changing with psql will only last as long as your session. To make the change persist, you have to edit postgresql.conf, either with your favorite text editor (vim, emacs, etc.) or with a utility program (sed, awk, etc.). Everything that follows assumes that you have suitable privileges to edit postgresql.conf.
Your first job is to find it. Different Linux distributions store it in different places. In Ubuntu, it's in
/etc/postgresql/9.4/main
^^^
Note the version number. Different for each version of PostgreSQL, of course. If I wanted to change a setting, I'd do this after putting the file under version control.
$ sudoedit /etc/postgresql/9.4/main/postgresql.conf
[sudo] password for mike:
Then find the setting and change it. Here's what the relevant section of postgresql.conf looks like here.
#------------------------------------------------------------------------------
# VERSION/PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
# - Previous PostgreSQL Versions -
#array_nulls = on
I'd change the setting to
array_nulls = off # array_nulls = on
This kind of change usually requires either a reload or a restart of the PostgreSQL dbms.
I've already taken a look at both of these:
PHP: mount USB device
Error on mount through php "exec"
But, my problem appears to be different.
I have built an extensive library that's used to call Linux CLI tools. It's built around proc_open, it's family and POSIX.
I'm using it to successfully execute all (until I hit this mount/umount bug) CLI tools.
Now, I'm building a RAID setup routine, that involves partprobe, parted - rm, mklabel, mkpart, mdadm - stop, zero-superblock, create, dd, mkfs and ultimately mount/umount.
There are actually two graceful routines, one for assembling the RAID, the other one for disassembly.
As the title says, the problem relies in mount and umount. The other tools and their commands listed above execute successfully.
Environment
Arch Linux - Linux stone 3.11.6-1-ARCH #1 SMP PREEMPT Fri Oct 18 23:22:36 CEST 2013 x86_64 GNU/Linux.
The Arch is running with systemd - might be that is somehow affecting the mounting.
An Apache web server (latest), that runs mod_php (latest). Apache is run as http:http.
http is in wheel group, and wheels are sudoers - %wheel ALL=(ALL) NOPASSWD: ALL.
Please, don't start the webserver being given a full root capabilities discussion - the unit is a NAS, it's running a custom WebOS, and it's meant for intranet only. Even if there are hacking attempts - those will, most probably, break the whole system and that's not healthy for the customer. The NAS is a storage for Mobotix IP cameras, it runs a load of dependent services and the units are already deployed in over 30 objects with no issues. In short, the webserver is not serving a web, but an OS.
Before writing, I added, for a quick test, http explicitly to sudoers - http ALL=(ALL) NOPASSWD: ALL - didn't work.
Problem
The last command run in the RAID assembly process is mount /dev/md/stone\:supershare /mnt/supershare, which returns with an exit code of 0.
Performing a subsequent mount results in:
mount: /dev/md127 is already mounted or /mnt/supershare busy
/dev/md127 is already mounted on /mnt/supershare
with an exit code of 32. So, the array is mounted somewhere.
Performing an umount /dev/md/stone\:supershare afterwards the above mount, returns with an exit code of 0. Performing an subsequent umount results in:
umount: /dev/md/stone:supershare: not mounted
The commands above are auto-run with sudo.
So, it's mounted successfully and unmounted sucessfully, but... I'm logged in as root on TTY0, running lsblk after having performed the mount operation, yet, I do not see the mountpoint:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 55.9G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 1G 0 part [SWAP]
├─sda3 8:3 0 12G 0 part /
└─sda4 8:4 0 16.6G 0 part /home
sdb 8:16 0 931.5G 0 disk
└─sdb1 8:17 0 899M 0 part
└─md127 9:127 0 1.8G 0 raid0
sdc 8:32 0 931.5G 0 disk
└─sdc1 8:33 0 899M 0 part
└─md127 9:127 0 1.8G 0 raid0
Attempting the same mount command from TTY0 mounts it successfully (lsblk displays after).
If I mount it with my CLI tool, then run mount -l and lsblk also with the CLI tool, the mountpoint is visible.
Running immediately both commands from TTY0 as root, do not display the mountpoint.
Rebooting, to reset all mounts (not automounted), then, mounting from TTY0 and running lsblk from TTY0 displays the mountpoint.
Then, running lsblk with CLI tool, displays the mountpoint.
Then, running umount with CLI tool, exit code 0 - unmounted.
Running lsblk with CLI tool again, does not display the mountpoint.
Running lsblk from TTY0, still does display the mountpoint.
It appears that when the mount/umount is run with my CLI tool, it executes the commands privately for the sudo session runner.
umounting after TTY0 has mounted, does unmount it, but again - privately.
Logging in from TTY0 as http and running lsblk after having mounted the RAID from CLI tool, the mountpoint is not displayed. This kind of negates the "executes privately for the sudo session runner".
I've also found a material in IBM's:
The mount command uses the real user ID, not the effective user ID, to determine if the user has appropriate access. System group members can issue device mounts, provided they have write access to the mount point and those mounts specified in the /etc/file systems file. Users with root user authority can issue any mount command.
I hope I've explained good enough and not too confusing, I also hope that you guys will be able to help me catch the issue here.
Update (2013-10-28)
I attempted a test with the CLI tool outside web context, a simple PHP file, that'd I exec with root and a custom user.
In both scenarios, the mounting and unmounting was successful. So, it must be something with Apache executing the commands, though, I don't understand why do other commands work.
Question
What is causing the issue, and how do I overcome it?
In short, the hassle has been resolved.
It was the Apache's corresponding systemd service, that had PrivateTmp=true directive. Apparently, the directive executes the process with a new file system namespace.
This question, while attempting to debug and fix the issue spawned a numerous other posts around the internet.
https://unix.stackexchange.com/questions/97897/sudo-mount-from-webserver-apache-by-mod-php-result-not-visible-by-root
https://bbs.archlinux.org/viewtopic.php?id=172072
https://unix.stackexchange.com/questions/98182/a-process-run-as-root-when-performing-mount-is-mounting-for-self-how-to-ma/98191#98191
Each derived from stuff I've learn in the process.
I started with getting deeper information about mount working on EUID. Soon, I found out that my simple sudo call is actually not executing with EUID 0. That led me to multiple queries on how to do so, that in return spawned command syntax like sudo -i 'su' -c 'mount /dev/sdb1 /mnt/firstone' and other derivatives.
Having no success with the solution, I looked further.
I started to think of trying to add the entry to /etc/fstab, that led me to loads of permission issues. Also, sudo and my CLI tool proved to be incomplete for the task. Lets bring the big weapons - lets compile Apache with -DBIG_SECURITY_HOLE, also known as, give Apache the possibility to be run as root.
Lets append entry to the tab, lets attempt to mount... and... fail!
After numerous tests, queries and what not, I stumbled upon per process mount that led me here and opened the dimension of namespaces to me.
Okay, that explains everything - checking /proc/<pid>/mounts validates it, now, lets gnaw deeper and see how to overcome it.
Again, after numerous attempts and no success, I started posting questions based around my fresh knowledge of namespaces. Narrowing the questions down and becoming more technical (at least I think I did), that eventually led to a user hiciu who pointed me into systemd direction, specifically, Apaches service - PrivateTmp.
Voila! ...apparently systemd can enforce new namespaces.
I had the same strange behavior of apache and spent more than 3 days without any working solution. Then luckyly I found this post and as you described PrivateTmp caused the issue. In my case, I tried to mount a drive from php:
<?php
...
exec("sudo mount /dev/sda1 /mnt/drive", $output, $ret);
...
?>
When I ran above code from web browser, exec function return 0 (success) and I was even abble to list thru mapped drive within the code:
exec("ls /mnt/drive", $o, $r);
foreach ($o as $line){
echo $line.'<BR>';
}
But when I tried search for mapped drive from cli, I cannot see it. I tried everything, include change permissions, change php.ini etc. Nothing help. Until now, changing
PrivateTmp=false
in
/lib/systemd/system/apache2.service
does the trick. Thank you very much for sharing!
It was searching for this and is looks like this behavior is implemented and detectable from php via chroot:
system('ischroot;echo $?');
gives 0 with the setting PrivateTmp=true (saying 'you are in a chroot') and 1 with PrivateTemp=false.
I've installed Apache 2.4 with PHP 5.4 on Windows Server 2008 following instructions from this manual:
Apache installing manual.
Apache runs as a service now.
My application requires a php websocket script to run in the background. I'm running it manually with:
php myscript.php
The question is: Is there a way to start a background script automatically on system(apache) restart?
I found the following topic, but I didn't know where I could find an apache startup script for Windows.
Any help will be much appriciated.
I come up with a solution :)
Create an environment variable pointing to your Apache directory
APACHE_HOME = C:/PATH/TO_APACHE
Rename %APACHE_HOME%\bin\httpd.exe to %APACHE_HOME%\bin\httpdVendor.exe
Create a batch file and put the following code :
php myscript.php
%APACHE_HOME%\bin\httpdVendor.exe -k runservice
exit 0
Download/Install the free software BatToExeConverter (next, next, ...)
Open the installed converter and open your freshly created batch file
Click on the button Build EXE (let the default configuration)
Save the file : %APACHE_HOME%\bin\httpd.exe
Start your Apache Server
Tested on : Windows 7, Apache 2.4, Advanced Bat to Exe Converter 2.92
Use built in Windows Task Scheduler which triggers .bat script, which calls curl with defined url.
Download curl from http://curl.haxx.se/download.html and extract curl.exe on any directory, but we will use c:\backgroundtasks
Adjust script below to your needs:
cd c:\
cd c:\backgroundtasks
curl http://localhost/path/to/script.php
exit
Configure Task Scheduler to run as basic task:
General tab - as system account (to run when you are not logged in server)
Triggers tab - adjust frequency
Settings tab - at bottom set If the task is already running... to Stop the existing instance
The best method here would be to use Windows services dependencies.
Make a php-websocket-server.cmd file with any necessary environment settings (e.g. changing to a directory, setting PATH, etc...) with the last line:
php myscript.php
Install the Windows Server Resource Kit Tools, to get srvany and instsrv to create a user defined service. Note the install path as you'll need it in the next step.
Open a cmd shell and run:
<path_to_resource_kit>\instsrv PHPWebSocketServer <path_to_resource_kit>\srvany.exe
Next, create a file php-websocket-server.reg containing the following (update for your environment):
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PHPWebSocketServer\Parameters]
"Application"="c:\\path\\to\\php-websocket-server.cmd"
Import it by double-clicking or regedit /s php-websocket-server.reg
Back in your cmd shell:
sc config Apache2.4 depend= PHPWebSocketServer
to make the Apache2.4* service depend on your php service. Now, when Apache is started, the php service will be brought up first. And likewise, if you stop the php service Apache will stop along with it.
*the howto indicates that the service is named "Apache2.4" but you may want to verify in your installation.
When running as service, you won't have the startup script.
Execute some service implementation that allows running other programs as services, and then make the new service (which is running your script) a dependency of the Apache service. However, this will not restart the script when apache restarts.
One possible solution using SrvStart, and another using ServiceEx.
Perhaps don't install Apache as a service, and then edit the startup/restart script, and use the above method to run Apache as service (instead of using Apache's own installer).
Create bat file,e eg 'myphp.bat' containing path/php myscript.php. Include the correct path to php if it's not path'd.
create a bat file, eg runmyphp.bat containing
AT 00:00 /every:M,T,W,Th,F "cmd /c /path/myphp.bat", again including the correct path.
Then use explorer to drag runmyphp into the startup folder, so it will always run on system startup.
Google 'windows at command' or 'windows cron' to get all the correct syntax for the 'at' command, but you can currently find a detailed explanation here.
I found another answer C:\wamp\scripts\wampserver.lib.php this file is run every time when your wamp starts
include your file path include_once("file_path"); to this file and its done . this is perfect solution which you want
Enjoy!!!!!!!!!
Although the solution of Halayem Anis is very creative, I think its important to note that you can never be sure that a PHP script keeps running in the background. So if you choose to start your script on "Apache start", then you probably end op resetting Apache quite often, simple to reboot your script.
I assume that's even how you came to this question, as on a normal server you never have to touch the Apache reset button. It starts on system start and then it just runs. If that was the case, you could simple run your php myscript.php command on start up.
Considering there is no way to make sure the script keeps running, I would use a different approach, where I check if it is running and if not, restart it.
So the first step is to make it possible to track if the script is running. I would go for the simple approach where your myscript.php writes a single byte to a file every 5seconds or so. This way I can use the last modified time on the file to see if it is still running, because last modified time + 5 seconds < now == not running.
You could also store the last access time in a database every 5 seconds or so. Might be slightly faster then accessing files if you have a lot of traffic.
The second part is to have each request check if the script is running. For this two work I would use the PHP.ini to prepend a php script on every request. You can do it with the auto_append_file option.
This prepend script would work like this:
<?php
$filename = 'checkonline.txt';
$cmd = "php myscript.php";
if (filemtime($filename)+5<time()) {
//run in background without freezing php
//based on code posted on PHP exec manual, linked below
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
?>
Make sure to check how filemtime and exec work and what you need to keep in mind. They work slightly different on Windows/*nix.
Wrap-up all your required processes in a batch file and use RunAsService
With some tweaking, you can ensure that your service starts before Apache.