WebSockets – Dashboard colaborativa

Desde hace unos años, se han puesto de moda la tecnología WebSocket.
Esta tecnología es una extensión del protocolo HTTP para simular un socket. Comunmente un sócket de comunicación es un recurso que se utiliza para poder transferir datos entre aplicaciones/máquinas. Existen varios tipos de sockets: UDP,TCP,RAW,UNIX,… cada uno se utiliza para una determinada función.

Por ejemplo, UDP se va muy bien para transferir grandes cantidades de datos ya que reduce el overhead introducido por cabeceras, Los sockets TCP se usan para las aplicaciones que no toleran errores en transmisión ya que posee un buen sistema de control de flujo y errores. En ambos casos existe un evidente problema: se necesitan abrir puertos específicos en los firewalls para poder establecer la conexión. Por defecto, el puerto 80/443 que utiliza el servidor de WebSocket suele estar abierto ya que son los puertos estándares de cualquier servidor HTTP.

Diagrama de Websockets

Este diagrama muestra la negociación y uso del protocolo de websockets

Este tipo de socket se utiliza en los navegadores para poder mantener un flujo de comunicación constante por lo facilita la operativa a los programadores web para tener el contenido actualizado en sus páginas. El clásico ejemplo de uso de websockets es construir una sala de chat en la que en tiempo real se reciben y envían mensajes (Hangouts utiliza websockets), las notificaciones de Facebook utilizan websockets.

Ejemplo básico de uso de Webcoskets con node JS
Servidor:

var server = require('websocket').server, http = require('http');

var socket = new server({
    httpServer: http.createServer().listen(1337)
});

socket.on('request', function(request) {
    var connection = request.accept(null, request.origin);

    connection.on('message', function(message) {
        console.log(message.utf8Data);
        connection.sendUTF('pong');
        setTimeout(function() {
            connection.sendUTF('[!] Server Event happended');
        }, 1000);
    });

    connection.on('close', function(connection) {
        console.log('connection closed');
    });
}); 

Cliente:

<div id="content"></div>

<script type="text/javascript">
    var content = document.getElementById('content');
    var socket = new WebSocket('ws://localhost:1337');
    socket.onopen = function () {
        setTimeout(function() {
                socket.send('ping');
        }, 1000);
    };
    socket.onmessage = function (message) {
        content.innerHTML += message.data +'<br />';
    };

    socket.onerror = function (error) {
        console.log('WebSocket error: ' + error);
    };
</script>

Fuente: http://hawkee.com/snippet/16051/

Para los que trabajamos en grupo en determinadas ocasiones necesitamos sincronizar determinadas tareas, como el reinicio y arranque de determinados servidores. Por ello poder avisar a los compañeros de que has iniciado la tarea y que lo reciban en tiempo real es importante, en esto nos ayudan los websockets. Si alguien quiere ver la potencia que ofrece este tipo de tecnología recomiendo ver una dashboard de ejemplo colaborativa que he diseñado para este fin. El código es libre y susceptible de aceptar mejoras:

https://github.com/berni69/ws-dashboard

Tratando logs con awk

Hoy en el trabajo me he encontrado con una problemática bastante común cuando tratamos de filtrar logs: mucha información que no nos interesa.

Para solventar este problema, habitualmente, la primera aproximación sería con grep y cut pero habitualmente se quedan cortos ya que es complicado usarlos para filtrar por fecha/hora.

En este ejemplo se usará un archivo de log del estilo

2016/06/29 17:10:35.838:Fatal error core dumped
2016/06/29 17:15:35.838:Fatal error core dumped
2016/06/29 17:20:35.838:Fatal error core dumped
2016/06/29 17:30:35.838:Fatal error core dumped

Para poder filtrar por hora, podemos usar awk, en el siguiente script contaremos el numero de líneas que hay en un intervalo de tiempo determinado (por defecto, los últimos 15 min).

#!/bin/awk -f

BEGIN {

if(minutos==""){minutos=15 }
    umbral = minutos *60  # Miramos los ultimos N segundos del log 
    now = strftime("%H:%M:%S",systime())
    counter=0;
    debug=0
 }
{ 
    split($2,chunks,".");
    hour=chunks[1];
    m=split(hour,w,":")
    n=split(now,t,":")
    FIRSTTIME= (t[1]*3600) + (t[2]*60) + t[3]
    SECONDTIME= (w[1]*3600) + (w[2]*60) + w[3]
    DIFFTIME=(FIRSTTIME - SECONDTIME)
    if (debug == 1){
        printf("%s|%s|%s\n",FIRSTTIME,SECONDTIME,DIFFTIME)
    }
    if(DIFFTIME < umbral ){
        counter++;
    }
}
END { print  counter }

