Class: Liri::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/agent/agent.rb,
lib/agent/runner.rb

Defined Under Namespace

Classes: Runner

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(udp_port, tcp_port, agent_folder_path) ⇒ Agent

Returns a new instance of Agent.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/agent/agent.rb', line 38

def initialize(udp_port, tcp_port, agent_folder_path)
  @udp_port = udp_port
  @udp_socket = UDPSocket.new
  @tcp_port = tcp_port

  @all_tests = {}

  @managers = {}

  @agent_folder_path = agent_folder_path

  @processing = true

  @hardware_specs = hardware_specs
end

Instance Attribute Details

#managersObject (readonly)

Returns the value of attribute managers.



9
10
11
# File 'lib/agent/agent.rb', line 9

def managers
  @managers
end

Class Method Details

.run(work_folder_path, stop = false) ⇒ Object

Inicia la ejecución del Agent

Parameters:

  • stop (Boolean) (defaults to: false)

    el valor true es para que no se ejecute infinitamente el método en el test unitario.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/agent/agent.rb', line 14

def run(work_folder_path, stop = false)
  setup_manager = Liri.set_setup(work_folder_path, :agent)
  agent_folder_path = setup_manager.agent_folder_path

  Liri.set_logger(setup_manager.logs_folder_path, 'liriagent.log')
  Liri.logger.info("Agent process started", true)
  Liri.logger.info("Press Ctrl + c to finish Agent process manually\n", true)

  agent = Agent.new(Liri.udp_port, Liri.tcp_port, agent_folder_path)
  threads = []
  threads << agent.start_server_socket_to_process_manager_connection_request # Esperar y procesar la petición de conexión del Manager

  Liri.init_exit(stop, threads)
rescue SignalException
  Liri.logger.info("Agent process finished manually", true)
rescue InxiCommandNotFoundError => e
  Liri.logger.error("Exception(#{e}) Please, install inxi in your operating system", true)
ensure
  # Siempre se ejecutan estos comandos, haya o no excepción
  Liri.kill(threads) if threads && threads.any?
  Liri.logger.info("Agent process finished", true)
end

Instance Method Details

#start_client_socket_to_process_tests(manager_ip_address, manager_data) ⇒ Object

Inicia un cliente tcp para responder a la petición broadcast del Manager para que éste sepa donde enviar las pruebas



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/agent/agent.rb', line 80

def start_client_socket_to_process_tests(manager_ip_address, manager_data)
  tcp_socket = TCPSocket.open(manager_ip_address, @tcp_port)
  agent_ip_address = tcp_socket.addr[2]
  tcp_socket.puts({ msg: 'get_source_code', hardware_specs: @hardware_specs }.to_json)

  # Las siguientes variables se usan para guardar momentaneamente los resultados mientras se hace un chequeo de que
  # el Manager siga ejecutandose o que ya no haya procesado los mismos tests ya ejecutados por otro agente
  tests_result_file_name = ""
  tests_result_file_path = ""
  tests_result = {}

  while line = tcp_socket.gets
    tcp_socket_data = JSON.parse(line.chop)
    msg = tcp_socket_data['msg']

    if msg == 'already_connected' || msg == 'no_exist_tests' || msg == 'finish_agent'
      break
    end

    if msg == 'proceed_get_source_code'
      init_work_folders(manager_ip_address)
      result = get_source_code(manager_ip_address, manager_data)
      tcp_socket.puts({ msg: result }.to_json)
    end

    if msg == 'process_tests'
      tests_batch = tcp_socket_data
      tests = get_tests(tests_batch, manager_ip_address)

      compressed_file_folder_path = @managers[manager_ip_address][:compressed_file_folder_path]
      decompressed_file_folder_path = @managers[manager_ip_address][:decompressed_file_folder_path]

      runner = Agent::Runner.new(Liri.unit_test_class, decompressed_file_folder_path)
      raw_tests_result = runner.run_tests(tests)
      batch_num = tests_batch['batch_num']
      tests_result = Common::TestsResult.new(compressed_file_folder_path)
      tests_result_file_name = tests_result.build_file_name(agent_ip_address, batch_num)
      tests_result_file_path = tests_result.save(tests_result_file_name, raw_tests_result)
      # TODO No se debería enviar el resultado si otro agente ya lo procesó, porque osinó reemplazaría el archivo de resultados
      # ya procesado. ACTUALIZACION: Puede que esto ya se haya arreglado
      send_tests_results_file(manager_ip_address, manager_data, tests_result_file_path)
      tests_result = { msg: 'processed_tests', batch_num: batch_num, tests_result_file_name: tests_result_file_name}
      tcp_socket.puts(tests_result.to_json) # Envía el número de lote y el nombre del archivo de resultados.
    end
  end

  tcp_socket.close
  unregister_manager(manager_ip_address)
rescue Errno::EADDRINUSE => e
  Liri.logger.error("Exception(#{e}) Busy UDP port #{@udp_port}")
  @processing = false
rescue Errno::ECONNRESET => e
  tcp_socket.close
  Liri.logger.error("Exception(#{e}) Closed connection in TCP port #{@tcp_port}", true)
  unregister_manager(manager_ip_address)
rescue Errno::ECONNREFUSED => e
  Liri.logger.error("Exception(#{e}) Rejected connection in TCP port #{@tcp_port}", true)
  unregister_manager(manager_ip_address)
end

#start_server_socket_to_process_manager_connection_requestObject

Inicia un servidor udp que se mantiene en espera de la primera petición de conexión del Manager



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/agent/agent.rb', line 55

def start_server_socket_to_process_manager_connection_request
  # El servidor udp se ejecuta en bucle dentro de un hilo, esto permite realizar otras tareas mientras este hilo sigue esperando
  # que un Manager se conecte, cuando se conecta un Manager, se guarda la ip de este manager y se vuelve a esperar otra petición
  Thread.new do
    BasicSocket.do_not_reverse_lookup = true
    begin
      @udp_socket.bind('0.0.0.0', @udp_port)
    rescue Errno::EADDRINUSE => e
      Liri.logger.error("Exception(#{e}) Busy UDP port #{@udp_port}", true)
      Thread.exit
    end
    Liri.logger.info("Waiting managers request in UDP port #{@udp_port}")

    while @processing
      @manager_request = @udp_socket.recvfrom(1024)
      manager_ip_address = @manager_request.last.last
      manager_data = get_manager_data(JSON.parse(@manager_request.first))
      # TODO: El cliente TCP debería inicicarse en otro hilo, de este modo se tendrá un cliente TCP para cada Manager
      # y se evita que un mismo cliente procese la ejecución de varios Manager
      process_manager_connection_request(manager_ip_address, manager_data)
    end
  end
end