------------------------------------------------------------------------
-- API para criação de um novo módulo SGA.
------------------------------------------------------------------------
--
-- Esse arquivo possui o "esqueleto" das funções que são necessárias
-- para implementar um novo SGA. A configuração do nó (em sgad-cnf.lua),
-- deverá usar o atributo loadlib para indicar o nome do arquivo que
-- contém o código desenvolvido. Esse atributo faz com que o 
-- sga-daemon carregue e execute as funções implementadas. Por exemplo,
-- supondo que o arquivo com a nova API possua o nome NovaAPI.lua, a
-- configuração do nó seria da seguinte forma:
--
-- Node{
--   name = "nomeDaMaquina",
--   platform_id = "SGANovo",
--   loadlib = "NovaAPI",
-- }
-- 
-- A escolha de configurar o SGA como Node ou como Grid vai depender de
-- como você deseja que este SGA apareça na interface do usuário. Se
-- o usuário deve ver o SGA Boinc como uma única máquina, você deve
-- configurá-lo como Node. Porém, se o Boinc possui vários nós e você
-- deseja que o usuário possa monitorá-los, você deve configurá-lo
-- como Grid. 
-- 
-- Grid {
--   name = "nomeDaMaquina",
--   loadlib = "NovaAPI",
--   default = {
--     platform_id = "SGANovo",
--   },
-- }
--
-- Você encontra mais detalhes em:
-- https://jira.tecgraf.puc-rio.br/confluence/pages/viewpage.action?pageId=37814618
------------------------------------------------------------------------

------------------------------------------------------------------------

--
-- Especificação das funções públicas
--

------------------------------------------------------------------------------
-- Incializa o módulo para execução. Essa função deve ser chamada antes 
-- de qualquer outra função desta biblioteca.
--
-- Retorna verdadeiro caso o módulo seja inicializado com sucesso. Em caso 
-- de erro, retorna nil e a mensagem de erro.
--
-- ok, err = open()
------------------------------------------------------------------------------
open = function ()
  return true, nil
end

------------------------------------------------------------------------------
-- Termina a execução do módulo. Os processos disparados que ainda estejam
-- rodando não são afetados por essa chamada. Essa função não retorna valores.
--
-- close()
------------------------------------------------------------------------------
close = function()
end

------------------------------------------------------------------------------
--
-- Funções de consulta à configuração de servidor.
--
-- Em SGAs que são clusters, o parâmetro server indica o nó sobre o
-- qual se deseja obter a informação.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Retorna o número de processadores no servidor especificado. Caso o servidor
-- seja nil, assume localhost. Em caso de erro, retorna nil e a mensagem de
-- erro.
--
-- cpus, err = getnumcpus(server)
------------------------------------------------------------------------------
getnumcpus = function (server)
   return 1, nil
end

------------------------------------------------------------------------------
-- Retorna a quantidade em bytes de memória no servidor especificado.
-- O retorno é uma tabela contendo o total de memória RAM e de Swap, 
-- no formato:
--    { ram = xxx, swap = yyy }
--
-- Caso o servidor seja nil, assume localhost.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- mem, err = getmemory(server)
------------------------------------------------------------------------------
getmemory = function (server)
   return { ram = 0, swap = 0 }, nil
end

------------------------------------------------------------------------------
--
-- Funções de monitoração de servidor.
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Retorna a taxa média de ocupação de CPU do último minuto no servidor
-- especificado. Esse valor considera o número de processadores que o
-- servidor possui.
--
-- Por exemplo, caso a métrica de ocupação seja o número de processos
-- na fila de prontos, este número estará dividido pela quantidade 
-- de processadores. Caso o servidor seja nil, assume localhost. 
-- 
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada 
-- no servidor em questão.
-- 
-- Em caso de erro, retorna nil e a mensagem de erro.  
--
-- load, err = getcpuload(server, maxold)
------------------------------------------------------------------------------
getcpuload = function (server, maxold)
   return 0, nil
