
He estado recorriendo los foros para descubrir cómo se puede permitir que un usuario ejecute un comando/proceso que normalmente solo está permitido por root o por sí mismo.
Existen algunos buenos recursos, pero ninguno me ayuda en mi caso. Espero que uno de los genios de Ubuntu pueda indicarme la dirección correcta.
Instalé cpulimit con apt-get install cpulimit, un paquete que agrega la capacidad de limitar el uso de la CPU por parte de un proceso en particular. Una vez instalado puedo ver la instalación en /usr/bin/cpulimit.
Ahora debo ejecutar cpulimit mientras ejecuto un proceso manejado por el usuario, dentro del código de ese proceso.
Agregué un par de intentos a mi archivo visudo, todas variaciones de esto:
{USER} ALL=(ALL:ALL) NOPASSWD:/usr/bin/cpulimit
Sin embargo, cuando ejecuto el comando (límite = porcentaje):
cpulimit --pid 159845 --limit 60
La respuesta es:
Error: Process 159845 detected, but you don't have permission to control it.
Donde 159845 es el proceso correcto, es mysqld.
Puedo ejecutar top -i y ver que el proceso lo ejecuta el usuario mysql:
PID | USUARIO | relaciones públicas | NI | VIRTUAL | RES | SHR | S | %UPC | %MEM | TIEMPO+ | DOMINIO |
---|---|---|---|---|---|---|---|---|---|---|---|
159845 | MySQL | 20 | 0 | 1460764 | 608076 | 3772 | S | 15.6 | 29,9 | 862:34.15 | mysqld |
Esto me lleva a pensar que no hay necesidad de agregar la línea visudo inicial que permite a {USER} ejecutar cpulimit, pero más aún, cuando {USER} ejecuta cpulimit mientras apunta al proceso en la pregunta 159845, no está permitido ya que {USER} no No tengo permiso para tocar los procesos de MySQL.
¿Cómo puedo, como {USUARIO}, ejecutar cpulimit en el proceso mysql de mysql?
GENÉRICO: ¿Cómo ejecutar un comando como {USUARIO} en un proceso propiedad de un 'usuario/cuenta/rol' diferente?
EDITAR: El comando se ejecuta dentro de un script activado dentro del crontab de {USUARIO}.
EDITAR 2: Después de ejecutar el comando como sudo así:
$limit_mysqld_cpu_usage = "sudo -u mysql cpulimit --pid " . $mysqld_id_exe_output[0] . " --limit " . $cpu_limit_as_perc_of_cpus;
// Run command
exec($limit_mysqld_cpu_usage, $limit_mysqld_cpu_usage_output, $limit_mysqld_cpu_usage_id);
El guión parece congelarse, donde anteriormente continuaría con el guión. Se ha comprobado que el script más allá de este punto funciona muy bien sin activar el comando anterior.
P: ¿Por qué esto no se ejecuta y luego continúa con el resto del script?
R: Debido a que el comando se ejecuta y comienza a vigilar ese proceso, impidiendo que avance a través del código ya que esperamos un retorno, se quedará colgado aquí para siempre.
P: ¿Cómo puedo activar el exec() del comando cpulimit en segundo plano o sin la necesidad de mirar y esperar una respuesta antes de continuar?
A:Si un programa se inicia con esta función, para que continúe ejecutándose en segundo plano, la salida del programa debe redirigirse a un archivo u otro flujo de salida. De no hacerlo, PHP se bloqueará hasta que finalice la ejecución del programa.
http://php.net/manual/en/function.exec.php
Básicamente, necesitamos > ir a otro espacio como /dev/null y ejecutar el proceso en segundo plano agregando un &. En mi caso, el comando deberá verse así:
sudo -u {USUARIO} cpulimit --pid {ID} --limit 60 > /dev/null &"
También cambié exec() en lugar de shell_exec() que aparentemente no requiere todos los parámetros ni genera una respuesta tan pesada:
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 > /dev/null &");
Respuesta1
Encontré la solución a mis problemas con la ayuda de @steeldriver.
Para responder esto en orden cronológico:
¿Cómo ejecutar un comando como {USUARIO} en un proceso propiedad de un 'usuario/cuenta/rol' diferente?
Para ejecutar un proceso en un {ALTERNATIVE_USER} mientras actuamos como {USER}, debemos hacer uso de sudo, al cual luego puedes especificar qué usuario exacto debe ejecutar el comando, así:
sudo -u {ALTERNATIVE_USER} {COMMAND}
¿Cómo puedo activar un {COMMAND} para que se ejecute en segundo plano permitiendo que la secuencia de comandos actual continúe?
El script parece congelarse cuando se activa el proceso, no está congelado, simplemente está esperando a que finalice el comando recién activado, lo cual no sucederá, ya que está actuando sobre el proceso activado inicialmente, que nunca llegará a su fin.
Para hacer esto, cuando iniciamos el comando que se cuelga, debemos especificar una salida para que tenga un lugar donde colgar. Esto se puede hacer señalando una ubicación alternativa, en mi caso usé > /dev/null
.
Por último, lo que tenía que hacer era ejecutarlo en segundo plano, lo que se puede hacer agregando un archivo &
.
Punto final, específicamente para mí, no deseaba recibir una respuesta, simplemente quería que el comando se ejecutara y hiciera lo que dije, así que cambié exec() a favor de shell_exec().
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 /dev/null &");