
Tenho vasculhado os fóruns para descobrir como você pode permitir que um comando/processo seja executado por um usuário que normalmente só é permitido pelo root ou pelo próprio.
Existem alguns bons recursos por aí, mas nenhum está me ajudando no meu caso. Tenho esperança de que um dos gênios do Ubuntu possa me indicar a direção certa.
Instalei o cpulimit com apt-get install cpulimit, um pacote que adiciona a capacidade de limitar o uso da CPU por um processo específico. Depois de instalado, posso ver a instalação em/usr/bin/cpulimit.
Agora devo executar cpulimit enquanto executo um processo manipulado pelo usuário, dentro do código desse processo.
Eu adicionei algumas tentativas ao meu arquivo visudo, todas variações disso:
{USER} ALL=(ALL:ALL) NOPASSWD:/usr/bin/cpulimit
Porém, quando executo o comando (limit=percentual):
cpulimit --pid 159845 --limit 60
A resposta é:
Error: Process 159845 detected, but you don't have permission to control it.
Onde 159845 é o processo correto, é mysqld.
Posso executar top -i e ver se o processo é executado pelo usuário mysql:
PID | DO UTILIZADOR | RP | IN | VIRTA | RES | SHR | S | %CPU | % MEM | TEMPO+ | COMANDO |
---|---|---|---|---|---|---|---|---|---|---|---|
159845 | mysql | 20 | 0 | 1460764 | 608076 | 3772 | S | 15.6 | 29,9 | 862:34,15 | mysqld |
Isso me leva a pensar que não há necessidade de adicionar a linha visudo inicial permitindo que {USER} execute cpulimit, mas mais ainda que quando {USER} executa cpulimit enquanto direciona o processo em questão 159845 não é permitido porque {USER} não não tenho permissão para mexer nos processos do mysql.
Como posso, como {USER}, executar cpulimit no processo mysql do mysql?
GENÉRICO: Como executar um comando como {USER} em um processo pertencente a um 'usuário/conta/função' diferente?
EDITAR: o comando está sendo executado em um script acionado no crontab de {USER}.
EDITAR 2: Depois de executar o comando como sudo assim:
$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);
O script parece congelar, onde antes continuaria com o script. O script após este ponto foi experimentado e testado para funcionar muito bem sem acionar o comando acima.
P: Por que isso não é executado e depois continua com o restante do script?
R: Porque o comando é executado e começa a monitorar esse processo, impedindo-o de progredir no código enquanto esperamos um retorno, então ele ficará pendurado aqui para sempre.
P: Como posso acionar o exec() do comando cpulimit em segundo plano ou sem a necessidade de observar e aguardar uma resposta antes de continuar?
A:Se um programa for iniciado com esta função, para que continue sendo executado em segundo plano, a saída do programa deve ser redirecionada para um arquivo ou outro fluxo de saída. Não fazer isso fará com que o PHP trave até que a execução do programa termine.
http://php.net/manual/en/function.exec.php
Então, essencialmente, precisamos > para outro espaço como /dev/null e executar o processo em segundo plano anexando um &. No meu caso, o comando precisará ficar assim:
sudo -u {USUÁRIO} cpulimit --pid {ID} --limit 60 > /dev/null &"
Também troquei exec() no lugar de shell_exec() que aparentemente não requer todos os parâmetros ou gera uma resposta tão pesada:
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 > /dev/null &");
Responder1
Encontrei a solução para meus problemas com a ajuda do @steeldriver.
Para responder isso em ordem cronológica:
Como executar um comando como {USER} em um processo pertencente a um 'usuário/conta/função' diferente?
Para executar um processo em um {ALTERNATIVE_USER} enquanto atua como {USER}, devemos fazer uso do sudo, para o qual você pode especificar qual usuário exato deve executar o comando, da seguinte forma:
sudo -u {ALTERNATIVE_USER} {COMMAND}
Como posso acionar um {COMMAND} para ser executado em segundo plano, permitindo que o script atual continue?
O script parece congelar à medida que o processo é acionado, ele não está congelado, está simplesmente aguardando o término do comando recém-acionado, o que não acontece, pois está agindo no processo inicialmente acionado, que nunca chegará ao fim.
Para fazer isso, quando iniciamos o comando que trava, devemos especificar uma saída para ele, para que tenha um lugar para travar. Isso pode ser feito apontando para um local alternativo, no meu exemplo usei > /dev/null
.
Por último, o que eu precisava fazer era executá-lo em segundo plano, o que pode ser feito anexando um arquivo &
.
Ponto final, especificamente para mim eu não queria receber uma resposta, eu simplesmente queria que o comando fosse executado e fizesse o que eu disse, então troquei exec() por shell_exec().
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 /dev/null &");