end

------------------------------------------------------------------------------
-- Retorna a média de ocupação de memória do último minuto no servidor
-- especificado. O retorno é uma tabela contendo o total em bytes de
-- memória RAM e de Swap, no formato:
--   { ram = xxx, swap = yyy }
--
-- Caso o servidor seja nil, assume localhost.
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada 
-- no servidor em questão. 
-- 
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- load, err = getmemoryload(server, maxold)
------------------------------------------------------------------------------
getmemoryload = function (server, maxold)
   return { ram=0, swap=0 }, nil
end


----------------------------------------------------------------------
-- Retorna o número de jobs que estão em execução no servidor
-- especificado.
-- 
-- Caso o servidor seja nil, assume localhost.
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada 
-- no servidor em questão.
-- 
-- Em caso de erro, retorna nil e a mensagem de erro.  
--
-- njobs, err = getnumberofjobs(server, maxold)
----------------------------------------------------------------------
getnumberofjobs = function(server, maxold)
   return 0, nil 
end


------------------------------------------------------------------------------
--
-- Funções de execução, monitoração e controle de processos.
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Executa um comando no servidor especificado e retorna um handle que
-- é a referência para o comando no contexto desta biblioteca. Pode ter
-- qualquer formato.
--
-- Parâmetros:
-- . id - um identificador único para este comando.
-- . command - o comando a ser executado.
-- . infile - nome de um arquivo de onde a entrada padrão será
--   direcionada. (opcional)
-- . outfile - nome de um arquivo para onde a saída padrão será
--   direcionada. (opcional)
-- . errorfile - nome de um arquivo para onde a saída de erro será
--   direcionada. (opcional)
--
-- * A saída padrão e de erro podem ser direcionadas para o mesmo arquivo.
--
-- Caso o servidor seja nil,assume localhost.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- handle, err = executecommand(identifier, command, infile, outfile,
--   errorfile, server)
------------------------------------------------------------------------------
executecommand = function(id, command, infile, outfile, errorfile, server)
   local handle ={ id = id, command = command}
   return handle, nil
end

------------------------------------------------------------------------------
-- Interrompe um processo iniciado através da função executecommand. Retorna
-- verdadeiro caso tenha sucesso. A definição de sucesso é que uma chamada a
-- getcommandstatus para o mesmo processo retornará o valor FINISHED. Retorna
-- falso caso o processo não termine.
-- 
-- Em caso de erro, retorna nil e a mensagem de erro.
-- 
-- ok, err = killcommand(handle)
------------------------------------------------------------------------------
killcommand = function (handle)
   return true, nil
end

------------------------------------------------------------------------------
-- Retorna uma tabela Lua com os dados do comando que precisam ser persistidos.
-- Estes dados devem ser suficientes para que um comando seja
-- 'recuperado' após a reinicialização do SGA, através da chamada à
-- retrievecommandhandle.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- pdata, err = getcommandpersistentdata(handle)
------------------------------------------------------------------------------
getcommandpersistentdata = function (handle)
  return handle, nil
end

------------------------------------------------------------------------------
-- A partir dos dados persistidos, retorna um handle que
-- é a referência para o comando no contexto desta biblioteca. Pode
-- ter qualquer formato.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- handle, err = retrievecommandhandle(pdata)
------------------------------------------------------------------------------
retrievecommandhandle = function (pdata)
   return pdata, nil
end

------------------------------------------------------------------------------
-- Libera todos os recursos relacionados ao processo especificado. Esta função
-- precisa ser chamada após o término do processo para que eventuais recursos
-- alocados a ele possam ser liberados. Após a chamada desta função, o handle
-- do processo não poderá mais ser utilizado.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- ok, err = releasecommandinfo(handle)
------------------------------------------------------------------------------
releasecommandinfo = function (handle)
   return true, nil
end