Para ejecutarlo bastaría con ejecutar:

cat mylog.log | awk -f script.awk -v minutos=8

Y el resultado sería

echo '2016/06/29 17:10:35.838:Fatal error core dumped
2016/06/29 17:15:35.838:Fatal error core dumped
2016/06/29 17:20:35.838:Fatal error core dumped
2016/06/29 17:30:35.838:Fatal error core dumped' | awk -f /var/www/scripts/countSuperacionesAma.awk -v minutos=8
1

Pues de este modo tan sencillo podemos tratar logs en función del tiempo.

Matar un proceso en Windows

Esta tarde un compañero me ha pedido si conocía si se podía matar un proceso dependiendo de la RAM que consumía y relanzarlo sin utilizar nada más que no fuera BATCH en Windows XP,… si señores BATCH 🙂

Pues evidentemente le dije que no lo sabía pero que lo investigaría. Y este ha sido el resultado, este script mata cualquier cmd.exe que consuma más de 4000Kb de RAM.

@echo off
set process=cmd.exe
set memLimit=4000
tasklist /FI "IMAGENAME eq %process%" | findstr  %process% > tmp
for /f "tokens=5" %%x in (tmp) do set memUsage=%%x
echo "Memusage %memUsage%"
if %memUsage% gtr %memLimit% goto killme
goto end 
:killme
taskkill /f /FI "IMAGENAME eq %process%"
%process%
:end
echo "fin"
del tmp

Sé que se puede mejorar el uso de archivos temporales pero.. como le dije a mi compñero BATCH no es mi fuerte

Snippet Consultar Active directory / LDAP

Este post trata de como consultar de una manera sencilla el Active Directory/LDAP corporativo, en concreto se extraerá la fecha de caducidad de una cuenta conociendo el login.

Antes de nada, hay que tener en cuenta que LDAP almacena las fechas a partir de los segundos transcurridos desde el 1 de enero de 1601. Por ello vamos a introducir en el código la siguiente función que nos ayudará a tratar con este tipo de fechas:

/// <summary>
/// Esta función convierte el tiempo de LDAP (AD) en una variable DateTime
/// </summary>
/// <param name="accountExpires">LDAP time</param>
/// <returns>La representación datetime del LDAP</returns>
static DateTime longToDatetime(Int64 accountExpires) {
      DateTime expireDate = DateTime.MaxValue;
      if (!accountExpires.Equals(Int64.MaxValue))
           expireDate = DateTime.FromFileTime(accountExpires);

       return expireDate;
   }

A continuación viene el código que tiene algo más de chicha, el acceso a AD:

public class UserResult {
        public String Name;
        public DateTime ExpireDate;
    }
 static UserResult GetUser(String userId)
        {
            UserResult res;
            DirectoryEntry searchRoot = new DirectoryEntry(dominio, "user","password");
            DirectorySearcher search = new DirectorySearcher(searchRoot);
            search.Filter = "(&(objectClass=user)(samaccountname="+userId+"))";
            search.PropertiesToLoad.Add("accountExpires");
            search.PropertiesToLoad.Add("samaccountname");
            SearchResult result;
            SearchResultCollection resultCol = search.FindAll();
            if (resultCol == null) { return null; }
            result = resultCol[0];
            res = new UserResult();
            res.ExpireDate = longToDatetime((Int64)result.Properties["accountExpires"][0]);
            res.Name = (string)result.Properties["samaccountname"][0];
            return res;
            
        }

El codigo anterior se conecta al active directory especificado por la variable dominio y por un usuario que tenga privilegios en el AD.

El string de domintio tiene que tener la forma:

const string dominio= "LDAP://DC=organizacion,DC=com";

Serializar y deserializar en C#

Cuantas veces hemos tenido que utilizar una lista de objetos y la queremos exportar en texto o queremos que los datos no estén incrustados en la App,..

Bueno pues aquí dejo 2 funciones para poder serializar y desserializar listas de objetos.

Serializar:

        public static void Serialize( List<T> list, string fileName)
        {
            var serializer = new XmlSerializer(typeof(List<T>));
            using (var stream = File.OpenWrite(fileName))
            {
                serializer.Serialize(stream, list);
            }
        }

Deserializar:

        public static void Deserialize( List<T> list, string fileName)
        {
            var serializer = new XmlSerializer(typeof(List<T>));
            using (var stream = File.OpenRead(fileName))
            {
                var other = (List<T>)(serializer.Deserialize(stream));
                list.Clear();
                list.AddRange(other);
            }
        }

Espero que os sea útil