------------------------------------------------------------------------------
-- Retorna o identificador do comando recebido na função executecommand.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- id, err = getcommandid(handle)
------------------------------------------------------------------------------
getcommandid = function (handle)
   return handle.id, nil
end

------------------------------------------------------------------------------
-- Retorna um identificador único do processo iniciado através da função
-- executecommand.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- pid, err = getcommandpid(handle)
------------------------------------------------------------------------------
getcommandpid = function (handle)
   return 0, nil
end

------------------------------------------------------------------------------
-- Retorna o estado de um processo iniciado através da função executecommand.
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada no
-- servidor que estiver executando o comando.
--
-- O retorno pode ser RUNNING, NOT_RESPONDING, WAITING ou FINISHED. 
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- status, err = getcommandstatus(handle, maxold)
------------------------------------------------------------------------------
getcommandstatus = function (handle, maxold)
   return servermanager.FINISHED, nil
end

------------------------------------------------------------------------------
-- Retorna  a máquina que está executando o comando definido por handle.
-- O parâmetro maxold indica o
-- tempo máximo que a informação pode ter. Caso maxold seja nil, é assumido
-- zero e a informação será buscada no servidor que estiver executando o
-- comando. Em caso de erro, retorna nil e a mensagem de erro.
--
-- host, err = getcommandexechost(handle, maxold) 
------------------------------------------------------------------------------
getcommandexechost = function (handle, maxold)
   return "host unknown", nil
end

------------------------------------------------------------------------------
-- Retorna a taxa média de ocupação de CPU do último minuto pelo processo
-- especificado. Esse valor considera o número de processadores que o 
-- servidor possui. Por exemplo, caso o processo execute em apenas um 
-- processador, este número estará dividido pela quantidade de processadores.
-- Caso o servidor seja nil, assume localhost.
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada 
-- no servidor que estiver executando o comando.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- load, err = getcommandcpuload(handle, maxold)
------------------------------------------------------------------------------
getcommandcpuload = function (handle, maxold)
   return 0, nil
end

------------------------------------------------------------------------------
-- Retorna a média de ocupação de memória do último minuto pelo processo
-- especificado. O retorno é uma tabela contendo o total em bytes de
-- memória RAM e Swap, no formato:
--     { ram = xxx, swap = yyy }
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter. Caso
-- maxold seja nil, é assumido zero e a informação será buscada no servidor
-- que estiver executando o comando.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- load, err = getcommandmemoryload(handle, maxold)
------------------------------------------------------------------------------
getcommandmemoryload = function (handle, maxold)
   return {ram=0, swap=0}, nil
end

------------------------------------------------------------------------------
-- Retorna os tempos de execução do processo especificado. O retorno é uma
-- tabela contendo os tempos de usuário, sistema e total (tempo de parede),
-- no formato:
--               { user = xxx, system = yyy, elapsed = zzz }
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter. Caso
-- maxold seja nil, é assumido zero e a informação será buscada no servidor
-- que estiver executando o comando.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- time, err = getcommandtimeusage(handle, maxold)
------------------------------------------------------------------------------
getcommandtimeusage = function (handle, maxold)
   return {
     user = 0,
     system = 0,
     elapsed = 0,
   }, nil
end

------------------------------------------------------------------------------
-- Retorna todas as informações sobre um determinado comando. O retorno
-- é uma tabela contendo os campos:
--
-- pid - identificador único do processo iniciado através da função executecommand.
-- command - o comando executado.
-- execHost - a máquina que está executando o comando.
-- state - o estado de um processo.
-- memoryRamSizeMb - o total de memória RAM usada pelo comando. (Em Mb)
-- memorySwapSizeMb - o total de memória SWAP usada pelo comando. (Em Mb)
-- CPUPerc - a taxa média de ocupação de CPU do último minuto pelo comando.
-- CPUTimeSec - o tempo de CPU usado pelo comando.
-- wallTimeSec - o tempo total usado pelo comando.
-- userTimeSec - o tempo de usuário usado pelo comando.
-- systemTimeSec - o tempo de sistema usado pelo comando.
--
-- O parâmetro maxold indica o tempo máximo que a informação pode ter.
-- Caso maxold seja nil, é assumido zero e a informação será buscada 
-- no servidor que estiver executando o comando.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- load, err = getcommandallinfo(handle, maxold)
------------------------------------------------------------------------------
getcommandallinfo = function (handle, maxold)
   local allinfo = {
       pid = 0,
       command = handle.command,
       execHost = "unknown",
       state = servermanager.FINISHED,
       memoryRamSizeMb = 0,
       memorySwapSizeMb = 0,
       CPUPerc = 0,
       CPUTimeSec = 0,
       wallTimeSec = 0,
       userTimeSec = 0,
       systemTimeSec = 0,
   }
   return allinfo, nil
end

------------------------------------------------------------------------------
--
-- Funções de consulta à clusters.
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Obtém as informações de todos os processos em execução no SGA.
-- ** Em desenvolvimento **
------------------------------------------------------------------------------
getjobsinfo = function()
   return nil
end

------------------------------------------------------------------------
-- Retorna uma tabela com os nós do servidor especificado.
--
-- Caso o servidor seja nil, assume localhost.
--
-- Em caso de erro, retorna nil e a mensagem de erro.
--
-- nodes, err = getnodes(server)
------------------------------------------------------------------------
getnodes = function (server)
   return { "localhost" }, nil
end

------------------------------------------------------------------------------
--
-- Funções de log de histórico
--
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Indica se o histórico deve ser ativado ou não para o SGA em questão.
--
-- setHistoric(historic)
------------------------------------------------------------------------------
setHistoric = function (historic)
  servermanager._enableHistoric = historic
end

------------------------------------------------------------------------------
-- Retorna true se o histórico deve ser ativado para o sga em questão,
-- ou false caso contrário.
--
-- enableHistoric = getHistoric()
------------------------------------------------------------------------------
getHistoric = function ()
  return servermanager._enableHistoric
end

------------------------------------------------------------------------
------------------------------------------------------------------------
servermanager = {
  -------------
  -- private --
  -------------
  _enableHistoric = false,

  -----------------------
  -- Constantes do módulo
  -----------------------
  RUNNING = 0,
  NOT_RESPONDING = 1,
  WAITING = 2,
  FINISHED = 3,

  ERROR_CODE = -1,

  -------------
  -- public --
  -------------
  now = now, -- Definida em C nos binários para Unix.
  sleep = sleep, -- Definida em C nos binários para Unix.

  -- Funções de controle do módulo:
  open = open,
  close = close,

  -- Funções de consulta à configuração de servidor:
  getnumcpus = getnumcpus,
  getmemory = getmemory,

  -- Funções de monitoração de servidor:
  getcpuload = getcpuload,
  getmemoryload = getmemoryload,
  getnumberofjobs = getnumberofjobs,

  -- Funções de execução, monitoração e controle de processos:
  executecommand = executecommand,
  killcommand = killcommand,
  getcommandpersistentdata = getcommandpersistentdata,
  retrievecommandhandle = retrievecommandhandle,
  releasecommandinfo = releasecommandinfo,
  getcommandid = getcommandid,
  getcommandpid = getcommandpid,
  getcommandstatus = getcommandstatus,
  getcommandexechost = getcommandexechost,
  getcommandcpuload = getcommandcpuload,
  getcommandmemoryload = getcommandmemoryload,
  getcommandtimeusage = getcommandtimeusage,
  getcommandallinfo = getcommandallinfo, -- OPCIONAL

  -- Funções para clusters:
  getjobsinfo = getjobsinfo,
  getnodes = getnodes, -- OPCIONAL
  
  -- Funções de log de histórico:
  setHistoric = setHistoric, -- OPCIONAL
  getHistoric = getHistoric, -- OPCIONAL
}
